Monitor auth tokens for problems like upcoming expiration
Currently supported providers:
github: GitHubfwf: Fermyon Wasm Functionslinode: Linodetailscale: Tailscale
The provider will be auto-detected for each provided token.
$ TOKEN=$(gh auth token) auth-token-monitor --token-env-vars TOKEN
Checking "TOKEN"...
Token user login: your-github-username
Token expiration: NONE
Rate limit usage: 6 / 5000 (~0%)
OAuth scopes: gist, read:org, repo, workflow
$ OLD_TOKEN="<some expiring token>" auth-token-monitor --token-env-vars OLD_TOKEN
Checking "OLD_TOKEN"...
Token user login: your-github-username
Token expiration: 2025-07-09 21:27:10 +0000 UTC (9.1 days)
WARNING: Expiring soon!
Rate limit usage: 9 / 5000 (~0%)
OAuth scopes: read:packages
Error: checks failed for token(s): OLD_TOKEN
exit status 1Here we assume TOKEN in the shell environment holds the value of a FwF auth token,
e.g. procured via spin aka auth tokens create --name mytoken:
$ ./auth-token-monitor --token-env-vars TOKEN
Checking "TOKEN" with provider "fwf"...
Token expiration: 2026-02-14 00:04:38.312316 +0000 UTC (15.1 days)The Linode provider uses the linodego SDK to call the List Personal Access Tokens API. It checks the expiration of all tokens returned by the API, not just the token used to authenticate.
$ LINODE_TOKEN="<your linode personal access token>" auth-token-monitor --token-env-vars LINODE_TOKEN
Checking "LINODE_TOKEN" with provider "linode"...
Found 3 Linode personal access token(s)
[my-cli-token] (id=123456): expiration: 2026-03-15T00:00:00Z (33.9 days)
[ci-deploy-token] (id=123457): expiration: 2026-02-12T00:00:00Z (3.1 days)
WARNING: Token "ci-deploy-token" expiring soon!
[long-lived-token] (id=123458): expiration: NEVER
Error: checks failed for token(s): ci-deploy-token
exit status 1The Tailscale provider uses the tailscale v2 SDK to call the List and Get Keys APIs. In contrast to the other providers supported by this program, Tailscale does not inform on the expiration date of the key/token used to query the API. Rather, either all keys are returned that are accessible to the provided API token (or OAuth client; see Auth Credentials below) or a specific key can be viewed when its key ID is provided.
Therefore, the current default is to list (and check expiration of) all keys in the tailnet, assuming sufficient privileges of the supplied token or auth credentials. However, the list of keys to be checked can be filtered via a list of IDs; see Filtering below.
There are a few authentication modes for this provider:
- if
TS_API_KEYis set, this value will be used instead of the supplied token (if different) for API requests - if
TS_OAUTH_CLIENT_IDandTS_OAUTH_CLIENT_SECRETare set, an ephemeral access token generated from the OAuth credentials will be used instead of the supplied token (if different) for API requests - if there there are no credentials in the env, the supplied token will be used
Additionally, a specific tailnet can be supplied via TAILNET. Otherwise, - is used, which represents the
default tailnet associated with the API credential.
For example:
$ export TS_API_KEY='...'
$ ./auth-token-monitor --token-env-vars TS_API_KEY
Checking token "TS_API_KEY" with provider "tailscale"...
No TAILNET supplied; using default tailnet associated with supplied credential
Using TS_API_KEY for API requests
Found 2 Tailscale key(s) in the - Tailnet
[test] (id=kB45wP7bzx11CNTRL): expiration: NEVER
[test2] (id=kVbFQqaG6F11CNTRL): expiration: 2026-03-31T18:48:44Z (1.0 days)
Scopes: [all all:read]
WARNING: Key "test2" (id=kVbFQqaG6F11CNTRL) expiring soon!
Error: checks failed for token(s): test2$ unset TS_API_KEY
$ export TS_OAUTH_CLIENT_ID='...' TS_OAUTH_CLIENT_SECRET='...'
$ export TAILNET='mytailnet'
$ ./auth-token-monitor --token-env-vars TS_OAUTH_CLIENT_SECRET
Checking token "TS_OAUTH_CLIENT_SECRET" with provider "tailscale"...
Using OAuth client to generate an access token for API requests
Found 2 Tailscale key(s) in the mytailnet Tailnet
[test] (id=kB45wP7bzx11CNTRL): expiration: NEVER
[test2] (id=kVbFQqaG6F11CNTRL): expiration: 2026-03-31T18:48:44Z (1.0 days)
Scopes: [all all:read]
WARNING: Key "test2" (id=kVbFQqaG6F11CNTRL) expiring soon!
Error: checks failed for token(s): test2To filter which Tailscale keys are checked, supply TS_KEY_IDS in the environment.
The value should be a comma-delimited string of key ID(s).
For example:
$ export TS_TOKEN='...'
$ export TS_KEY_IDS='kVbFQqaG6F11CNTRL'
$ ./auth-token-monitor --token-env-vars TS_TOKEN
Checking token "TS_TOKEN" with provider "tailscale"...
Using the provided token for Tailscale API requests, as neither TS_API_KEY nor OAuth credentials (TS_OAUTH_CLIENT_ID, TS_OAUTH_CLIENT_SECRET) are set
Filtering Tailscale key(s) to only include the following IDs: [kVbFQqaG6F11CNTRL]
[test2] (id=kVbFQqaG6F11CNTRL): expiration: 2026-03-31T18:48:44Z (0.9 days)
Scopes: [all all:read]
WARNING: Key "test2" (id=kVbFQqaG6F11CNTRL) expiring soon!
Error: checks failed for token(s): test2The Terraform provider uses the go-tfe SDK from Hashicorp to authenticate with the Terraform API and check token expiration dates. Terraform does not provide the expiration date of the token used for authentication with the API. Rather, tokens can be listed by type (e.g. org, team and user) and those that are visible to the authentication token are returned.
Therefore, the current default is to list (and check expiration of) all tokens that the authentication token can access. Note that currently, we only check tokens of the same type as the authentication token, e.g. by org, team or user.
Example:
$ export TERRAFORM_TEAM_TOKEN='...'
$ ./auth-token-monitor --token-env-vars TERRAFORM_TEAM_TOKEN
Checking token "TERRAFORM_TEAM_TOKEN" with provider "terraform"...
Found 3 team token(s) in the "tf-org" organization
[test] (id=at-ivU66CAEmzQbPi8V): expiration: 2026-04-23T21:20:46Z (-3.8 days)
ALERT: Terraform team token "test" (id=at-ivU66CAEmzQbPi8V) has expired!
[test2] (id=at-vQ9FBaL7YyMMh7uC): expiration: 2026-04-28T15:05:44Z (1.0 days)
WARNING: Terraform team token "test2" (id=at-vQ9FBaL7YyMMh7uC) expiring soon!
[test3] (id=at-yWUynyp7oFzc8sE3): expiration: 2026-05-16T21:40:05Z (19.2 days)
Error: checks failed for token(s): at-ivU66CAEmzQbPi8V, at-vQ9FBaL7YyMMh7uCThis repo publishes a lightweight container with
ko.
You can build the image locally after ko is installed on your system via:
KO_DOCKER_REPO=<registry>/auth-token-monitor ko build --bareYou can check expiration for a token in a Github Actions job directly using the
container, e.g. for a secret named TEST_TOKEN:
jobs:
test_token_expiration:
runs-on: ubuntu-latest
steps:
- uses: docker://ghcr.io/fermyon/auth-token-monitor:latest
with:
args: "--token-env-vars TEST_TOKEN"
env:
TEST_TOKEN: ${{ secrets.TEST_TOKEN }}You can point to a directory with --tokens-dir, which can be convenient when
using this as an e.g. Kubernetes CronJob to mount existing Secrets to be
checked. All files in the directory will be parsed as either bare tokens or
dockerconfig JSON.