Refresh tokens
Access tokens issued by Truora Pass expire after 60 minutes by default. The Authorization Code flow also issues a refresh_token, which lets your backend obtain fresh access tokens without sending the user through authorization again.
Refresh tokens are long-lived (365 days by default), single-use, and rotated on every exchange.
Note: every Authorization Code token exchange returns a refresh token, so any application using that flow can use this grant. The CIBA flow does not issue refresh tokens.
Exchanging a refresh token
Send a JSON request to the token endpoint:
curl -X POST https://api.pass.truora.com/v1/oauth2/token \
-H "Content-Type: application/json" \
-d '{
"grant_type": "refresh_token",
"refresh_token": "<your most recent refresh token>",
"client_id": "WLT_APP_your_client_id",
"client_secret": "your_client_secret"
}'
| Field | Required | Description |
|---|---|---|
grant_type |
Yes | Must be refresh_token. |
refresh_token |
Yes | The most recently issued refresh token. |
client_id |
Yes | Your application’s client ID — must be the client the token was issued to. |
client_secret |
Yes | Your application’s client secret. |
scope |
No | Space-delimited subset of the originally granted scopes, to narrow the new access token. |
On success:
{
"access_token": "<new access token>",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "openid profile email",
"refresh_token": "<NEW refresh token — replace the old one>"
}
Note: the refresh grant never returns an id_token. Read up-to-date identity claims from GET /v1/oauth2/userinfo with the new access token — see UserInfo and claims.
Rotation: every exchange returns a new token
Refresh tokens are single-use. Every successful exchange consumes the token you sent and returns a new one belonging to the same token family. Always persist the refresh_token from the latest response and discard the previous one — the old token cannot be used again.
The token lifetime slides with rotation: each successful exchange gives the new token a full lifetime (365 days by default) from the moment of rotation. A user who returns at least once a year therefore never needs to re-authorize; a family that goes unused for the full lifetime expires.
Reuse detection
If a refresh token that was already used is presented again, Truora Pass treats it as a possible token leak and revokes the entire token family — including the currently valid newest token. The exchange fails with invalid_grant (refresh token already used), and every subsequent exchange in that family fails too.
To recover, send the user through the Authorization Code flow again to obtain a new grant.
Note: reuse detection means a buggy retry (for example, replaying a request after a timeout whose original attempt actually succeeded) can revoke your tokens. Persist the new refresh token atomically with marking the old one as used on your side.
Client binding
A refresh token can only be exchanged by the application it was issued to. Presenting it with a different client_id fails with invalid_grant (refresh token was not issued to this client).
Down-scoping
The optional scope field lets you request an access token with fewer scopes than originally granted:
{
"grant_type": "refresh_token",
"refresh_token": "<your most recent refresh token>",
"client_id": "WLT_APP_your_client_id",
"client_secret": "your_client_secret",
"scope": "openid email"
}
The requested scopes must be a subset of the scopes in the original grant; anything outside that set fails with invalid_scope. Omitting scope keeps the originally granted scopes.
Errors
This grant answers errors in the standard OAuth 2.0 (RFC 6749) envelope, {"error": "...", "error_description": "..."}:
| HTTP | error |
When |
|---|---|---|
| 401 | invalid_client |
Wrong client_id / client_secret. |
| 400 | invalid_grant |
The refresh token is invalid or expired; was not issued to this client; or was already used (reuse detected — the whole family is revoked). |
| 400 | invalid_scope |
The requested scope is not a subset of the originally granted scopes. |
On invalid_grant, discard your stored tokens for that user and re-run the Authorization Code flow.