Skip to main content

Refresh tokens

Step 4: Refresh tokenโ€‹

To get a refresh token, you must include the offline_access scope when you initiate an authentication request through the authorize endpoint. To refresh your access token, using the Refresh Token you already got during authorization, make a POST request to the token endpoint. Read more here.

Keep the session alive by using the refresh tokenโ€‹

Whenever an access_token is required to access a protected resource, a client may use a refresh_token to get a new Access Token issued by the Authentication Server. Although access_token can be renewed at any time using refresh_tokens, they should be renewed when old ones have expired, or when getting access to a new resource for the first time. When the access_token expires, the refresh_token can be used to obtain a fresh access_token with the same permissions, without further involvement from a user. When the access_token expires, you can use the refresh_token to get a new access_token by using the token endpoint as shown below:

Sample request:

POST https://api.sandbox.mobilepay.dk/merchant-authentication-openidconnect/connect/token
Content-Type: application/x-www-form-urlencoded
Host: api.sandbox.mobilepay.dk
Body:
grant_type=refresh_token
refresh_token=01cab0f861cdb89c326604cae408ae6e8c57e72c70c84143b93e04bbecb8c748
client_id=some.test.client.received.in.zipfile
client_secret=mysecret.received.in.zip.file

Explanation of parameters:

ParameterDescriptionValueRequired
grant_typeA way to specify how the client will interact with the serverMust be set to "refresh_token"Yes
refresh_tokenThe refresh token to be usedThe existing refresh tokenYes
client_idThe client_id that you received by zip fileThe client_id given in the zip fileYes
client_secretThe client_secret that you received by zip file.The client_secret given in the zip file.Yes

Refresh_tokens are long-lived. This means when a client gets one from a server, this token must be stored securely to keep it from being used by potential attackers. Therefore, it is not safe to store them in the browser. If a refresh_token is leaked, it may be used to obtain new access_tokens (and access protected resources) until it is blacklisted or invalidated. To get a refresh_token, you must include the offline_access scope when you initiate an authorization request through the authorize endpoint.

If the refresh token is valid, then you get back a new access token:

{
"id-token" : "MIOf-U1zQbyfa3[...]MUfJHhvnUqIut9ClH0xjlDXGJAyqo"
"access_token": "eyJhbGciOiJ[...]K1Sun9bA",
"token_type": "Bearer",
"expires_in": 300,
"token_type": "Bearer",
"refresh_token": "MIOf-U1zQbyfa3[...]MUfJHhvnUqIut9ClH0xjlDXGJAyqo"
}

Invalid tokensโ€‹

If you make an API call using an invalid token, you will receive a 401 Unauthorized response back from the server. A token could be invalid and in need of regeneration if:

  • It has expired.
  • The user has revoked the permission they initially granted
  • You have changed the (scope) your application is requesting.
  • A subsequent OpenID Connect flow that generated a new access token. The previous token will be invalidated if running Single Use tokens. You should only ask for a new token if the access_token has expired or you want to refresh the claims contained in the ID Token. For example, it's a bad practice to call the endpoint to get a new access_token every time you call an API, if you already have an active access_token.

Refresh tokens can expire but are long-lived. They are subject to strict storage requirements to ensure they are not leaked. Since a predictable expiry time is not the only contributing factor to token invalidation, it is very important that you code your applications to properly handle an encounter with a 401 error by redirecting the user back to the start of the authorization workflow.

PKCE / Code Challengeโ€‹

For more information on the PKCE protocol and the security considerations, see IETF RFC 7636.

MobilePay supports the Proof Key for Code Exchange protocol to make the authorization flow more secure. A unique code verifier is created for every authorization request, and its transformed value, called "code_challenge", is sent to the authorization server to obtain the authorization code. Example: C# example. Note that it is hidden in the framework. This line calls a IdentityModel feature which automatically uses PKCE.

Terminology:

  • code verifier: A cryptographically random string that is used to correlate the authorization request to the token request. The client creates a one-time secret (code verifier) that is used to generate a code challenge
  • code challenge: A challenge derived from the code verifier that is sent in the authorization request, to be verified against later. Code challenge is also referred to as the code that you generated, and made cryptographically secure and sent to us in /authorize endpoint property code challenge.

PKCE Parameters

  • code_verifier: A random value of 43-128 characters. Created by the client. Stored on the server upon an authorization request. The recommended value is a 32-octet sequence that is base64url-encoded to create a 43-octet URL safe string.
  • code_challenge_method: The code challenge method used to generate the code challenge value. S256 โ€“ SHA256 encoding is performed: code_challenge=base64url(sha256(code_verifier))
  • code_challenge: Value based on the code_verifier and the code_challenge_method.
private string CreateCodeChallenge()
{
_codeVerifier = RandomNumberGenerator.CreateUniqueId();
var sha256 = HashAlgorithmProvider.OpenAlgorithm(HashAlgorithm.Sha256);
var challengeBuffer = sha256.HashData(
CryptographicBuffer.CreateFromByteArray(Encoding.UTF8.GetBytes(_codeVerifier)));
byte[] challengeBytes;
CryptographicBuffer.CopyToByteArray(challengeBuffer, out challengeBytes);
return Base64Url.Encode(challengeBytes);
}

Here is how IdentityServer do the validation:

  • var codeVerifierBytes = Encoding.ASCII.GetBytes(codeVerifier);
  • var hashedBytes = codeVerifierBytes.Sha256();
  • var transformedCodeVerifier = Base64Url.Encode(hashedBytes);
  • return TimeConstantComparer.IsEqual(transformedCodeVerifier.Sha256(), codeChallenge);

If you get an error that the code challenge is either too short or too long, please update the value of code_challenge to meet the requirements and try again. Regarding code_verifier, it has the same length requirements as code challenge.

  • CodeChallengeMinLength = 43
  • CodeChallengeMaxLength = 128

The method for calculating code_challenge is base64urlencoder(Sha256(code_verifier)) when challenge method is S256.

How Can Access be Revoked?โ€‹

It might be useful for you to know, what happens in theory, if your merchant decides to revoke the consent.

  • The merchant can revoke the consent for the Integrator. It's done from the MobilePay Portal, specifically the menu item Settings โ†’ Integration. The Tab is empty if no consent is granted. The merchant needs to have a SuperManager role in the MobilePay Portal in order to be allowed to remove the consent.
  • Subscriptions and Invoice merchants should have max one integrator. When the integrator has been granted consent, the integrator will be able to retrieve information about the Subscriptions Provider, and make API calls on behalf of the merchant.
  • Access can be revoked at any time by the merchant though, and once consent is revoked, the integrator won't be able to access merchant data with their token, nor will they be able to refresh the token.
  • If the merchant is changing from one integrator to another, the consent process should be coordinated between the merchant and the new integrator. The merchant will need to go through the authorize process again.

Best Practiceโ€‹

  • Focus on having logic, that ensures that when you use access token, then you also check if it is expired. The logic should tell you, for how long the access token is valid, so that you can know, when it is time to refresh the access token, without making a call to MobilePay service and receiving 401. When it is expired, then you can use refresh_token to get a new valid access token.
  • The refresh_token are subject to strict storage requirements to ensure that they are not leaked.
  • Although access token can be renewed at any time using refresh_token, they should only be renewed when old ones have expired, or when getting access to a new resource for the first time.
note

You should only ask for a new token if the access_token has expired or you want to refresh the claims contained in the ID Token. For example, it's a bad practice to call the endpoint to get a new access_token every time you call an API. Please avoid hitting the rate limits in that will throttle the amount of requests to this endpoint that can be executed using the same token from the same IP.

The long-lived refresh_tokens must never be exposed. If you have any suspicion that they might be, you should contact us at developer@vippsmobilepay.com or the merchant in question, so the token can be revoked.

Refresh_tokens must be stored securely by an application since they allow a user to remain authenticated essentially forever.