โ All flows
Refresh Token Flow
For getting a new access token without logging in again
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.
See it step by step
๐ฅ๏ธ
AppAn app you already signed in to๐
Login serverChecks who you are and hands out tokens๐ฆ
APIHolds the data the app wantsExpired token
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.
When to use this flow
- Long-lived sessions โ Keep users signed in for days or weeks
- Background sync โ Apps that call an API while the user is away
- Client Credentials โ That flow has no user, so just request a new token
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
Code example
Refresh Token example
javascript
// 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? }
}