Skip to main content

Handle Token Expiration

Implement automatic token refresh to prevent authentication failures in long-running applications.

What You'll Need

Understanding Token Expiration

See Authentication Concepts to understand why tokens expire and the trade-offs between reactive vs. proactive refresh strategies.

Reactive Refresh

Detect 401 errors and refresh the token on demand:

const makeAuthenticatedRequest = async (url, options = {}) => {
const makeRequest = async (token) => {
const response = await fetch(url, {
...options,
headers: {
...options.headers,
Authorization: `Bearer ${token}`,
},
});

if (response.status === 401) {
// Token expired, return null to trigger refresh
return null;
}

return response;
};

// Try with current token
let response = await makeRequest(currentToken);

// If unauthorized, refresh token and retry
if (response === null) {
console.log("Token expired, refreshing...");
currentToken = await refreshToken();
response = await makeRequest(currentToken);
}

return response;
};

const refreshToken = async () => {
const response = await fetch("https://partner.api.sasha.eu/oauth/token", {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
Authorization: `Basic ${btoa(`${CLIENT_ID}:${CLIENT_SECRET}`)}`,
},
body: "grant_type=client_credentials",
});

const data = await response.json();
return data.access_token;
};

// Usage
const response = await makeAuthenticatedRequest(
"https://partner.api.sasha.eu/jobs/job_123"
);

Proactive Refresh

Check token expiration before each request and refresh if needed:

let token = null;
let expiresAt = null;

const getToken = async () => {
// Refresh if no token or expires in less than 5 minutes
if (!token || Date.now() > expiresAt - 5 * 60 * 1000) {
const response = await fetch("https://partner.api.sasha.eu/oauth/token", {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
Authorization: `Basic ${btoa(`${CLIENT_ID}:${CLIENT_SECRET}`)}`,
},
body: "grant_type=client_credentials",
});

const data = await response.json();
token = data.access_token;
expiresAt = Date.now() + data.expires_in * 1000;
}

return token;
};

// Usage
const token = await getToken();
const response = await fetch("https://partner.api.sasha.eu/jobs/job_123", {
headers: { Authorization: `Bearer ${token}` }
});

Production Considerations

For production applications:

  • Retry failed refreshes - Use a retry library with exponential backoff
  • Prevent concurrent refreshes - Store a single refresh promise and await it across multiple requests
  • Secure credentials - Use environment variables or secret management systems, never hardcode

See Also