Stitch SSO

4.4. Token Lifetimes

OAuth 2.0 recommends using a combination of access tokens and refresh tokens to grant tokens. When the service issues the access token, a refresh token is also returned in that response. When the access token expires, the application can use the refresh token to obtain a new access token.

User Token Lifetime

User Access tokens are configured to have a 15 minute lifetime by default. The token expiry is indicated by the expires_in field (displayed in seconds) which is returned when successfully retrieving a token. You can refresh your token before the indicated time to ensure you always have a fresh token.

Queries with an expired token will yield the following response:

2 "errors": [
3 {
4 "message": "UNAUTHENTICATED: Token is expired or malformed"
5 }
6 ],
7 "extensions": {
9 }

Client Token Lifetime

⚠Refresh token expiry and lifetime

Refresh tokens have a sliding expiry of 365 days. Exact values for these durations can be found in your client credentials JSON.


  • A refresh token can only be used once, the result of the token call will include a new access and refresh token.
  • Requesting a new token also creates a new banking session. Depending on the bank, this means that it may trigger a login notification, or bring up a second-factor authentication prompt. The latter case will not interrupt the process of retrieving a new access token, but follow-up requests to the API may require user interaction.
  • A refresh token is only returned if it is explicitly requested by passing in offline_access as the scope.
  • Your client_assertion needs to passed in when making a request to the token endpoint

Refreshing the Token Using cURL

This example bash script uses cURL to retrieve the user access and refresh token.

You'll need to replace the clientId and refreshToken with the appropriate values.

This request if correctly formed, will return a JSON payload with the token

3clientAssertion='<your client assertion>'
6curl -X POST \
7 \
8 -H 'Content-Type: application/x-www-form-urlencoded' \
9 -d "grant_type=refresh_token&client_id=$clientId&refresh_token=$refreshToken&client_assertion=$clientAssertion&client_assertion_type=$clientAssertionType"

Refreshing the Token Using JavaScript and the Fetch API

1async function retrieveTokenUsingRefreshToken(clientId, refreshToken, clientAssertion) {
2 const body = {
3 grant_type: 'refresh_token',
4 client_id: clientId,
5 refresh_token: refreshToken,
6 client_assertion: clientAssertion,
7 client_assertion_type: 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer'
8 }
9 const bodyString = Object.entries(body).map(([k, v]) => `${k}=${encodeURIComponent(v)}`).join('&');
11 const response = await fetch('', {
12 method: 'post',
13 headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
14 body: bodyString,
15 });
17 const responseBody = await response.json();
18 console.log('Tokens: ', responseBody);
19 return responseBody;

Refreshing the Token Using Postman

Download the following Postman collection, and import it into Postman:

Getting Started.postman_collection.json

The second request in the collection is "Refresh Token". Replace the entries in the Body tab with the appropriate values and click send. The request if correctly formed will return a JSON payload with the token.

Response Body

A typical response body returned from the refresh token endpoint will look like the following:

2 "id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6Im9TbWt2RmhqVWNia0I4MjRrek5fWkEiLCJ0eXAiOiJKV1QifQ.eyJuYmYiOjE1NzYyMjM1MjEsImV4cCI6MTU3NjIyMzgyMSwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo1MDAxIiwiYXVkIjoiZjVjYzk0ZWUtZTk1MS00MGQzLWEzMWUtNzk0NjU5ODA2MjMwIiwiaWF0IjoxNTc2MjIzNTIxLCJhdF9oYXNoIjoiZmNaeVN5MnBSYlBKMnUwSW1OWUNlQSIsInN1YiI6InVzZXIvZjVjYzk0ZWUtZTk1MS00MGQzLWEzMWUtNzk0NjU5ODA2MjMwL2ZuYi9kY2QxMzczNy0xMTc4LTRhMTUtOGQwYy00MGE0YzBiMmU1ODkiLCJhdXRoX3RpbWUiOjE1NzYyMjM0MTAsImlkcCI6ImxvY2FsIiwiYW1yIjpbInB3ZCJdfQ.ISRH-W9SgDJmTAcAFcrRggDb4Ym-0xmZ-Lbv1gfceUr00wjV8eiZcf_EE1Ca9t7fXgeFMsWTclc-ZxX5szWQAvLaqGdFo-3IlKuPgmftTmfTAb1y7_RWNIjuTjDtJvWzLnf1WGO62Ki_uz2kB3VicneDEzSx5YJRGJz6tZ5LBvrCAj_WQ4mpodNEawuC1komJMhROVtLdM7tAAE7BPhF3Ks0v-SiAzh8QtxBAs8l-13dcmgeXrgCiND5i520QtuOhdVV7DNQ1BvP8SGxMhmuA4V5s3V2BDTIUkR8_IsMq6OE-BxjXfflM1QGlV7_tRs52w5CLxfuFNX_sVIHNIWQzw",
3 "access_token": "ey-K-qPC5Cs0ERd0eDuLJI636rLEnd3Kwi5L1NrVNJY",
4 "expires_in": 899,
5 "token_type": "Bearer",
6 "refresh_token": "Wce1_ujqCD8B-BHAzrV-1S_3WFsHSxXKWUHGtfJvZvc",
7 "scope": "openid accounts transactions offline_access"
Refresh Token Response Body Parameters
id_tokenSame as the one returned from the authorize call. id_token contains user profile information and is JWT encoded
access_tokenThe token needed to query the Stitch API
expires_inThe number of seconds until the token expires
refresh_tokenThe next refresh_token which needs to be stored for later use
scopeThe scopes that were granted by the user

Attempting to refresh the access token with an expired or malformed refresh token will yield the following response:

2 "error": "invalid_grant"