Skip to main content

Refresh Tokens

A refresh token is a security credential that allows client applications to obtain new access tokens without requiring users to reauthorize the application.

  • Token Lifespan: Access tokens are designed with a limited lifespan of 1 hour. Once expired, new access tokens can be obtained by providing the original refresh token, which is issued during the authorization token request response.
{
"access_token": "NgCXRK...MzYjw",
"token_type": "Bearer",
"scope": "user-read-private user-read-email",
"expires_in": 3600,
"refresh_token": "NgAagA...Um_SHo"
}

Request

To refresh an access token, you need to send a POST request with the specified parameters and headers.

Request Details

  • Method: POST
  • Endpoint: /api/token (implicit from context, typically used for token requests)

The body of the POST request must be encoded in application/x-www-form-urlencoded and include the following parameters:

Body ParameterRelevanceValue
grant_typeRequiredMust be set to refresh_token.
refresh_tokenRequiredThe refresh token obtained from the initial authorization token request.
client_idOnly required for PKCE extensionThe Client ID for your app, available from the Developer Dashboard.

The request must include the following headers:

Header ParameterRelevanceValue
Content-TypeRequiredMust be set to application/x-www-form-urlencoded.
AuthorizationOnly required for Authorization CodeA Base64-encoded string of client_id:client_secret, formatted as Authorization: Basic <base64 encoded client_id:client_secret>.

Example

The following code snippets represent two examples:

  • A client side (browser) JavaScript function to refresh tokens issued following the Authorization Code with PKCE extension flow.
  • A server side (nodeJS with express) Javascript method to refresh tokens issued under the Authorization Code flow.
const getRefreshToken = async () => {
// Refresh token that has been previously stored
const refreshToken = localStorage.getItem("refresh_token");
const url = "https://accounts.spotify.com/api/token";

const payload = {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
body: new URLSearchParams({
grant_type: "refresh_token",
refresh_token: refreshToken,
client_id: clientId, // Ensure clientId is defined in your environment
}),
};
const body = await fetch(url, payload);
const response = await body.json();

localStorage.setItem("access_token", response.access_token);
if (response.refresh_token) {
localStorage.setItem("refresh_token", response.refresh_token);
}
};
// Server Version (Node.js with request)
app.get('/refresh_token', function(req, res) {
var refresh_token = req.query.refresh_token;
var authOptions = {
url: 'https://accounts.spotify.com/api/token',
headers: {
'content-type': 'application/x-www-form-urlencoded',
'Authorization': 'Basic ' + (new Buffer.from(client_id + ':' + client_secret).toString('base64'))
},
form: {
grant_type: 'refresh_token',
refresh_token: refresh_token
},
json: true
};

request.post(authOptions, function(error, response, body) {
if (!error && response.statusCode === 200) {
var access_token = body.access_token,
refresh_token = body.refresh_token || refresh_token;
res.send({
'access_token': access_token,
'refresh_token': refresh_token
});
}
});
});

Response

If everything goes well, you'll receive a 200 OK response which is very similar to the response when issuing an access token:

{
access_token: 'BQBLuPRYBQ...BP8stIv5xr-Iwaf4l8eg',
token_type: 'Bearer',
expires_in: 3600,
refresh_token: 'AQAQfyEFmJJuCvAFh...cG_m-2KTgNDaDMQqjrOa3',
scope: 'user-read-email user-read-private'
}

The refresh token contained in the response, can be used to request new tokens. Depending on the grant used to get the initial refresh token, a refresh token might not be included in each response. When a refresh token is not returned, continue using the existing token.