Refresh Token Flow
For getting a new access token without logging in again
- Who's involved
- Your app, auth server
- Best for
- Staying signed in
- Difficulty
- Easy
1Overview
How it works
A refresh token is a long-lived credential the app receives along with its access token. When the access token expires, the app sends the refresh token to the token endpoint (the login server's address for issuing tokens) and gets a new access token.
The result: the user does not have to sign in again.
2Use cases
When would you use this?
Staying signed in
A mobile app keeps you logged in for weeks. It quietly gets a new access token each time the old one expires.
Background sync
A calendar app updates your events overnight while you are asleep.
Long sessions on the web
A web app with a server avoids sending users back to the login page every hour.
Not the right fit? No user involved? Client Credentials has no refresh token. Just ask for a new access token.
3Interactive
Try it step by step
See it step by step
Step 1 of 4
The token has expired
The app asks the API for your data, but the API says the access token has expired.
4Practical advice
Do this, avoid that
Good practices
- Store refresh tokens securely โ They last a long time. Keep them on the server, or in secure storage on a device
- Save the new refresh token โ Many servers rotate them, so the old one stops working after one use
- Request only what you need โ A refreshed token can only carry scopes the user already approved
- Refresh only when needed โ Wait for expiry (or a
401) rather than refreshing on every request
Common mistakes
- Putting refresh tokens in local storage โ Any script on the page could steal them
- Sending a refresh token to the API โ It belongs only at the token endpoint
- Ignoring errors โ If refresh fails with
invalid_grant, send the user through login again - Logging tokens โ Never write them to logs or URLs
5Code
Code example
Show the code
// Refresh an expired access token
async function refreshAccessToken(refreshToken) {
const res = await fetch('https://auth.provider.com/oauth/token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'refresh_token',
refresh_token: refreshToken,
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET, // server-side apps only
}),
});
if (!res.ok) throw new Error('Refresh failed, ask the user to log in again');
return res.json(); // { access_token, expires_in, refresh_token? }
}