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.

Need help integrating this into your project?

Our team of expert developers can help you build your custom application from scratch.

Hire DigitalCodeLabs