JAVASCRIPT
Implement OAuth 2.0 Client Credentials Flow (Node.js)
Secure server-to-server API communications by implementing the OAuth 2.0 Client Credentials Grant Flow to programmatically obtain access tokens in Node.js.
const axios = require('axios');
const querystring = require('querystring'); // Built-in Node.js module
// Configuration for your OAuth provider and client
const OAUTH_TOKEN_URL = 'https://auth.example.com/oauth/token'; // Replace with your OAuth token endpoint
const CLIENT_ID = process.env.OAUTH_CLIENT_ID || 'your-client-id'; // Store securely
const CLIENT_SECRET = process.env.OAUTH_CLIENT_SECRET || 'your-client-secret'; // Store securely
const SCOPES = 'read:data write:data'; // Required scopes for the access token
let accessToken = null;
let tokenExpiresAt = 0; // Unix timestamp in seconds
/**
* Retrieves an access token using the OAuth 2.0 Client Credentials Grant Flow.
* Caches the token and refreshes it if expired.
*
* @returns {Promise<string>} The valid access token.
*/
async function getAccessToken() {
const currentTime = Math.floor(Date.now() / 1000); // Current time in seconds
if (accessToken && tokenExpiresAt > currentTime + 60) { // Refresh 60 seconds before actual expiry
console.log('Using cached access token.');
return accessToken;
}
console.log('Fetching new access token...');
try {
const response = await axios.post(
OAUTH_TOKEN_URL,
querystring.stringify({ // x-www-form-urlencoded
grant_type: 'client_credentials',
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET,
scope: SCOPES,
}),
{
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
}
);
accessToken = response.data.access_token;
tokenExpiresAt = currentTime + response.data.expires_in; // expires_in is usually in seconds
console.log('New access token obtained. Expires in', response.data.expires_in, 'seconds.');
return accessToken;
} catch (error) {
console.error('Failed to obtain OAuth access token:', error.message);
if (error.response) {
console.error('OAuth Error Response:', error.response.status, error.response.data);
}
throw new Error('Authentication failed: Could not get access token.');
}
}
/**
* Example function to make an authenticated API call.
*
* @param {string} apiEndpoint The target API endpoint.
* @returns {Promise<object>} The API response data.
*/
async function callAuthenticatedApi(apiEndpoint) {
try {
const token = await getAccessToken(); // Ensure we have a valid token
const response = await axios.get(apiEndpoint, {
headers: {
'Authorization': `Bearer ${token}`,
'Accept': 'application/json'
}
});
console.log(`API call to ${apiEndpoint} successful.`);
return response.data;
} catch (error) {
console.error(`API call to ${apiEndpoint} failed:`, error.message);
throw error;
}
}
// --- Example Usage ---
// (async () => {
// try {
// const data = await callAuthenticatedApi('https://api.example.com/protected-resource');
// console.log('Protected resource data:', data);
// // Simulate token expiry and refresh
// // accessToken = null; // Invalidate token to force refresh
// // tokenExpiresAt = 0;
// // const newData = await callAuthenticatedApi('https://api.example.com/another-protected-resource');
// // console.log('Another protected resource data:', newData);
// } catch (e) {
// console.error('Application failed:', e.message);
// }
// })();
How it works: This Node.js snippet demonstrates how to implement the OAuth 2.0 Client Credentials Grant Flow, which is ideal for server-to-server communication where no user interaction is involved. It fetches an access token from an OAuth provider using a client ID and client secret, then caches the token and refreshes it before expiration. This token is then used in the `Authorization` header for subsequent API calls to protected resources.