Refresh Token
Learn how to refresh OAuth2 access tokens to maintain continuous API access.
Overview
OAuth2 access tokens are short-lived for security reasons. When an access token expires, you can use a refresh token to obtain a new access token without requiring the user to re-authenticate. This guide explains how to implement the refresh token flow in your application.
Token Lifecycle
Token Expiration
When you receive an access token, it includes an expires_in
field
that indicates the token's lifetime in seconds. Typically, access tokens expire after 1 hour (3600 seconds).
{ "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...", "token_type": "bearer", "expires_in": 3600, "refresh_token": "def50200641f3e...", "scope": "read:user read:projects" }
You should track token expiration in your application and proactively refresh tokens before they expire to ensure uninterrupted API access.
Refresh Token Flow
To refresh an access token, make a POST request to the token endpoint with the refresh_token
grant type:
POST https://api.iiniit.com/oauth2/token Content-Type: application/x-www-form-urlencoded grant_type=refresh_token& refresh_token=REFRESH_TOKEN& client_id=YOUR_CLIENT_ID& client_secret=YOUR_CLIENT_SECRET
The response will contain a new access token and, in some cases, a new refresh token:
{ "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...", "token_type": "bearer", "expires_in": 3600, "refresh_token": "def50200a9f54e...", "scope": "read:user read:projects" }
Important: Always update your stored tokens when you receive a new refresh token. Refresh tokens may be rotated for security reasons, making previous refresh tokens invalid.
Implementing Token Refresh
When to Refresh Tokens
There are two approaches to refreshing tokens:
- Proactive Refresh: Refresh the token before it expires (e.g., when it has 5 minutes of lifetime left).
- Reactive Refresh: Refresh the token when an API request fails with a 401 Unauthorized error.
We recommend using a combination of both approaches for the best user experience.
Code Examples
JavaScript Example
// Token management class class TokenManager { constructor(clientId, clientSecret, redirectUri) { this.clientId = clientId; this.clientSecret = clientSecret; this.redirectUri = redirectUri; this.tokens = this.loadTokens(); } // Load tokens from storage loadTokens() { const tokensJson = localStorage.getItem('oauth_tokens'); if (tokensJson) { return JSON.parse(tokensJson); } return null; } // Save tokens to storage saveTokens(tokens) { localStorage.setItem('oauth_tokens', JSON.stringify({ ...tokens, created_at: Date.now() })); this.tokens = tokens; } // Check if access token is expired or about to expire isTokenExpired(bufferSeconds = 300) { if (!this.tokens) return true; const createdAt = this.tokens.created_at; const expiresIn = this.tokens.expires_in; const expiresAt = createdAt + (expiresIn * 1000); const now = Date.now(); // Return true if token is expired or will expire within the buffer time return now >= (expiresAt - (bufferSeconds * 1000)); } // Refresh the access token async refreshToken() { if (!this.tokens?.refresh_token) { throw new Error('No refresh token available'); } try { const response = await fetch('https://api.iiniit.com/oauth2/token', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, body: new URLSearchParams({ grant_type: 'refresh_token', refresh_token: this.tokens.refresh_token, client_id: this.clientId, client_secret: this.clientSecret, }), }); if (!response.ok) { throw new Error('Failed to refresh token'); } const newTokens = await response.json(); this.saveTokens(newTokens); return newTokens; } catch (error) { console.error('Error refreshing token:', error); // Clear tokens if refresh fails this.clearTokens(); throw error; } } // Get a valid access token (refreshing if necessary) async getAccessToken() { if (this.isTokenExpired()) { await this.refreshToken(); } return this.tokens.access_token; } // Clear tokens (e.g., on logout) clearTokens() { localStorage.removeItem('oauth_tokens'); this.tokens = null; } } // Usage example const tokenManager = new TokenManager( 'YOUR_CLIENT_ID', 'YOUR_CLIENT_SECRET', 'YOUR_REDIRECT_URI' ); // API client that handles token refresh class ApiClient { constructor(tokenManager) { this.tokenManager = tokenManager; this.baseUrl = 'https://api.iiniit.com/v1'; } async request(endpoint, options = {}) { try { // Get a valid access token const accessToken = await this.tokenManager.getAccessToken(); // Set up request with token const requestOptions = { ...options, headers: { ...options.headers, 'Authorization': `Bearer ${accessToken}`, 'Content-Type': 'application/json', }, }; // Make the request const response = await fetch(`${this.baseUrl}${endpoint}`, requestOptions); // Handle 401 errors (token might be invalid despite our checks) if (response.status === 401) { // Try to refresh the token await this.tokenManager.refreshToken(); // Retry the request with the new token const newAccessToken = await this.tokenManager.getAccessToken(); requestOptions.headers['Authorization'] = `Bearer ${newAccessToken}`; return fetch(`${this.baseUrl}${endpoint}`, requestOptions); } return response; } catch (error) { console.error('API request error:', error); throw error; } } // Example API methods async getProjects() { const response = await this.request('/projects'); return response.json(); } async createProject(data) { const response = await this.request('/projects', { method: 'POST', body: JSON.stringify(data), }); return response.json(); } } // Usage const apiClient = new ApiClient(tokenManager); // Example usage async function fetchProjects() { try { const projects = await apiClient.getProjects(); console.log('Projects:', projects); } catch (error) { console.error('Failed to fetch projects:', error); // Handle authentication errors if (error.message.includes('token')) { // Redirect to login window.location.href = '/login'; } } }
Best Practices
- Secure Storage: Store refresh tokens securely. For web applications, use HTTP-only cookies or secure storage mechanisms.
- Token Rotation: Always update your stored tokens when you receive a new refresh token.
- Error Handling: Implement proper error handling for token refresh failures.
- Proactive Refresh: Refresh tokens before they expire to prevent disruption to the user experience.
- Offline Access: If your application needs offline access, request the appropriate scope during authorization.
Refresh Token Expiration
Refresh tokens have a longer lifetime than access tokens, but they can still expire. The iiniit API refresh tokens typically expire after 30 days of inactivity. If a refresh token expires, the user will need to re-authenticate.
Troubleshooting
Error | Cause | Solution |
---|---|---|
invalid_grant | The refresh token is invalid or expired | Redirect the user to re-authenticate |
invalid_client | Client authentication failed | Check your client ID and client secret |
invalid_request | Missing required parameter | Check that all required parameters are included |
unauthorized_client | Client is not authorized to use refresh token grant | Check your OAuth2 application settings |
Next Steps
Now that you understand how to refresh tokens, you can: