Skip to main content

Refresh Token

The Refresh Token grant (RFC 6749 §6) lets a client obtain a new access token without prompting the user to sign in again. The client sends its refresh token to the token endpoint and receives a new access token (and optionally a new refresh token) in return.

Refresh tokens are long-lived credentials and must be treated as such: they replace the user's session. ThunderID supports rotation so refresh tokens themselves can be short-lived in practice.

How It Works

The refresh request goes directly to the token endpoint and returns a new token bundle.

POST /oauth2/token HTTP/1.1
Host: thunderid.example.com
Authorization: Basic <client_id:client_secret>
Content-Type: application/x-www-form-urlencoded

grant_type=refresh_token
&refresh_token=<refresh_token>
&scope=openid%20profile # optional, narrow only
&resource=https://api.example.com # optional, must match the existing audience

Response (rotation enabled):

{
"access_token": "eyJhbGciOi...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "eyJhbGciOi...",
"scope": "openid profile"
}

Authorization on Refresh

Each refresh re-evaluates the subject's authorization rather than replaying the decision made when the refresh token was issued.

Change since the refresh token was issuedEffect on the refresh
A role is unassigned from the subject, deleted, or stripped of a permissionThe affected permission scopes are dropped from the new access token
The subject loses a group membership that granted a roleThe affected permission scopes are dropped from the new access token
A permission is removed from the resource serverThe scope is dropped from the new access token
The user's password is resetThe refresh fails with invalid_grant
The client secret is rotatedThe refresh fails with invalid_grant
The user is deletedThe refresh fails with invalid_grant

OIDC scopes such as openid, profile, and email are not permission scopes, so authorization changes never remove them.

Access tokens issued earlier are unaffected and remain valid until they expire. Clients must handle a refreshed access token that carries fewer scopes than the previous one, and an invalid_grant response that requires the user to sign in again.

How ThunderID Implements It
AspectBehavior
EndpointPOST /oauth2/token with grant_type=refresh_token
Client authenticationSame methods as the original grant, see Client Authentication Methods
RotationControlled globally by oauth.refresh_token.renew_on_grant in deployment.yaml, enabled by default. Every refresh issues a new refresh_token; when disabled, the existing one is reused
Old token after rotationWhen oauth.refresh_token.revoke_previous_on_renew is enabled, the consumed refresh token is revoked after renewal. A revocation failure stops the rotation
Grant lifetimeA rotated refresh token inherits the expiry of the token it replaces, so refreshing extends access but never the grant. Once oauth.refresh_token.validity_period has elapsed since the original grant, the user must authenticate again
Audience preservationThe new access token keeps the refresh token's single audience when resource is omitted
Resource validationWhen supplied, resource must match the refresh token's audience. A mismatch returns invalid_target
Scope narrowingThe scope parameter may request a subset of the originally granted scopes. Asking for a wider scope returns invalid_scope
Authorization re-evaluationPermission scopes are re-evaluated against the subject's current role and group assignments on every refresh. Scopes the subject no longer holds are dropped
Credential changesEach entity records when its password or client secret last changed. A refresh token established at or before that instant is rejected with invalid_grant
DPoP bindingA DPoP-bound refresh token continues to require a DPoP proof on refresh; the new access token inherits the cnf.jkt binding

What Changes Between the Original and Refreshed Token

ClaimBehavior on refresh
subUnchanged
issUnchanged
audPreserved. A supplied resource must match this value
scopePreserved by default. Narrowed when scope is supplied, and narrowed further to the permissions the subject currently holds
exp / iatNew values
cnf.jkt (DPoP)Preserved
auth_timeNot carried into refreshed tokens

Try It in ThunderID

  1. Open Applications or Agents in the ThunderID Console and select your client.
  2. Open the Advanced tab.
  3. Under Grant Types, add refresh_token alongside a token-issuing grant (authorization_code or urn:openid:params:grant-type:ciba).
  4. Save.

Refresh token rotation is a deployment-wide setting, not per client. It is enabled by default; disable it by setting oauth.refresh_token.renew_on_grant: false in deployment.yaml. By default, oauth.refresh_token.revoke_previous_on_renew is true, so a successful rotation revokes the consumed refresh token.

Because rotation makes each refresh token single-use, a client must persist the new refresh_token from every response and discard the old one. Replaying a consumed token revokes the entire token family, ending the session. Clients that issue concurrent refresh requests should serialise them, since only the first will succeed.

  • Authorization Code, the most common source of refresh tokens
  • Resource Indicators, preserve and validate the resource binding during refresh
  • DPoP, refresh tokens issued under DPoP remain sender-constrained
  • Token Formats, token lifetimes, signing and encryption settings

Explore with AI

ThunderID LogoThunderID Logo

Product

DocsAPIsSDKs
© Copyright Linux Foundation Europe.For web site terms of use, trademark policy and other project policies please see https://linuxfoundation.eu/en/policies.