Table Of Contents
Problem
You need to authenticate API requests by adding Bearer tokens to the Authorization header, handle token refresh, and manage authentication across different HTTP clients.
Solution
// 1. Basic Bearer Token with fetch()
async function fetchWithBearerToken(url, token, options = {}) {
try {
const response = await fetch(url, {
...options,
headers: {
'Authorization': `Bearer ${token}`,
'Accept': 'application/json',
'Content-Type': 'application/json',
...options.headers
}
});
if (response.status === 401) {
throw new Error('Unauthorized - invalid or expired token');
}
if (!response.ok) {
throw new Error(`Request failed: ${response.status} ${response.statusText}`);
}
return await response.json();
} catch (error) {
console.error('Bearer token request error:', error.message);
throw error;
}
}
// 2. Axios with Bearer Token
const axios = require('axios');
// Create axios instance with default Bearer token
function createAuthenticatedAxios(token) {
return axios.create({
baseURL: 'https://api.example.com',
timeout: 10000,
headers: {
'Authorization': `Bearer ${token}`,
'Accept': 'application/json',
'Content-Type': 'application/json'
}
});
}
// Using the authenticated axios instance
async function useAuthenticatedAxios(token) {
try {
const client = createAuthenticatedAxios(token);
const response = await client.get('/user/profile');
return response.data;
} catch (error) {
if (error.response?.status === 401) {
throw new Error('Token expired or invalid');
}
throw error;
}
}
// 3. Token Management Class
class TokenManager {
constructor(baseURL, initialToken = null) {
this.baseURL = baseURL;
this.token = initialToken;
this.refreshToken = null;
this.tokenExpiry = null;
}
setToken(token, refreshToken = null, expiresIn = null) {
this.token = token;
this.refreshToken = refreshToken;
if (expiresIn) {
this.tokenExpiry = new Date(Date.now() + expiresIn * 1000);
}
}
isTokenExpired() {
if (!this.tokenExpiry) return false;
return new Date() >= this.tokenExpiry;
}
async refreshAccessToken() {
if (!this.refreshToken) {
throw new Error('No refresh token available');
}
try {
const response = await fetch(`${this.baseURL}/auth/refresh`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${this.refreshToken}`
}
});
if (!response.ok) {
throw new Error('Token refresh failed');
}
const data = await response.json();
this.setToken(data.access_token, data.refresh_token, data.expires_in);
return data.access_token;
} catch (error) {
console.error('Token refresh error:', error.message);
throw error;
}
}
async request(endpoint, options = {}) {
// Check if token needs refresh
if (this.isTokenExpired()) {
await this.refreshAccessToken();
}
if (!this.token) {
throw new Error('No authentication token available');
}
try {
const response = await fetch(`${this.baseURL}${endpoint}`, {
...options,
headers: {
'Authorization': `Bearer ${this.token}`,
'Accept': 'application/json',
'Content-Type': 'application/json',
...options.headers
}
});
// Handle token expiry
if (response.status === 401) {
console.log('Token expired, attempting refresh...');
await this.refreshAccessToken();
// Retry request with new token
return this.request(endpoint, options);
}
if (!response.ok) {
throw new Error(`Request failed: ${response.status}`);
}
return await response.json();
} catch (error) {
console.error('Authenticated request error:', error.message);
throw error;
}
}
async get(endpoint) {
return this.request(endpoint, { method: 'GET' });
}
async post(endpoint, data) {
return this.request(endpoint, {
method: 'POST',
body: JSON.stringify(data)
});
}
async put(endpoint, data) {
return this.request(endpoint, {
method: 'PUT',
body: JSON.stringify(data)
});
}
async delete(endpoint) {
return this.request(endpoint, { method: 'DELETE' });
}
}
// 4. Environment-based Token Loading
function getAuthToken() {
// Try different sources for token
return process.env.API_TOKEN ||
process.env.BEARER_TOKEN ||
process.env.ACCESS_TOKEN ||
null;
}
async function authenticatedRequest(url, options = {}) {
const token = getAuthToken();
if (!token) {
throw new Error('No authentication token found in environment variables');
}
return fetchWithBearerToken(url, token, options);
}
// 5. OAuth2 Flow Implementation
class OAuth2Client {
constructor(clientId, clientSecret, authURL, tokenURL) {
this.clientId = clientId;
this.clientSecret = clientSecret;
this.authURL = authURL;
this.tokenURL = tokenURL;
this.accessToken = null;
this.refreshToken = null;
}
// Exchange authorization code for tokens
async exchangeCodeForTokens(authCode, redirectUri) {
try {
const response = await fetch(this.tokenURL, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Accept': 'application/json'
},
body: new URLSearchParams({
grant_type: 'authorization_code',
client_id: this.clientId,
client_secret: this.clientSecret,
code: authCode,
redirect_uri: redirectUri
})
});
if (!response.ok) {
throw new Error(`Token exchange failed: ${response.status}`);
}
const tokens = await response.json();
this.accessToken = tokens.access_token;
this.refreshToken = tokens.refresh_token;
return tokens;
} catch (error) {
console.error('OAuth2 token exchange error:', error.message);
throw error;
}
}
async makeAuthenticatedRequest(url, options = {}) {
if (!this.accessToken) {
throw new Error('No access token available');
}
return fetchWithBearerToken(url, this.accessToken, options);
}
}
// 6. API Client with Multiple Authentication Methods
class APIClient {
constructor(baseURL) {
this.baseURL = baseURL;
this.defaultHeaders = {
'Accept': 'application/json',
'Content-Type': 'application/json'
};
}
// Bearer token authentication
setBearerToken(token) {
this.defaultHeaders['Authorization'] = `Bearer ${token}`;
}
// API key authentication
setAPIKey(apiKey, headerName = 'X-API-Key') {
this.defaultHeaders[headerName] = apiKey;
}
// Basic authentication
setBasicAuth(username, password) {
const credentials = Buffer.from(`${username}:${password}`).toString('base64');
this.defaultHeaders['Authorization'] = `Basic ${credentials}`;
}
async request(endpoint, options = {}) {
const url = `${this.baseURL}${endpoint}`;
const config = {
...options,
headers: {
...this.defaultHeaders,
...options.headers
}
};
try {
const response = await fetch(url, config);
if (!response.ok) {
const errorData = await response.text();
throw new Error(`API request failed: ${response.status} - ${errorData}`);
}
const contentType = response.headers.get('Content-Type');
if (contentType?.includes('application/json')) {
return await response.json();
} else {
return await response.text();
}
} catch (error) {
console.error('API client error:', error.message);
throw error;
}
}
}
// 7. JWT Token Validation
function isJWTExpired(token) {
try {
const payload = JSON.parse(
Buffer.from(token.split('.')[1], 'base64').toString()
);
const currentTime = Math.floor(Date.now() / 1000);
return payload.exp < currentTime;
} catch (error) {
console.error('JWT validation error:', error.message);
return true; // Assume expired if can't parse
}
}
async function requestWithJWTValidation(url, token, options = {}) {
if (isJWTExpired(token)) {
throw new Error('JWT token has expired');
}
return fetchWithBearerToken(url, token, options);
}
// 8. Concurrent Requests with Same Token
async function makeConcurrentAuthenticatedRequests(urls, token) {
try {
const requests = urls.map(url =>
fetchWithBearerToken(url, token).catch(error => ({
error: error.message,
url
}))
);
const results = await Promise.allSettled(requests);
return results.map((result, index) => ({
url: urls[index],
success: result.status === 'fulfilled' && !result.value.error,
data: result.value,
error: result.value?.error || result.reason?.message
}));
} catch (error) {
console.error('Concurrent authenticated requests error:', error.message);
throw error;
}
}
// Usage Examples
async function runBearerTokenExamples() {
console.log('=== Bearer Token Examples ===');
const sampleToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'; // Your actual token
try {
// 1. Basic bearer token request
console.log('1. Basic bearer token request...');
const basicResult = await fetchWithBearerToken(
'https://httpbin.org/bearer',
sampleToken
);
console.log('Basic request success');
// 2. Token manager
console.log('2. Token manager...');
const tokenManager = new TokenManager('https://api.example.com');
tokenManager.setToken(sampleToken);
// const userProfile = await tokenManager.get('/user/profile');
// 3. API client with bearer token
console.log('3. API client...');
const apiClient = new APIClient('https://httpbin.org');
apiClient.setBearerToken(sampleToken);
const clientResult = await apiClient.request('/bearer');
console.log('API client success');
// 4. Environment-based token
console.log('4. Environment token...');
// Set environment variable: export API_TOKEN="your-token-here"
// const envResult = await authenticatedRequest('https://httpbin.org/bearer');
console.log('All bearer token examples completed successfully');
} catch (error) {
console.error('Bearer token example error:', error.message);
}
}
// Run examples if this file is executed directly
if (require.main === module) {
runBearerTokenExamples();
}
module.exports = {
fetchWithBearerToken,
createAuthenticatedAxios,
TokenManager,
OAuth2Client,
APIClient,
isJWTExpired,
requestWithJWTValidation,
makeConcurrentAuthenticatedRequests
};
Explanation
Bearer tokens are added to the Authorization
header with the format Bearer <token>
. Always handle 401 responses which indicate invalid or expired tokens. Implement token refresh logic for long-running applications.
Use environment variables to store tokens securely, never hardcode them in source code. For complex applications, create token management classes that handle refresh logic automatically. JWT tokens can be validated client-side by checking the expiration time in the payload.
Share this article
Add Comment
No comments yet. Be the first to comment!