Why this lesson exists
Ask a platform team for their worst Vault outage and it is rarely Vault being down. It is "the service worked for 32 days and then stopped" - a token reached its maximum lifetime. Or "we revoked one token and three services died" - those services had child tokens of it. Everything you do in Vault, you do with a token, and tokens have lifetimes and family trees. Knowing exactly how they behave is the difference between a five-minute fix and a long night.
What you need to know already: the request shape - client, path, token, policy (the first lesson of this chapter); an unsealed server (the architecture lesson); environment variables and $(...) in bash (6.12).
The words you need first
- Token - the credential every request carries. Service tokens start with
hvs., batch tokens withhvb.. A token has policies (what it may do) and a TTL. - Accessor - a second id for a token that can look it up, renew it and revoke it, but cannot be used to make requests. Safe to log, to put in tickets, to give to an admin.
- TTL (time to live) - how long until the token expires. Renewing pushes the expiry out again.
- Max TTL - the hard limit: no renewal can take the token past it.
- Periodic token - a token with a period instead of a max TTL: each renewal sets the TTL back to the period, forever, as long as it is renewed in time.
- Parent / child - a token created by another token is its child. Revoking the parent revokes every child, grandchild and the leases they own. An orphan has no parent.
- Auth method - how you prove who you are to get a token: userpass, LDAP, OIDC for people; AppRole, Kubernetes, cloud IAM, JWT for machines.
Logging in is exchanging an identity for a token
proves who you are gets back
person --- username + password --> auth/userpass/login/alice --> token, TTL 30m
CI job --- role_id + secret_id --> auth/approle/login --> token, TTL 10m
pod --- ServiceAccount JWT --> auth/kubernetes/login --> token, TTL 1h
Every auth method ends the same way: Vault creates a token with the policies the method's configuration says, and a TTL. From then on Vault does not care how you logged in - it only sees the token. The token auth method is built in and cannot be disabled: it is where all tokens live, whatever method created them.
$ vault auth list
Path Type Accessor Description Version
---- ---- -------- ----------- -------
token/ token auth_token_8ae79b34 token based credentials n/a
Reading a token
Your shell is logged in to the lab Vault with a lab-admin token (the platform team's admin policy - nobody works with the root token day to day):
$ vault token lookup
Key Value
--- -----
accessor 0za7jbcsSimhVT4YcfVLcYfu
creation_time 1790107203
creation_ttl 768h
display_name token-lab-admin
entity_id n/a
expire_time 2026-10-24T20:00:03.000757000Z
explicit_max_ttl 0s
id hvs.CAESIWOCC8Q48fupiMV6U3IKAALnuugwvYv4yaWQiHGh4KHGh2cy4qoASRy5KPKRPiMrospDo74y6p3p8B8G2
issue_time 2026-09-22T20:00:03.000557000Z
meta <nil>
num_uses 0
orphan true
path auth/token/create-orphan
policies [default lab-admin]
renewable true
ttl 767h59m59s
type service
Field by field, the ones you will read in incidents:
- policies - what it may do.
defaultis attached to every token unless you say otherwise; it lets a token look itself up, renew and revoke itself, use its cubbyhole. - ttl / expire_time - how long it has left, and when that is.
- creation_ttl - the TTL it got when created; a renewal without
-incrementasks for this again. - explicit_max_ttl - a hard cap set at creation (0s = none set; the mount's and the system's max still apply).
- path - how it was created:
auth/userpass/login/alice,auth/approle/login,auth/token/create. In an audit log this tells you which method a client used. - display_name - a label for humans and the audit log (
userpass-alice,token-ci). - orphan - true: nothing above it in the tree.
- num_uses - 0 = unlimited; otherwise the requests left.
768h is 32 days: the system default and maximum TTL. Unless something sets a shorter one, every token and every lease lives at most 32 days - which is exactly when the "worked for a month, then stopped" outages happen.
TTL, max TTL and renewal
A token's life:
$ vault token create -policy=default -ttl=10m -explicit-max-ttl=30m -display-name=demo
Key Value
--- -----
token hvs.CAESITiWmwE2nyBNBF5kPUOriDzdoPqsjJbOfqSuqWGh4KHGh2cy4J8hth5taRXVIwWmjC6jfhde6PZRUfLsA
token_accessor s32IVHi6tAAaLjeiuCtFiGhV
token_duration 10m
token_renewable true
token_policies ["default"]
identity_policies []
policies ["default"]
It expires in 10 minutes unless renewed. Renewing asks for more time from now, and Vault caps it at the max:
$ VAULT_TOKEN=$T vault token renew -increment=1h
WARNING! The following warnings were returned from Vault:
* TTL of "1h" exceeded the effective max_ttl of "29m59s"; TTL value is capped
accordingly
Key Value
--- -----
token hvs.CAESI1TO2XdpyZfksSDfZcqA8uKeOrC1sqAc8MUEGPGh4KHGh2cy4Tu2av4MMF4dDErGRwKQxLO8JY4SUEDz1
token_accessor 5elgBuAdDrNnCfehjAOTOp2a
token_duration 29m59s
token_renewable true
token_policies ["default"]
identity_policies []
policies ["default"]
Read the warning: that is the moment a client can see its token's end coming. Thirty minutes after creation, no renewal helps - the token is revoked, and the only way forward is to log in again. A client that only ever renews, and never re-authenticates, works perfectly until the max TTL and then fails with permission denied on every request.
The max TTL is the smallest of:
- the token's own explicit_max_ttl (set at creation);
- the auth method's setting for this login (a role's or user's token_max_ttl);
- the auth mount's max_lease_ttl (
vault auth tune -max-lease-ttl=...); - the system maximum, 768h by default (
max_lease_ttlinvault.hcl).
Yes - renewing with a small -increment can shorten a token.
Periodic tokens
A long-running service that cannot re-authenticate easily (no way to get a new secret) can use a periodic token: every renewal sets the TTL back to the period, there is no max TTL, and the token lives forever as long as it renews within the period.
$ vault token lookup $T | grep -E "ttl|period|explicit"
creation_ttl 24h
explicit_max_ttl 0s
period 24h
ttl 23h59m59s
Convenient, and a liability: a leaked periodic token never expires on its own. Prefer short TTLs and re-authentication through an auth method (AppRole, Kubernetes) - which is exactly what Vault Agent automates, later in this chapter.
The token tree
A token created with vault token create is a child of the token that created it. Revoke the parent and Vault walks down the tree:
$ P=$(vault token create -policy=lab-admin -ttl=1h -field=token)
$ C=$(VAULT_TOKEN=$P vault token create -policy=default -ttl=1h -field=token)
$ O=$(VAULT_TOKEN=$P vault token create -policy=default -ttl=1h -orphan -field=token)
$ vault token revoke $P
Success! Revoked token (if it existed)
$ vault token lookup $C
Error looking up token: Error making API request.
URL: POST https://127.0.0.1:8200/v1/auth/token/lookup
Code: 403. Errors:
* bad token
$ vault token lookup $O | grep -E "orphan|path"
orphan true
path auth/token/create-orphan
The child died with its parent; the orphan survived. Everything the child had created - grandchild tokens, database credentials (leases, a later lesson) - is revoked too. That is a feature: revoking one compromised token takes back everything derived from it. It is also how one vault token revoke takes down three services that were given child tokens of a person's token.
Rules worth knowing:
- Tokens from an auth method login (userpass, AppRole, Kubernetes) are orphans: their life is tied to the login, not to another token.
- Creating an orphan with
vault token create -orphanneedssudoonauth/token/create(or the root policy). vault token revoke -mode=orphan TOKENrevokes only the token and turns its children into orphans.- A child's policies must be a subset of the parent's - you cannot create a token with more power than your own:
* child policies must be subset of parent's policies.
Accessors
You often need to act on a token you do not have (and should not have): the token of a departed colleague, a token found in a log line. Every token has an accessor:
$ vault token lookup -accessor $(vault token lookup -field=accessor) | head -6
Key Value
--- -----
accessor pQkSk4591PaltrIKWpDz4vqQ
creation_time 1790107203
creation_ttl 768h
display_name token-lab-admin
vault token revoke -accessor ACCESSOR revokes it. vault list auth/token/accessors (a sudo path) lists every token's accessor - the inventory of who is logged in. Audit logs record accessors (HMAC'd unless configured otherwise), so "revoke whatever that log line used" is possible without anyone ever seeing the token itself.
Use limits and batch tokens
-use-limit=N makes a token die after N requests - good for a one-shot bootstrap:
$ VAULT_TOKEN=$T vault token lookup
Error looking up token: Error making API request.
URL: GET https://127.0.0.1:8200/v1/auth/token/lookup-self
Code: 403. Errors:
* permission denied
Batch tokens (-type=batch, hvb. prefix) are not stored in Vault at all - the token itself carries its data, encrypted. They are cheap at very high volume, but cannot be renewed, cannot create children and do not get revoked when a parent is.
A first auth method: userpass
userpass is a username/password store inside Vault - fine for labs and break-glass accounts; real people log in through LDAP or OIDC (your company SSO), which work the same way from the token's point of view.
$ vault auth enable userpass
Success! Enabled userpass auth method at: userpass/
$ vault write auth/userpass/users/alice password=s3cret-pass token_policies=default token_ttl=30m token_max_ttl=8h
Success! Data written to: auth/userpass/users/alice
The token_* parameters are the same on every auth method's roles and users: which policies the tokens get, their TTL, their max TTL. A working day for a person is a sensible max; a CI job gets minutes.
$ vault login -method=userpass username=alice password=s3cret-pass
Success! You are now authenticated. The token information displayed below
is already stored in the token helper. You do NOT need to run "vault login"
again. Future Vault requests will automatically use this token.
Key Value
--- -----
token hvs.CAESIwKUuW60f93YGKmDIAayEogDZ8ycpkzUibedKxGh4KHGh2cy4QvI7YUUaubUOuTbPifRYFh51xXbifKHt
token_accessor Xb85vzi0Yhdx682aBhGynh32
token_duration 30m
token_renewable true
token_policies ["default"]
identity_policies []
policies ["default"]
token_meta_username alice
Without password= it prompts (Password (will be hidden):), which keeps the password out of shell history - do that outside labs. Vault also creates an entity for alice (entity_id in her token): one identity across auth methods, so the same person logging in with LDAP and OIDC is still one entity with one set of identity policies.
Where the CLI gets its token
VAULT_TOKEN, if set;- otherwise
~/.vault-token(written byvault login- the token helper).
VAULT_TOKEN wins, and vault login warns you:
$ VAULT_TOKEN=hvs.bogus vault login -method=userpass username=alice password=s3cret-pass | head -3
WARNING! The VAULT_TOKEN environment variable is set! The value of this
variable will take precedence; if this is unwanted please unset VAULT_TOKEN or
update its value accordingly.
Two errors tell you which problem you have:
| error | meaning |
|---|---|
Code: 400. Errors: * missing client token | no token was sent at all (no VAULT_TOKEN, no ~/.vault-token) |
Code: 403. Errors: * permission denied | a token was sent, but it is invalid or expired, or it is used up |
Code: 403. Errors: * 1 error occurred: * permission denied | the token is valid, but its policies do not allow this (the next lessons) |
Root tokens
A root token has the root policy: every capability on every path, no TTL. Use one only to bootstrap (create the first admin policy and auth method) and in emergencies, then revoke it. When you need root again, a quorum of unseal key holders generates a new one with vault operator generate-root. A root token sitting in a file or a CI variable is the worst secret you can leak.
In an interview: "A service worked for weeks and suddenly gets permission denied from Vault. Where do you look?" - at the token's lifetime: vault token lookup -accessor (from the audit log or the app) for ttl, expire_time and the max TTL; most likely it hit its max TTL (default 768h) because the app only renewed and never re-authenticated. Fix by re-authenticating through its auth method before the max, ideally with Vault Agent.
What you can now do
- Read
vault token lookupand say how long a token has and why. - Predict a renewal: now + increment, capped by explicit max, role max, mount max, 768h.
- Explain the token tree, orphans, and what revoking a parent takes down.
- Use accessors to look up and revoke tokens you do not hold.
- Enable userpass, create a user with token policies and TTLs, and log in.
- Tell "missing client token" from "permission denied".