Refresh Tokens

On this page

Issuing and Using Refresh Tokens

Refresh tokens allow the client to obtain more access tokens without needing the user to re-authenticate. The refresh tokens is a longer lived token that may have a lifetime up to many years.


This tutorial builds on the configuration setup described in the steps First Configuration and Configure an Authenticator under the menu Getting Started. If you have not gone through those steps yet, you can visit the guides by clicking on the links.

You may run this tutorial on a custom setup also, but keep in mind that names and URLs may be different, as well as the capabilities configured in the profiles.

You will also need a client capable of refresh. If you follow the code flow tutorial, you will have obtained a refresh token.


Token Endpoint

Refresh Flow Diagram
  1. The client sends the refresh token along with credentials to the token endpoint
  2. The server responds with new a new access token and a new refresh token

This is a POST request to the token endpoint. The client uses HTTP basic authentication to identify itself in this example; other mechanisms are also possible (e.g., sending the client ID and secret in the body, using the JWT assertion grant type, mutual TLS, etc.). The payload is URL encoded. The contents of which include at least grant_type and refresh_token. The grant_type parameter should always have a value of refresh_token in this flow and the value of the refresh_token parameter should be the actual refresh token obtained by the client after some other flow, like the code flow, which included a refresh token.

Setup in Curity

No additional setup is needed from the previous steps.

Making Requests with the Client

With the default configuration from the initial setup, use the code flow to obtain an access token and a refresh token. Take the refresh token and form the following request:

POST /oauth/v2/oauth-token HTTP/1.1
Host: localhost
Content-Type: application/x-www-form-urlencoded

The same request using cURL:

curl -X POST \
https://localhost:8443/oauth/v2/oauth-token \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'grant_type=refresh_token&client_id=www&client_secret=Secr3t!&refresh_token=THE_REFRESH_TOKEN'

The response will be either an success or error; both will be an object encoded as JSON. A successful result will produce a response like this:

"access_token": "79ed4e85-954d-4044-9362-99ac9695d7e0",
"refresh_token": "ff8cfad8-9888-44c7-afb2-8c597cf96037",
"scope" : "",
"token_type": "bearer",
"expires_in": 300

In such a case, the response will have access_token, refresh_token, scope, token_type, and expires_in fields.1

Note how the refresh_token in the response is not the same as the one that was sent. This is Curity's default behavior -- it creates a new refresh token with each redemption of an existing refresh token. This means that the client will have to store the refresh token from each response and use that in the next request. This is an extra security measure that is in place but can be relaxed.

Controlling Refresh Tokens

Reusing refresh tokens

To reuse the same refresh token, in the admin UI:

Visit the Profiles screen and click the Token Service. On the General page scroll down to Reuse Refresh Tokens

Reusing a Refresh Token

If you toggle this on, the refresh token presented in the request will be the same one that is echoed in the response. This will alleviate the client from having to update its stored refresh token and allow it to use the same one with each request.

Disabling Access Token Issuance

There are times when a client should not be issued a refresh token even if it performs a flow that allows for one. This is often done to manage the risk associated with a distrusted client. To disable the issuance of a refresh token in the admin UI, find the OAuth profile and client which should not be issued a refresh token. Then, toggle off the control labeled Refresh Token Time to Live.

Changing Scope of Access Token on Refresh

One of the request parameters that can sent is scope. This indicates to the OAuth server the scope of access that the refreshed token should have. If excluded, the scope will not change. If this parameter is included though, it should be a space-separated value, as is normal for indicating scope in OAuth. As an example, suppose the client performed the code flow and got an access token with the scope shown in the following listing:

"access_token": "aebc4798-9a2c-4c4a-a39f-c31eeb6409e6",
"refresh_token": "4dc21b27-b1ef-4e68-98b4-055d215fa5e2",
"scope": "read openid profile"

With this refresh token, the client could refresh the access token with lesser scope by making a request like this:

POST /token HTTP/1.1
Host: localhost:8443
Content-Type: application/x-www-form-urlencoded
Authorization: basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

The response shows that the new, refreshed access token has less scope than the original:

"access_token": "2a44b422-f2c2-4fd8-bfcb-1ea6140cea87",
"refresh_token": "daa38700-ba96-4ef1-8b30-5cb3527aae19",
"scope": "read profile"

The scope was originally read openid profile and after refresh the access was reduced to read profile (i.e., the access_token now only has read profile scope and any new tokens obtained using the refresh token daa38700-ba96-4ef1-8b30-5cb3527aae19 will have the same, reduced scope). Note that increasing the scope of access cannot be done in this way unless first reduced and increased back to the original scope.

Changing scope

It is only possible to remove the scopes during refresh, not add new scopes.


  1. Some of these are recommended or optional in the OAuth specification, but Curity always includes them.

Join our Newsletter

Get the latest on identity management, API Security and authentication straight to your inbox.

Start Free Trial

Try the Curity Identity Server for Free. Get up and running in 10 minutes.

Start Free Trial