Caching Management API Access Tokens in Login Action

Overview

This article describes how to best cache access tokens and manage their renewal within the context of an action.

Applies To

  • Access Tokens
  • Token Renewal
  • Cache

Solution

The api.cache object (see post-login API object) provides functions for storing and retrieving data across executions. It’s possible to store and retrieve data such as access tokens via api.cache.set and api.cache.get respectively.

There are some limitations to keep in mind:

  • Cached items persist for a maximum of 24 hours.
  • A maximum of 20 entries can be cached per Trigger.
  • Cache keys have a maximum size of 64 bytes and values have a maximum size of 4kB.
  • The cumulative size of cached keys and their values must not exceed 8kB.
  • Actions that perform an Execution that yields back (such as a redirect) may result in subsequent actions being scheduled on a separate instance with a different cache state. This can result in cached data being inconsistent from one Action to the next.

This API can be used to store and retrieve access tokens issued within the action. In the case of the management API, it’s possible to use the Management API Client provided by the node-auth0 library. Here’s an example implementation:

const ManagementClient = require('auth0').ManagementClient;
const jwtDecode = require('jwt-decode');

export const onExecutePostLogin = async (event, api) => {
  const { domain, clientID, clientSecret } = event.secrets;
  const cacheKey = 'management-api-token';

  const getManagementClient = (token) => new ManagementClient({
    token,
    domain,
  });

  const isTokenValid = (token) => {
    if (!token) return false;
    const decoded = jwtDecode(token);
    return decoded.exp > Date.now() / 1000;
  };

  const getCachedToken = () => {
    const record = api.cache.get(cacheKey);
    return record?.value;
  };

  const setTokenInCache = async (token) => {
    const result = await api.cache.set(cacheKey, token);
    if (result.type === 'error') {
      console.log(`Failed to set the token in the cache with error code: ${result.code}`);
    } else {
      console.log('Successfully set access token in cache');
    }
  };

  const getNewToken = async () => {
    const management = new ManagementClient({
      domain,
      clientId: clientID,
      clientSecret,
    });
    return management.getAccessToken();
  };

  let token = getCachedToken();

  if (!isTokenValid(token)) {
    token = await getNewToken();
    await setTokenInCache(token);
  }

  const management = getManagementClient(token);

  // Call Management API here
  // Example: const users = await management.getUsers();
};

The example above uses the domain, clientId, and clientSecret secret values to issue a management API token using the client credentials grant. See Get Management API Access Tokens for Production for further details. It stores the token in the management-api-token key and later upon retrieval, renews the token if it has expired.

Please note this example is only provided as a reference. It’s not tested and should not be used in production.

3 Likes