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_token
s, 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:
Parameter | Description | Value | Required |
---|---|---|---|
grant_type | A way to specify how the client will interact with the server | Must be set to "refresh_token" | Yes |
refresh_token | The refresh token to be used | The existing refresh token | Yes |
client_id | The client_id that you received by zip file | The client_id given in the zip file | Yes |
client_secret | The 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 theaccess token
is valid, so that you can know, when it is time to refresh theaccess token
, without making a call to MobilePay service and receiving 401. When it is expired, then you can userefresh_token
to get a new validaccess 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 usingrefresh_token
, they should only be renewed when old ones have expired, or when getting access to a new resource for the first time.
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.