Table of Contents

Using Refresh Tokens

This chapter explains how to use refresh tokens in TMS Sphinx to allow client applications to obtain new access tokens without requiring user re-authentication.

What are Refresh Tokens?

Refresh tokens are long-lived credentials that can be exchanged for new access tokens without requiring the user to log in again. They are particularly useful for:

  • Native applications that need to maintain long-term access
  • Web applications that need to access APIs on behalf of users over extended periods
  • Any scenario where access tokens expire but you want to maintain authorization

Access tokens typically have a short lifetime (e.g., 1 hour) for security reasons. When an access token expires, instead of forcing the user to log in again, the client application can use a refresh token to obtain a new access token silently.

Enabling Refresh Tokens

To enable refresh tokens in your Sphinx server, you need to:

  1. Allow the refresh_token grant type for your client application by adding gtRefreshToken to the TSphinxClient​App.​Allowed​Grant​Types property.

  2. Request the offline_access scope when initiating the authorization flow. Sphinx only issues refresh tokens when this scope is present in the authorization request.

Here's an example of configuring a client application to support refresh tokens:

  Client := SphinxConfig1.Clients.Add;
  Client.ClientId := 'myclient';
  Client.DisplayName := 'My Application';
  Client.RequireClientSecret := False;
  Client.AllowedGrantTypes := [TGrantType.gtAuthorizationCode, TGrantType.gtRefreshToken];
  Client.ValidScopes.Add('openid');
  Client.ValidScopes.Add('email');
  Client.ValidScopes.Add('offline_access');  // Required for refresh tokens

Obtaining a Refresh Token

Refresh tokens are only issued during the authorization code flow. When your client application exchanges an authorization code for tokens, and the offline_access scope was requested, the token endpoint response will include a refresh_token in addition to the access_token and (if openid scope was requested) id_token:

{
  "access_token": "eyJhbGc...",
  "id_token": "eyJhbGc...",
  "refresh_token": "rt_abc123...",
  "token_type": "Bearer",
  "expires_in": 3600
}

Important security considerations:

  • Refresh tokens are only issued for authorization code flow. They are never issued for implicit flow or client credentials flow.
  • The offline_access scope must be included in the initial authorization request.
  • Refresh tokens are bound to the specific client application that requested them.

Using a Refresh Token

To obtain a new access token using a refresh token, send a POST request to the token endpoint (<base_url>/oauth/token) with the following parameters:

  • grant_type: Must be refresh_token
  • refresh_token: The refresh token value received previously
  • client_id: The client application identifier
  • scope (optional): Space-separated list of scopes. Can only reduce scopes, not expand them.

If client authentication is required (TSphinxClient​App.​Require​Client​Secret is True), you must also provide the client credentials.

Example request:

POST /oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=refresh_token&
refresh_token=rt_abc123...&
client_id=myclient

The response will include a new access token and, if the openid scope is present, a new id_token:

{
  "access_token": "eyJhbGc...",
  "id_token": "eyJhbGc...",
  "refresh_token": "rt_xyz789...",
  "token_type": "Bearer",
  "expires_in": 3600
}

Refresh Token Rotation

For enhanced security, TMS Sphinx implements refresh token rotation. This means:

  • Each time a refresh token is used, it is marked as consumed and invalidated
  • A new refresh token is issued in the response
  • The old refresh token cannot be used again

This rotation mechanism helps detect token theft. If a refresh token is used more than once, it indicates either:

  • The token was stolen and is being used by an attacker
  • The client application has a bug where it's reusing old tokens

In either case, when a consumed refresh token is reused, Sphinx will:

  • Reject the token request with an invalid_grant error
  • Return an error indicating the token was already consumed

Best Practice: Always store the most recent refresh token and discard the old one after obtaining a new token.

Scope Reduction

When using a refresh token, you can optionally reduce the scopes in the new access token by providing a scope parameter that is a subset of the original scopes. However, you cannot request additional scopes beyond what was originally granted.

Example:

// Original authorization requested: openid email profile
// Refresh token request can use: openid email (reduced)
// Refresh token request CANNOT use: openid email profile customers (expanded)

If you don't provide a scope parameter, the new access token will have the same scopes as the original authorization.

Token Lifetime

Refresh tokens have a default lifetime of 30 days. You can customize this by changing the value of property TSphinxClient​App.​Refresh​Token​Lifetime method in your client facade, or by setting it in your custom implementation if you're not using the built-in configuration.

Access tokens issued via refresh token grant will have the same lifetime as those issued via authorization code grant, as configured in TSphinxClient​App.​Access​Token​Lifetime.

Security Recommendations

When implementing refresh tokens in your application:

  1. Store refresh tokens securely: They are long-lived credentials and should be treated with the same care as passwords.

  2. Use HTTPS: Always transmit refresh tokens over HTTPS to prevent interception.

  3. Implement token rotation: Sphinx implements this by default - always use the new refresh token and discard the old one.

  4. Request minimum necessary scopes: Only request the scopes your application actually needs.

Error Handling

When using refresh tokens, you may encounter these common errors:

  • invalid_grant: The refresh token is invalid, expired, revoked, or has already been used
  • invalid_scope: The requested scopes are not a subset of the original scopes
  • unauthorized_client: The client is not authorized to use the refresh_token grant type
  • invalid_client: Client authentication failed

Your application should handle these errors gracefully, typically by requiring the user to log in again to obtain a new refresh token.