From 1ece93b98b0f31f0fbbe82b423c9293ff3497982 Mon Sep 17 00:00:00 2001
From: Dave Dykstra <2129743+DrDaveD@users.noreply.github.com>
Date: Thu, 13 Nov 2025 16:11:01 -0600
Subject: [PATCH 1/2] add htgettoken --novaulttoken and htdestroytoken -f
---
htdestroytoken | 68 +++++++++++++++++++++++++++++++++++-------
htdestroytoken.1 | 50 +++++++++++++++++++++++--------
htdestroytoken.html | 59 ++++++++++++++++++++++++++++--------
htgettoken.1 | 16 ++++++----
htgettoken.html | 26 ++++++++++------
htgettoken.spec | 6 +++-
htgettoken/__init__.py | 7 +++++
7 files changed, 180 insertions(+), 52 deletions(-)
diff --git a/htdestroytoken b/htdestroytoken
index 30e2264..ed99e25 100755
--- a/htdestroytoken
+++ b/htdestroytoken
@@ -1,21 +1,67 @@
#!/bin/bash
-VERBOSE=true
-if [ "$1" = "-q" ]; then
- VERBOSE=false
- shift
-fi
+ME=htdestroytoken
-if [ $# != 0 ]; then
- echo "Usage: htdestroytoken [-q]" >&2
- echo "Removes bearer and vault tokens" >&2
- echo "-q means to do it silently" >&2
+usage()
+{
+ echo "Usage: $ME [-h] [-q] [-f [htgettoken options]]"
+ echo "Removes bearer and vault tokens if present"
+ echo " -h prints this help message and exits"
+ echo " -q do removals silently"
+ echo " -f first force removal of refresh token from vault, if vault token is valid."
+ echo " Runs htgettoken to find the vault path so requires sufficient htgettoken"
+ echo " options on command line or in \$HTGETTOKENOPTS."
+ echo "The location of the bearer token can be set by \$BEARER_TOKEN_FILE"
+ echo " and the location of the vault token can be set by \$VAULT_TOKEN_FILE."
exit 2
-fi
+} >&2
+
+VERBOSE=true
+RMREFRESH=false
+HTGETOPTS=""
+for ARG; do
+ case $ARG in
+ -h) usage;;
+ -q) VERBOSE=false; HTGETOPTS="$HTGETOPTS -q";;
+ -f) RMREFRESH=true;;
+ *) if $RMREFRESH; then
+ HTGETOPTS="$HTGETOPTS $ARG"
+ else
+ usage
+ fi;;
+ esac
+done
# UID is a standard bash variable
+VTFILE="/tmp/vt_u$UID"
+if [ -n "$VAULT_TOKEN_FILE" ]; then
+ VTFILE="$VAULT_TOKEN_FILE"
+ HTGETOPTS="$HTGETOPTS --vaulttokenfile=$VTFILE"
+fi
+if $RMREFRESH && [ -f "$VTFILE" ]; then
+ if ( [ -z "$HTGETOPTS" ] || [ "$HTGETOPTS" = "-q" ] ) \
+ && [ -z "$HTGETTOKENOPTS" ]; then
+ echo "$ME: no htgettoken options were given" >&2
+ usage
+ fi
+ BEARERURL="$(htgettoken $HTGETOPTS --novaulttoken --nobearertoken --showbearerurl)"
+ if [ -z "$BEARERURL" ]; then
+ echo "$ME: Unable to obtain vault URL to remove refresh token" >&2
+ exit 3
+ fi
+ if $VERBOSE; then
+ echo "Deleting refresh token"
+ echo " at path $BEARERURL"
+ fi
+ # be careful to not let the vault token show up in a ps list; send to stdin
+ if ! (echo -n "X-Vault-Token: ";cat $VTFILE) | \
+ curl -q -f -m 5 -H @- -X DELETE "$BEARERURL"; then
+ echo "$ME: Unable to delete refresh token" >&2
+ exit 3
+ fi
+fi
TOKENFILE="${BEARER_TOKEN_FILE:-${XDG_RUNTIME_DIR:-/tmp}/bt_u$UID}"
-for FILE in $TOKENFILE /tmp/vt_u$UID*; do
+for FILE in $TOKENFILE ${VTFILE}; do
if [ -f "$FILE" ]; then
if $VERBOSE; then
echo "Removing $FILE"
diff --git a/htdestroytoken.1 b/htdestroytoken.1
index 0b3dc5b..7949f3d 100644
--- a/htdestroytoken.1
+++ b/htdestroytoken.1
@@ -4,20 +4,26 @@ htdestroytoken \- remove bearer and vault tokens
.SH SYNOPSIS
.B htdestroytoken
-[-q]
-
+[-h] [-q] [-f [htgettoken options]]"
.SH DESCRIPTION
.B htdestroytoken
-removes a bearer token found by WLCG Bearer Token Discovery and also
-removes a vault token found in the default location used by
-.BR htgettoken.
-
-Note that the vault server additionally caches bearer tokens, so the
-next time that
+by default removes a bearer token found by WLCG Bearer Token Discovery and
+also removes a vault token found either by the environment variable
+$VAULT_TOKEN_FILE or in the default location used by
+.BR htgettoken .
+.PP
+Note that the vault server additionally caches refresh tokens and bearer
+tokens, so this alone does not completely clear them. The
+.I -f
+option (described below) can remove the refresh token to force a new
+oidc authentication.
+If that is not used and
+.B htgettoken
+is subsequently run and gets a new vault token with one of the non-oidc
+authentication methods, it is possible that the same bearer token might
+be returned from the vault cache unless a new one is forced to be
+retrieved with an
.B htgettoken
-is run the same bearer token might be returned unless a new one is
-forced to be retrieved with either oidc authentication or with an
-htgettoken
.I \-\-minsecs
option.
@@ -25,8 +31,26 @@ option.
The following options are recognized:
.PP
.TP
-.BR \-q
-Do removals silently
+.B \-h
+Show help message.
+.TP
+.B \-q
+Do removals silently.
+.TP
+.B \-f [htgettoken options]
+Force a removal of the refresh token in vault before removal of the
+vault token, if the vault token is valid. This runs
+.B htgettoken
+to locate the path in vault to remove, so sufficient options to locate
+that path such as
+.IR \-a ,
+.I \-i
+and possibly
+.I \-r
+need to either be passed on the rest of the command line or in the
+$HTGETTOKENOPTS environment variable.
+If this option is given and the removal of the refresh token fails,
+the command will exit and not remove the vault or bearer tokens.
.SH AUTHOR
Dave Dykstra
diff --git a/htdestroytoken.html b/htdestroytoken.html
index 5033e58..acd77f0 100644
--- a/htdestroytoken.html
+++ b/htdestroytoken.html
@@ -1,5 +1,5 @@
-
-
+
+
@@ -46,7 +46,7 @@
SYNOPSIS
htdestroytoken
-[-q]
+[-h] [-q] [-f [htgettoken options]]"
DESCRIPTION
@@ -55,15 +55,21 @@ DESCRIPTION
htdestroytoken
-removes a bearer token found by WLCG Bearer Token Discovery
-and also removes a vault token found in the default location
-used by htgettoken.
+by default removes a bearer token found by WLCG Bearer Token
+Discovery and also removes a vault token found either by the
+environment variable $VAULT_TOKEN_FILE or in the default
+location used by htgettoken.
Note that the
-vault server additionally caches bearer tokens, so the next
-time that htgettoken is run the same bearer token
-might be returned unless a new one is forced to be retrieved
-with either oidc authentication or with an htgettoken
+vault server additionally caches refresh tokens and bearer
+tokens, so this alone does not completely clear them. The
+-f option (described below) can remove the refresh
+token to force a new oidc authentication. If that is not
+used and htgettoken is subsequently run and gets a
+new vault token with one of the non-oidc authentication
+methods, it is possible that the same bearer token might be
+returned from the vault cache unless a new one is forced to
+be retrieved with an htgettoken
−−minsecs option.
OPTIONS
@@ -81,16 +87,43 @@ OPTIONS
|
+ −h |
+ |
+
+
+
+ Show help message. |
+
+ |
+
+ |
+
+
+
−q |
|
-
+ |
- Do removals silently |
-
+ Do removals silently. |
+
|
+
−f [htgettoken
+options]
+
+Force a removal of the refresh
+token in vault before removal of the vault token, if the
+vault token is valid. This runs htgettoken to locate
+the path in vault to remove, so sufficient options to locate
+that path such as −a, −i and
+possibly −r need to either be passed on the
+rest of the command line or in the $HTGETTOKENOPTS
+environment variable. If this option is given and the
+removal of the refresh token fails, the command will exit
+and not remove the vault or bearer tokens.
+
AUTHOR
diff --git a/htgettoken.1 b/htgettoken.1
index 82dbe60..be113f1 100644
--- a/htgettoken.1
+++ b/htgettoken.1
@@ -94,7 +94,7 @@ The name of the issuer role, as configured in the vault server. The
default role name is "default". Different roles for the same issuer
map to different token scopes as configured in vault.
.TP
-.BR \ \-\-nokerberos
+.BR \-\-nokerberos
Do not attempt to use kerberos authentication.
.TP
.BR \-\-kerbpath=vaultpath
@@ -115,7 +115,7 @@ command and the "-l" option of the
.B klist
command for more information.
.TP
-.BR \ \-\-nooidc
+.BR \-\-nooidc
Do not attempt to do OIDC authentication.
.TP
.BR \-\-oidcpath=vaultpath
@@ -129,7 +129,7 @@ where %issuer is the value from the
option.
.RE
.TP
-.BR \ \-\-nossh
+.BR \-\-nossh
Do not attempt to do ssh-agent authentication.
.TP
.BR \-\-sshpath=vaultpath
@@ -140,7 +140,7 @@ auth/ssh
.RE
.RE
.TP
-.BR \ \-\-registerssh
+.BR \-\-registerssh
Register all public keys available from
.B ssh-agent
with vault for future use. This forces OIDC authentication even if a
@@ -149,6 +149,12 @@ then registers the public keys before storing the vault token and access
token. Must be allowed in the configuration of the vault server in
order to work.
.TP
+.BR \-\-novaulttoken
+Disable all authentication methods that get vault tokens.
+Currently this equivalent to
+.IR \-\-nooidc\ \-\-nokerberos\ \-\-nossh .
+.BR
+.TP
.BR \-c\ path , \ \-\-configdir=path
The path to a directory to save
.B htgettoken
@@ -238,7 +244,7 @@ Skip getting a bearer token. Always gets a vault token except in
combination with
.BR \-\-showbearerurl .
.TP
-.BR \-o\ path , \ \-\-out=path
+.BR \-o\ path , \ \-\-outfile=path
The path of the file used to store the bearer token on the local
machine. The default is $BEARER_TOKEN_FILE. If that is not set
but $XDG_RUNTIME_DIR is set, then the default is
diff --git a/htgettoken.html b/htgettoken.html
index abb0d3c..55a13a5 100644
--- a/htgettoken.html
+++ b/htgettoken.html
@@ -1,5 +1,5 @@
-
-
+
+
@@ -175,7 +175,7 @@ OPTIONS
The name of the issuer role, as
configured in the vault server. The default role name is
"default". Different roles for the same issuer map
-to different token scopes as configured in vault.
+to different token scopes as configured in vault.
−−nokerberos
@@ -201,7 +201,7 @@ OPTIONS
for example when $KRB5CCNAME begins with "DIR:".
The default is the currently selected principal. See the
kswitch command and the "-l" option of the
-klist command for more information.
+klist command for more information.
−−nooidc
@@ -218,7 +218,7 @@ OPTIONS
auth/oidc-%issuer/oidc
where %issuer is the value from
-the −−issuer option.
+the −−issuer option.
−−nossh
@@ -231,7 +231,7 @@ OPTIONS
The path in vault for doing
ssh-agent authentication. The default is
-auth/ssh
+auth/ssh
−−registerssh
@@ -245,6 +245,13 @@ OPTIONS
vault server in order to work.
+
−−novaulttoken
+
+Disable all authentication
+methods that get vault tokens. Currently this equivalent to
+−−nooidc −−nokerberos −−nossh.
+
+
−c path, −−configdir=path
The path to a directory to save
@@ -349,11 +356,12 @@
OPTIONS
−−nobearertoken
-Skip getting a bearer token;
-only get a vault token.
+Skip getting a bearer token.
+Always gets a vault token except in combination with
+−−showbearerurl.
-−o path, −−out=path
+−o path, −−outfile=path
The path of the file used to
store the bearer token on the local machine. The default is
diff --git a/htgettoken.spec b/htgettoken.spec
index 7139366..5499237 100644
--- a/htgettoken.spec
+++ b/htgettoken.spec
@@ -74,8 +74,12 @@ rm -rf $RPM_BUILD_ROOT
%changelog
+# - Add htdestroytoken -f option to force a removal of a refresh token in
+# vault.
+# - Add htgettoken --novaulttoken option as an alias for --noiodc, --nossh,
+# and --nokerberos.
# - Again fix --showbearerurl to work in combination with --nobearertoken.
-# That was fixed in 1.17 but broken in 1.21 and 2.0.
+# That was fixed in 1.17 but broke in 1.21 and 2.0.
* Fri Jun 20 2025 Dave Dykstra 2.4-1
- Add the new -s and -f options to the htdecodetoken usage summary.
diff --git a/htgettoken/__init__.py b/htgettoken/__init__.py
index 11a06b0..6e8c58f 100644
--- a/htgettoken/__init__.py
+++ b/htgettoken/__init__.py
@@ -545,6 +545,9 @@ def main(args=None):
parser.add_option("--registerssh",
action="store_true", default=False,
help="register ssh-agent keys (forces oidc authentication)")
+ parser.add_option("--novaulttoken",
+ action="store_true", default=False,
+ help="skip all the authentication methods of getting a vault token")
parser.add_option("-c", "--configdir",
metavar="path",
default="~/.config/" + prog,
@@ -660,6 +663,10 @@ def main(args=None):
if options.registerssh:
options.nokerberos = True
options.nossh = True
+ if options.novaulttoken:
+ options.nooidc = True
+ options.nokerberos = True
+ options.nossh = True
# calculate vault token ttl and minttl in seconds
vaulttokensecs = ttl2secs(options.vaulttokenttl, "--vaulttokenttl")
From d3129fa02d417e3f889ceaf8c550b116f1e66af1 Mon Sep 17 00:00:00 2001
From: Dave Dykstra <2129743+DrDaveD@users.noreply.github.com>
Date: Thu, 13 Nov 2025 16:30:46 -0600
Subject: [PATCH 2/2] update tests to use --novaulttoken
---
tests/005-scopeexchange/main | 2 +-
tests/006-audienceexchange/main | 2 +-
tests/007-minsecs/main | 6 +++---
tests/008-minsecsexchange/main | 6 +++---
tests/013-showbearerurl/main | 2 +-
tests/014-checkdefaultsub/main | 4 ++--
tests/015-checkgroupsub/main | 2 +-
7 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/tests/005-scopeexchange/main b/tests/005-scopeexchange/main
index 6a80387..17453c6 100644
--- a/tests/005-scopeexchange/main
+++ b/tests/005-scopeexchange/main
@@ -4,7 +4,7 @@ fi
# assumes vault token is already present
set -e
-htgettoken --nooidc --nokerberos --nossh -a $VAULTSERVER -i $ISSUER --scopes="$TESTSCOPES"
+htgettoken --novaulttoken -a $VAULTSERVER -i $ISSUER --scopes="$TESTSCOPES"
TOKENSCOPES="$(htdecodetoken|jq -r .scope)"
if [ "$TOKENSCOPES" != "$TESTSCOPES" ]; then
diff --git a/tests/006-audienceexchange/main b/tests/006-audienceexchange/main
index ad662dd..a3cecef 100644
--- a/tests/006-audienceexchange/main
+++ b/tests/006-audienceexchange/main
@@ -4,7 +4,7 @@ fi
# assumes vault token is already present
set -e
-htgettoken --nooidc --nokerberos --nossh -a $VAULTSERVER -i $ISSUER --audience="$TESTAUDIENCES"
+htgettoken --novaulttoken -a $VAULTSERVER -i $ISSUER --audience="$TESTAUDIENCES"
TOKENAUDIENCES="$(echo $(htdecodetoken |jq -r .aud[]))"
if [ "$TOKENAUDIENCES" != "$TESTAUDIENCES" ]; then
diff --git a/tests/007-minsecs/main b/tests/007-minsecs/main
index 08a60f8..60f53c3 100644
--- a/tests/007-minsecs/main
+++ b/tests/007-minsecs/main
@@ -2,10 +2,10 @@
# cached in vault is not close to its expiration
set -e
# make sure there's normal token, not an exchanged token
-htgettoken --nooidc --nokerberos --nossh -a $VAULTSERVER -i $ISSUER
+htgettoken --novaulttoken -a $VAULTSERVER -i $ISSUER
EXPTIME="$(htdecodetoken|jq -r .exp)"
# make sure that the same token is returned from cache the second try
-htgettoken --nooidc --nokerberos --nossh -a $VAULTSERVER -i $ISSUER
+htgettoken --novaulttoken -a $VAULTSERVER -i $ISSUER
EXPTIME2="$(htdecodetoken|jq -r .exp)"
if [ "$EXPTIME" != "$EXPTIME2" ]; then
echo "The same token was not received twice from vault!"
@@ -16,7 +16,7 @@ fi
sleep 2
NOW="$(date +%s)"
let MINSECS=$EXPTIME-$NOW+1
-htgettoken --nooidc --nokerberos --nossh -a $VAULTSERVER -i $ISSUER --minsecs=$MINSECS
+htgettoken --novaulttoken -a $VAULTSERVER -i $ISSUER --minsecs=$MINSECS
EXPTIME3="$(htdecodetoken|jq -r .exp)"
if [ "$EXPTIME" = "$EXPTIME3" ]; then
echo "The access token was not renewed!"
diff --git a/tests/008-minsecsexchange/main b/tests/008-minsecsexchange/main
index befdee6..1a6400c 100644
--- a/tests/008-minsecsexchange/main
+++ b/tests/008-minsecsexchange/main
@@ -2,10 +2,10 @@
# cached in vault is not close to its expiration
set -e
# make sure there's an exchanged token
-htgettoken --nooidc --nokerberos --nossh -a $VAULTSERVER -i $ISSUER --scopes="$TESTSCOPES"
+htgettoken --novaulttoken -a $VAULTSERVER -i $ISSUER --scopes="$TESTSCOPES"
EXPTIME="$(htdecodetoken|jq -r .exp)"
# make sure that the same token is returned from cache the second try
-htgettoken --nooidc --nokerberos --nossh -a $VAULTSERVER -i $ISSUER --scopes="$TESTSCOPES"
+htgettoken --novaulttoken -a $VAULTSERVER -i $ISSUER --scopes="$TESTSCOPES"
EXPTIME2="$(htdecodetoken|jq -r .exp)"
if [ "$EXPTIME" != "$EXPTIME2" ]; then
echo "The same token was not received twice from vault!"
@@ -16,7 +16,7 @@ fi
sleep 2
NOW="$(date +%s)"
let MINSECS=$EXPTIME-$NOW+1
-htgettoken --nooidc --nokerberos --nossh -a $VAULTSERVER -i $ISSUER --minsecs=$MINSECS --scopes="$TESTSCOPES"
+htgettoken --novaulttoken -a $VAULTSERVER -i $ISSUER --minsecs=$MINSECS --scopes="$TESTSCOPES"
EXPTIME3="$(htdecodetoken|jq -r .exp)"
if [ "$EXPTIME" = "$EXPTIME3" ]; then
echo "The access token was not renewed!"
diff --git a/tests/013-showbearerurl/main b/tests/013-showbearerurl/main
index c07a67a..2f72240 100644
--- a/tests/013-showbearerurl/main
+++ b/tests/013-showbearerurl/main
@@ -1,4 +1,4 @@
-URL="$(htgettoken --nooidc --nokerberos --nossh -a $VAULTSERVER -i $ISSUER --showbearerurl --nobearertoken)"
+URL="$(htgettoken --novaulttoken -a $VAULTSERVER -i $ISSUER --showbearerurl --nobearertoken)"
if [ -z "$URL" ]; then
echo "Nothing came from stdout!"
diff --git a/tests/014-checkdefaultsub/main b/tests/014-checkdefaultsub/main
index 3bb8ac7..fba38a8 100644
--- a/tests/014-checkdefaultsub/main
+++ b/tests/014-checkdefaultsub/main
@@ -2,7 +2,7 @@ if [ -z "$GROUPSUBPAT" ]; then
exit $SKIPCODE
fi
set -ex
-htgettoken --nokerberos --nooidc --nossh -a $VAULTSERVER -i $ISSUER --scopes="$TESTSCOPES"
+htgettoken --novaulttoken -a $VAULTSERVER -i $ISSUER --scopes="$TESTSCOPES"
EXPTIME="$(htdecodetoken|jq -r .exp)"
# check sub for token exchange
@@ -15,7 +15,7 @@ htdecodetoken | jq -r .sub | grep -v $GROUPSUBPAT
sleep 2
NOW="$(date +%s)"
let MINSECS=$EXPTIME-$NOW+1
-htgettoken --nooidc --nokerberos --nossh -a $VAULTSERVER -i $ISSUER --minsecs=$MINSECS
+htgettoken --novaulttoken -a $VAULTSERVER -i $ISSUER --minsecs=$MINSECS
EXPTIME2="$(htdecodetoken|jq -r .exp)"
if [ "$EXPTIME" = "$EXPTIME2" ]; then
echo "The access token was not renewed!"
diff --git a/tests/015-checkgroupsub/main b/tests/015-checkgroupsub/main
index 02696b6..a2a843a 100644
--- a/tests/015-checkgroupsub/main
+++ b/tests/015-checkgroupsub/main
@@ -17,7 +17,7 @@ htdecodetoken | jq -r .sub | grep $GROUPSUBPAT
sleep 2
NOW="$(date +%s)"
let MINSECS=$EXPTIME-$NOW+1
-htgettoken --nooidc --nokerberos --nossh -a $VAULTSERVER -i $ISSUER -r $GROUPROLE --minsecs=$MINSECS
+htgettoken --novaulttoken -a $VAULTSERVER -i $ISSUER -r $GROUPROLE --minsecs=$MINSECS
EXPTIME2="$(htdecodetoken|jq -r .exp)"
if [ "$EXPTIME" = "$EXPTIME2" ]; then
echo "The access token was not renewed!"