Skip to content
  • Build on Kinde
  • Tokens

Refresh tokens

Refresh tokens are used to request new access tokens.

Access tokens are issued when a user makes an authentication request or a call is made to an API. An access token gives permission to enter and interact with a system.

How refresh tokens work

Link to this section

Access tokens usually have an intentionally short lifetime. However, rather than having a user need to re-authenticate frequently, a refresh token can be used to request a new access token. Refresh tokens operate without user intervention, extending session access without the same security risk as requesting a new access token.

There is no cap on the number of times a refresh token can be used — it remains valid until it expires or is rotated out.

How to get a refresh token

Link to this section

To get a refresh token, you need to include the offline scope when you initiate an authentication request through the https://<your_subdomain>.kinde.com/oauth2/auth endpoint. You also need to initiate Offline Access in your API.

Details on how to do this is provided in our SDKs, but here’s how to do it yourself.

Below is an example using the Authorization Code grant, with the offline scope being one of the scopes passed to the authentication request.

Terminal window
curl -G "https://<your_subdomain>.kinde.com/oauth2/auth" \
-d "response_type=code" \
-d "client_id=<client_id>" \
-d "redirect_uri=<redirect_uri>" \
-d "scope=offline%20email%20openid%20profile"

In a real app you typically redirect the user to this URL in a browser rather than calling it with curl. The response will redirect the user to your redirect_uri with an authorization code in the query string; you then exchange that code for tokens (including a refresh token) via POST to https://<your_subdomain>.kinde.com/oauth2/token with grant_type=authorization_code.

Refresh tokens are stored in sessions. When a session needs to be refreshed (for example, a pre-defined time has passed), the app uses the refresh token on the backend to obtain a new access token, using the https://<your_subdomain>.kinde.com/oauth2/token endpoint with grant_type=refresh_token.

Example: request a new access token using a refresh token

Terminal window
curl -X POST "https://<your_subdomain>.kinde.com/oauth2/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=refresh_token" \
-d "client_id=<client_id>" \
-d "client_secret=<client_secret>" \
-d "refresh_token=<refresh_token>"

Use this only from a secure backend. Do not send client_secret from frontend or public clients; use PKCE for SPAs and similar apps.

Example of a refresh token response

{
"access_token": "<access_token>",
"refresh_token": "<refresh_token>",
"token_type": "Bearer"
}

Refresh token rotation

Link to this section

Kinde always rotates refresh tokens. When you use an existing refresh token to request a new access token, a new refresh token is also generated and provided with your new access token. The old refresh token becomes immediately invalid.

Auto-update of refresh tokens

Link to this section

Kinde allows a small overlap period after rotation where both the previous and new refresh token are valid. This is to account for retries and bad network connections (for example, parallel requests that both send the old token before the rotation response arrives). You can set the lifetime of a refresh token in Kinde. It needs to be longer than the life of an access token.

Client-specific refresh token cookies

Link to this section

When multiple applications share the same custom domain, they normally share a single refresh_token cookie. That can cause one app’s refresh token to overwrite another’s—for example, signing in to App B may replace the refresh token that App A had set, breaking App A’s session.

To avoid this, Kinde supports client-specific refresh token cookies. When enabled for an application, the refresh token is stored in a cookie named with the application’s client ID prefix (for example, refresh_token_abc123), so each app keeps its own refresh token independently.

  • Where to enable: Settings > Applications > [your app] > Tokens > Refresh token cookies
  • Requirement: A custom domain must be configured; this feature is not available without one.
  • Default: The feature is disabled by default.
  • Cookie naming: Kinde uses the first 6 characters of the application’s client ID to build the cookie name (e.g. refresh_token_abc123).
  • Fallback: If a client-specific cookie is not found, Kinde falls back to the standard refresh_token cookie.

Refresh tokens when you are not using an SDK

Link to this section

You should store the refresh token you get with your initial /token request. Otherwise, your user will need to go through the sign in process again, to get a new access token.

Use the SDK getToken function to silently refresh tokens

Link to this section

Front-end packages do not all behave the same way:

How long does a refresh token last?

Link to this section

Refresh tokens have a default lifetime of 15 days (1,296,000 seconds). You can change this in Settings > Environment > Applications > [your app] > Tokens. The refresh token lifetime must always be set longer than the access token lifetime.

There is no cap on the number of times a refresh token can be used within its lifetime — it remains valid until it expires or is rotated out.

For a comparison of all token default lifetimes, see Configure token and session expiry.

Token security recommendations

Link to this section

Token security can be approached in a number of ways. We recommend at least covering the basics of:

  • keeping the number of refresh tokens within a manageable limit to keep credentials safe and secure.
  • storing refresh tokens securely in the back-end of your application because they essentially allow a user to remain authenticated forever.
  • employing refresh token rotation and automatic reuse detection for added security.