Skip to content

Commit

Permalink
fix: Updated templates to check cache for token
Browse files Browse the repository at this point in the history
- Updated four templates, to make use of API cache, to check for auth
  token BEFORE attempting to create a new token. this will reduce the
  number of times the template attempts to create a new auth0 token,
  especially when under high loads
  • Loading branch information
jean1880 committed Feb 5, 2024
1 parent 9640504 commit 7f87259
Show file tree
Hide file tree
Showing 4 changed files with 215 additions and 51 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const { ManagementClient } = require('auth0');
const { ManagementClient, AuthenticationClient } = require('auth0');

const HTTP_TIMEOUT = 1000; // 1s

Expand Down Expand Up @@ -33,25 +33,19 @@ exports.onExecutePostChallenge = async (event, api) => {
return api.access.deny('missing client id');
}

const clientId = event.secrets.CLIENT_ID;

if (!event.secrets.CLIENT_SECRET) {
return api.access.deny('missing client secret');
}

const clientSecret = event.secrets.CLIENT_SECRET;

if (!event.secrets.TENANT_DOMAIN) {
return api.access.deny('missing tenant domain');
}

const domain = event.secrets.TENANT_DOMAIN;

const management = new ManagementClient({
domain,
clientId,
clientSecret,
httpTimeout: HTTP_TIMEOUT,
const management = await getManagementApiClient(api.cache, {
domain: event.secrets.TENANT_DOMAIN,
clientId: event.secrets.CLIENT_ID,
clientSecret: event.secrets.CLIENT_SECRET,
timeoutDuration: HTTP_TIMEOUT,
});

await management.users.update(
Expand All @@ -63,6 +57,52 @@ exports.onExecutePostChallenge = async (event, api) => {
}
);
};
/**
* Get an AccessToken
*
* @param {CacheAPI} cache
* @param {{domain: string, clientId: string, clientSecret: string, audience?: string}} options - AuthenticationClient options to fetch the token
* @return {Promise<string>}
*/
async function getAccessToken(cache, options) {
const key = `access_token_${options.clientId}`;
// Check the cache if we have a valid entry
const record = cache.get(key);
if (record && record.expires_at > Date.now()) {
return record.value;
}

// Get the AccessToken using a client_credential grant.
const authClient = new AuthenticationClient(options);

const {
data: { access_token, expires_in },
} = await authClient.oauth.clientCredentialsGrant({
audience: options.audience ?? `https://${options.domain}/api/v2/`,
});

// Try to cache it
const cacheSetResult = cache.set(key, access_token, { ttl: expires_in });
if (cacheSetResult.type === 'error') {
console.error(`Failed to set ${key}: ${cacheSetResult.code}`);
}

return access_token;
}

/**
* @param {CacheAPI} cache
* @param {{domain: string, clientId: string, clientSecret: string, audience?: string}} options - AuthenticationClient options to fetch the token
*/
async function getManagementApiClient(cache, options) {
const token = await getAccessToken(cache, options);

return new ManagementClient({
domain: options.domain,
token,
httpTimeout: HTTP_TIMEOUT,
});
}

/**
* Handler that will be invoked when this action is resuming after an external redirect. If your
Expand Down
65 changes: 53 additions & 12 deletions templates/add-persistence-attribute-POST_CHANGE_PASSWORD/code.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const { ManagementClient } = require('auth0');
const { ManagementClient, AuthenticationClient } = require('auth0');

const HTTP_TIMEOUT = 1000; // 1s

Expand Down Expand Up @@ -36,27 +36,21 @@ exports.onExecutePostChangePassword = async (event, api) => {
return;
}

const clientId = event.secrets.CLIENT_ID;

if (!event.secrets.CLIENT_SECRET) {
console.log('missing event.secrets.CLIENT_SECRET');
return;
}

const clientSecret = event.secrets.CLIENT_SECRET;

if (!event.secrets.TENANT_DOMAIN) {
console.log('missing event.secrets.TENANT_DOMAIN');
return;
}

const domain = event.secrets.TENANT_DOMAIN;

const management = new ManagementClient({
domain,
clientId,
clientSecret,
httpTimeout: HTTP_TIMEOUT,
const management = await getManagementApiClient(api.cache, {
domain: event.secrets.TENANT_DOMAIN,
clientId: event.secrets.CLIENT_ID,
clientSecret: event.secrets.CLIENT_SECRET,
timeoutDuration: HTTP_TIMEOUT,
});

await management.users.update(
Expand All @@ -68,3 +62,50 @@ exports.onExecutePostChangePassword = async (event, api) => {
}
);
};

/**
* Get an AccessToken
*
* @param {CacheAPI} cache
* @param {{domain: string, clientId: string, clientSecret: string, audience?: string}} options - AuthenticationClient options to fetch the token
* @return {Promise<string>}
*/
async function getAccessToken(cache, options) {
const key = `access_token_${options.clientId}`;
// Check the cache if we have a valid entry
const record = cache.get(key);
if (record && record.expires_at > Date.now()) {
return record.value;
}

// Get the AccessToken using a client_credential grant.
const authClient = new AuthenticationClient(options);

const {
data: { access_token, expires_in },
} = await authClient.oauth.clientCredentialsGrant({
audience: options.audience ?? `https://${options.domain}/api/v2/`,
});

// Try to cache it
const cacheSetResult = cache.set(key, access_token, { ttl: expires_in });
if (cacheSetResult.type === 'error') {
console.error(`Failed to set ${key}: ${cacheSetResult.code}`);
}

return access_token;
}

/**
* @param {CacheAPI} cache
* @param {{domain: string, clientId: string, clientSecret: string, audience?: string}} options - AuthenticationClient options to fetch the token
*/
async function getManagementApiClient(cache, options) {
const token = await getAccessToken(cache, options);

return new ManagementClient({
domain: options.domain,
token,
httpTimeout: HTTP_TIMEOUT,
});
}
66 changes: 54 additions & 12 deletions templates/add-persistence-attribute-POST_USER_REGISTRATION/code.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const { ManagementClient } = require('auth0');
const { ManagementClient, AuthenticationClient } = require('auth0');

const HTTP_TIMEOUT = 1000; // 1s

Expand Down Expand Up @@ -36,27 +36,21 @@ exports.onExecutePostUserRegistration = async (event, api) => {
return;
}

const clientId = event.secrets.CLIENT_ID;

if (!event.secrets.CLIENT_SECRET) {
console.log('missing event.secrets.CLIENT_SECRET');
return;
}

const clientSecret = event.secrets.CLIENT_SECRET;

if (!event.secrets.TENANT_DOMAIN) {
console.log('missing event.secrets.TENANT_DOMAIN');
return;
}

const domain = event.secrets.TENANT_DOMAIN;

const management = new ManagementClient({
domain,
clientId,
clientSecret,
httpTimeout: HTTP_TIMEOUT,
const management = await getManagementApiClient(api.cache, {
domain: event.secrets.TENANT_DOMAIN,
clientId: event.secrets.CLIENT_ID,
clientSecret: event.secrets.CLIENT_SECRET,
timeoutDuration: HTTP_TIMEOUT,
});

await management.users.update(
Expand All @@ -68,3 +62,51 @@ exports.onExecutePostUserRegistration = async (event, api) => {
}
);
};

/**
* Get an AccessToken
*
* @param {CacheAPI} cache
* @param {{domain: string, clientId: string, clientSecret: string, audience?: string}} options - AuthenticationClient options to fetch the token
* @return {Promise<string>}
*/
async function getAccessToken(cache, options) {
const key = `access_token_${options.clientId}`;
// Check the cache if we have a valid entry
const record = cache.get(key);

if (record && record.expires_at > Date.now()) {
return record.value;
}

// Get the AccessToken using a client_credential grant.
const authClient = new AuthenticationClient(options);

const {
data: { access_token, expires_in },
} = await authClient.oauth.clientCredentialsGrant({
audience: options.audience ?? `https://${options.domain}/api/v2/`,
});

// Try to cache it
const cacheSetResult = cache.set(key, access_token, { ttl: expires_in });
if (cacheSetResult.type === 'error') {
console.error(`Failed to set ${key}: ${cacheSetResult.code}`);
}

return access_token;
}

/**
* @param {CacheAPI} cache
* @param {{domain: string, clientId: string, clientSecret: string, audience?: string}} options - AuthenticationClient options to fetch the token
*/
async function getManagementApiClient(cache, options) {
const token = await getAccessToken(cache, options);

return new ManagementClient({
domain: options.domain,
token,
httpTimeout: HTTP_TIMEOUT,
});
}
71 changes: 56 additions & 15 deletions templates/add-persistence-attribute-SEND_PHONE_MESSAGE/code.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const { ManagementClient } = require('auth0');
const { ManagementClient, AuthenticationClient } = require('auth0');

const HTTP_TIMEOUT = 1000; // 1s

Expand All @@ -11,14 +11,14 @@ const HTTP_TIMEOUT = 1000; // 1s
*/
exports.onExecuteSendPhoneMessage = async (event, api) => {
if (!event.secrets.METADATA_KEY) {
console.log('missing event.secrets.METADATA_KEY');
console.log('missing metadata key');
return;
}

const metadataKey = event.secrets.METADATA_KEY;

if (!event.secrets.METADATA_DEFAULT_VALUE) {
console.log('missing event.secrets.METADATA_DEFAULT_VALUE');
console.log('missing metadata default value');
return;
}

Expand All @@ -36,27 +36,21 @@ exports.onExecuteSendPhoneMessage = async (event, api) => {
return;
}

const clientId = event.secrets.CLIENT_ID;

if (!event.secrets.CLIENT_SECRET) {
console.log('missing event.secrets.CLIENT_SECRET');
return;
}

const clientSecret = event.secrets.CLIENT_SECRET;

if (!event.secrets.TENANT_DOMAIN) {
console.log('missing event.secrets.TENANT_DOMAIN');
console.log('missing tenant domain');
return;
}

const domain = event.secrets.TENANT_DOMAIN;

const management = new ManagementClient({
domain,
clientId,
clientSecret,
httpTimeout: HTTP_TIMEOUT,
const management = await getManagementApiClient(api.cache, {
domain: event.secrets.TENANT_DOMAIN,
clientId: event.secrets.CLIENT_ID,
clientSecret: event.secrets.CLIENT_SECRET,
timeoutDuration: HTTP_TIMEOUT,
});

await management.users.update(
Expand All @@ -68,3 +62,50 @@ exports.onExecuteSendPhoneMessage = async (event, api) => {
}
);
};
/**
* Get an AccessToken
*
* @param {CacheAPI} cache
* @param {{domain: string, clientId: string, clientSecret: string, audience?: string}} options - AuthenticationClient options to fetch the token
* @return {Promise<string>}
*/
async function getAccessToken(cache, options) {
const key = `access_token_${options.clientId}`;
// Check the cache if we have a valid entry
const record = cache.get(key);

if (record && record.expires_at > Date.now()) {
return record.value;
}

// Get the AccessToken using a client_credential grant.
const authClient = new AuthenticationClient(options);

const {
data: { access_token, expires_in },
} = await authClient.oauth.clientCredentialsGrant({
audience: options.audience ?? `https://${options.domain}/api/v2/`,
});

// Try to cache it
const cacheSetResult = cache.set(key, access_token, { ttl: expires_in });
if (cacheSetResult.type === 'error') {
console.log(`Failed to set ${key}: ${cacheSetResult.code}`);
}

return access_token;
}

/**
* @param {CacheAPI} cache
* @param {{domain: string, clientId: string, clientSecret: string, audience?: string}} options - AuthenticationClient options to fetch the token
*/
async function getManagementApiClient(cache, options) {
const token = await getAccessToken(cache, options);

return new ManagementClient({
domain: options.domain,
token,
httpTimeout: HTTP_TIMEOUT,
});
}

0 comments on commit 7f87259

Please sign in to comment.