Tokens and lifetimes

What lives how long, how to refresh, and why presenting an old refresh token twice is dangerous.

What you get

TokenLivesPurpose
access_token1 hourrequests to /me
id_token1 hourproof of identity at sign-in
refresh_tokenas long as the auth.my sessionrefresh without signing in again
refresh_token with offline_access90 daysaccess that outlives the user's sign-out

The difference between the two refresh modes matters. An ordinary site wants the first: sign-in does not fall over after an hour, and when the person signs out of auth.my their access ends with the session, exactly as they expect. Long-lived access to their data while they are away is offline_access, and they approve it as a separate line on the consent screen.

The profile is inside the id_token

The specification allows omitting scope-requested data from the id_token and sending clients to /me for it. We include it — nearly every library reads name and email from there.

{
  "sub": "65df5d53-a1fa-4dd1-ab0a-7f5ecc0ef3a0",
  "email": "[email protected]",
  "email_verified": true,
  "iss": "https://auth.my",
  "aud": "your-client-id"
}

A call to /me is only needed if the data may have changed since sign-in.

Signing

id_token is signed with RS256 — the algorithm every library understands without configuration. Discovery also advertises ES256: choose it explicitly if you want it, the key is there.

Signing keys rotate without notice. That is exactly what /jwks is for, and libraries fetch from it themselves.

Careful

Do not hard-code or pin the key. Key rotation is routine, and an application with a baked-in key breaks the moment it happens.

Refresh

curl -u "CLIENT_ID:CLIENT_SECRET" https://auth.my/token \
  -d grant_type=refresh_token \
  -d refresh_token=CURRENT_TOKEN

The response carries a new refresh token. Store it in place of the old one.

Rotation is single-use: each exchange retires the previous token. That is how theft detection works — if a stolen token is presented after the legitimate owner has already used it, we see it and revoke the whole chain.

The race window

Strict single use breaks ordinary life: two tabs refresh at once, a mobile client retries after a dropped connection, two application processes refresh in parallel.

So a repeat presentation within 30 seconds counts as a race, not theft, and is served. Later than that it is treated as theft: every token on the grant is revoked and the user must sign in again.

The window is measured from first use and repeats do not extend it.

What to do about invalid_grant

It is not an outage, it is a message saying "this token is finished". Causes: the chain was revoked, the user blocked your site, the auth.my session ended, an organization administrator removed their access.

Handle them all the same way: send the user to sign in again. In the normal case they return instantly without noticing.

Revoking your own token

curl -u "CLIENT_ID:CLIENT_SECRET" https://auth.my/token/revocation \
  -d token=TOKEN

This kills one token without touching the user's auth.my session. Full sign-out is in Sign-out and revocation.

Did this page help?