OAuth

OAuth Refresh Token Expired — How to Handle It

A refresh token expires silently — your app keeps working until the next API call fails with invalid_grant or token_expired. Handle it gracefully: catch the error, clear tokens, redirect to login.

Why refresh tokens expire

Catch expiry in your token refresh logic

async function getValidToken() {
  const stored = getStoredTokens();
  if (!stored) return promptLogin();

  // Check if access token is still valid
  if (Date.now() < stored.expires_at - 60000) {
    return stored.access_token;
  }

  // Try to refresh
  try {
    const fresh = await refreshAccessToken(stored.refresh_token);
    storeTokens(fresh);
    return fresh.access_token;
  } catch (err) {
    if (err.error === 'invalid_grant' || err.status === 401) {
      clearTokens();
      promptLogin(); // redirect to /login
      return null;
    }
    throw err; // re-throw other errors
  }
}

Token lifetimes by provider

ProviderAccess tokenRefresh tokenIdle expiry
Auth024h (configurable)No expiry by default30 days idle
AWS Cognito1h30 days30 days from issue
Google1hNo expiry6 months unused
Microsoft/Azure1h90 days90 days idle
Okta1hConfigurableConfigurable

Silent re-authentication for SPAs

If you want to avoid visible login prompts, use silent auth — an invisible iframe that attempts to get a new token using a session cookie:

// Auth0 example — checkSession
auth0.checkSession({}, function(err, result) {
  if (err) {
    // Session expired — full login required
    auth0.authorize();
  } else {
    // New tokens in result
    updateTokens(result);
  }
});
Debug your OAuth error live → OAuthFixer