Token Lifecycle in Practice
Every OAuth flow guide mentions refresh_token, but a long-running integration (one that keeps running across many requests, workers, or days) needs more than “swap the token when it expires.” This page covers real token lifetimes, caching a token across workers, when to refresh, and what can invalidate a token before it would otherwise expire.
Token lifetimes by flow
Section titled “Token lifetimes by flow”The access token’s lifetime is one fixed duration, the same for every flow. The refresh token’s lifetime is not: it depends on which OAuth flow issued it.
| Flow | Access token TTL | Refresh token TTL |
|---|---|---|
| Client Credentials | About 1 hour | About 30 days |
| Native app (PKCE, loopback redirect) | About 1 hour | No fixed expiry: stays valid until it’s rotated away or revoked |
| Authorization Code + custom HTTPS redirect | About 1 hour | No fixed expiry: stays valid until it’s rotated away or revoked |
Cache the token, don’t mint one per request
Section titled “Cache the token, don’t mint one per request”Requesting a fresh access token for every API call, or independently in every worker process, works but wastes a round trip on every single request for a token that’s already good for about an hour. Request one token, cache it (in memory for a single process, or in a shared store such as Redis for a fleet of workers) keyed by the credential that issued it, and hand the cached token to every request until it’s close to expiry.
This also matters for the refresh token: the fewer processes that independently exchange it, the less likely you are to hit the race described below.
Refresh on expiry, not just on 401
Section titled “Refresh on expiry, not just on 401”Because the access token TTL is fixed and known in advance, refresh proactively: track when you obtained the token (or decode its exp claim) and request a new one shortly before that time, rather than waiting for a request to fail first.
Still handle a failed request as a fallback, but branch on which error you got:
401withnot_authenticated: the request didn’t carry a usable bearer token at all. This comes from a missing or malformedAuthorizationheader on your side, not a signal to refresh.401withinvalid_token: the token’s signature or expiry check failed. Refresh and retry once.403: never a token problem. The token is valid; the caller doesn’t have the scope, content access, or role the operation requires. Refreshing will not help. See Error Codes: rate limiting, authentication, and access control for the full breakdown of what each code means.
Concurrent refresh races
Section titled “Concurrent refresh races”A refresh token is single-use: exchanging it with grant_type=refresh_token invalidates that refresh token and issues a new access token and a new refresh token together. If several workers share one cached refresh token and two of them try to refresh at nearly the same moment, only one exchange succeeds; the other gets a generic 401, not a distinguishable “already used” error.
What invalidates a token early
Section titled “What invalidates a token early”None of the events below revoke a live access token outright. Each one blocks something new (a fresh token request, or the next refresh) while the access token already in hand keeps working until its own TTL runs out.
| Trigger | Effect |
|---|---|
| The OAuth application’s client secret is rotated | New token or refresh requests using the old secret are rejected immediately. An access token already issued is unaffected and keeps working until it naturally expires. |
| The OAuth application or its service user is removed | Blocks minting new tokens for that application. Tokens already issued are not proactively revoked. |
| The OAuth application’s scopes are changed | An access token already issued keeps its original scopes for the rest of its life. The token only picks up the new scopes the next time it’s refreshed or reissued. |
| The grant is explicitly revoked | Blocks the next refresh attempt immediately. The still-valid access token is not force-expired and keeps working until it naturally expires. |
What’s next?
Section titled “What’s next?”- Error Codes for the full breakdown of
401and403responses - Client Credentials Flow, Native Application Flow, or Authorization Code + Custom Redirect Flow for how to get your first token