Access Management 7.3.2

Refresh tokens

Refresh tokens (RFC 6749) let an OAuth 2.0 client get a new access token with identical or narrower scopes than the original and without involving the resource owner. AM can issue refresh tokens for all OAuth 2.0/OpenID Connect grant flows except the implicit and client credentials flows.

About refresh tokens

Access tokens have short lifetimes because they grant any bearer access to a protected resource.

Refresh tokens give an OAuth 2.0 client something to exchange for a new access token. The exchange does not involve resource owner interaction. Refresh tokens are useful when an OAuth 2.0 client needs:

  • Long term access to a protected resource.

  • Access when the resource owner is unavailable.

  • Multiple operations to access the same protected resources, and the resource owner should only have to grant consent once.

Refresh tokens are safer than long-lived access tokens. To exchange a refresh token for an access token, the OAuth 2.0 client must authenticate. A malicious user with a compromised access token has access to the protected resource. A user with a refresh token must also have the client ID and client secret to obtain an access token.

Settings for refresh tokens

Refresh tokens configuration settings include:

Token issuance

By default, AM issues a refresh token whenever it issues an access token. When AM issues a new refresh token, it expires the old refresh token.

You can disable refresh token issuance in the AM admin UI OAuth 2.0 provider configuration under Realms > Realm Name > Services > OAuth2 Provider > Core with:

Issue Refresh Tokens

Whether to issue refresh tokens with access tokens.

Issue Refresh Tokens on Refreshing Access Tokens

Whether to issue new refresh tokens when exchanging a refresh token for an access token.

Token lifetime

Refresh tokens are long-lived by default.

You set the lifetime of refresh tokens in the OAuth 2.0 provider settings or for individual OAuth 2.0 clients. By default, AM relies on the OAuth 2.0 provider configuration.

In the AM admin UI, you can change the setting per client under Realm > Realm Name > Applications > OAuth 2.0 > Clients > Client ID > Refresh Token Lifetime.

For details, refer to the OAuth2 provider and the advanced client settings.

Grace period

The grace period specifies how long an OAuth 2.0 client can replay requests to exchange a refresh token for an access token if there’s a network problem or other transient issue.

For details, refer to the OAuth2.0 provider or OAuth 2.0 client settings.

Clients can revoke refresh tokens using the /oauth2/token/revoke endpoint. The next time the client requires access to protected resources, it must involve the resource owner.

Demonstrate refresh tokens

Demonstrate using refresh tokens with the following steps:

OAuth 2.0 client

  1. Create a confidential OAuth 2.0 client account.

  2. In the AM admin UI, select Realm > Realm Name > Applications > OAuth 2.0 > Clients and click + Add Client.

  3. Create a new confidential client with the following credentials:

    Client ID

    myClient

    Client Secret

    forgerock

    Redirection URIs

    https://www.example.com:443/callback

Resource owner

An OAuth 2.0 client requests the access token on behalf of a resource owner. Create the OAuth 2.0 resource owner account:

  1. In the AM admin UI, select Identities > + Add Identity and fill the required fields.

  2. Record the username and password.

Get an access token

  1. Authenticate as the resource owner:

    curl \
    --request POST \
    --header 'Content-Type: application/json' \
    --header 'X-OpenAM-Username: <resource-owner-username>' \
    --header 'X-OpenAM-Password: <resource-owner-password>' \
    --header 'Accept-API-Version: resource=2.0, protocol=1.0' \
    'https://openam.example.com:8443/openam/json/realms/root/realms/alpha/authenticate'
    {"tokenId":"<resource-owner-tokenId>","successUrl":"/enduser/?realm=/alpha","realm":"/alpha"}
  2. Request the authorization code as the client:

    curl \
    --dump-header - \
    --request POST \
    --Cookie 'iPlanetDirectoryPro=<resource-owner-tokenId>' \
    --data 'scope=openid' \
    --data 'response_type=code' \
    --data 'client_id=myClient' \
    --data 'csrf=<resource-owner-tokenId>' \
    --data 'redirect_uri=https://www.example.com:443/callback' \
    --data 'state=abc123' \
    --data 'decision=allow' \
    'https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/authorize'
    …​
    location: https://www.example.com:443/callback?code=<authorization-code>&iss=https%3A%2F%2F…​
    …​
  3. Exchange the authorization code for an access token as the client:

    curl \
    --request POST \
    --user 'myClient:forgerock' \
    --data 'grant_type=authorization_code' \
    --data 'code=<authorization-code>' \
    --data 'redirect_uri=https://www.example.com:443/callback' \
    'https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/access_token'
    {
      "access_token": "<access-token>",
      "refresh_token": "<refresh-token>",
      "scope": "openid",
      "id_token": "<id-token>",
      "token_type": "Bearer",
      "expires_in": 3599
    }

Refresh an access token

Exchange the refresh token for a new access token:

$ curl \
--request POST \
--data "grant_type=refresh_token" \
--data "refresh_token=<refresh-token>" \
--data "client_id=myClient" \
--data "client_secret=forgerock" \
--data "scope=openid" \
"https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/access_token"
{
  "access_token": "<new-access-token>",
  "refresh_token": "<new-refresh-token>",
  "scope": "openid",
  "id_token": "<id-token>",
  "token_type": "Bearer",
  "expires_in": 3599
}
  • The scope parameter is optional. By default, AM issues an access token with the same scopes as the original token.

  • AM has issued a new refresh token; the original refresh token is now inactive.