Skip to content

Commit

Permalink
fix: Updated templates to check cache for token (#17)
Browse files Browse the repository at this point in the history
  • Loading branch information
jean1880 authored Feb 5, 2024
1 parent 9640504 commit 76016c6
Show file tree
Hide file tree
Showing 4 changed files with 304 additions and 66 deletions.
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
const { ManagementClient } = require('auth0');
const { ManagementClient, AuthenticationClient } = require('auth0');

const HTTP_TIMEOUT = 1000; // 1s

// --- AUTH0 ACTIONS TEMPLATE https://github.com/auth0/opensource-marketplace/blob/main/templates/add-persistence-attribute-PASSWORD_RESET_POST_CHALLENGE ---
/**
* Handler that will be called during the execution of a Password Reset / Post Challenge Flow.
* Handler that will be called during the execution of a Password Reset / Post Challenge Flow. Makes use of a few SECRETS:
* METADATA_KEY - object key value to be set for the user
* METADATA_DEFAULT_VALUE - value to set for METADATA_KEY on initialization
* TENANT_DOMAIN - Domain used for auth in AuthenticationClientOptions (See https://auth0.github.io/node-auth0/interfaces/auth.AuthenticationClientOptions.html for deetails on object)
* CLIENT_ID - Client ID used for auth in AuthenticationClientOptions
* CLIENT_SECRET - Client Secret used for auth in AuthenticationClientOptions
* AUDIENCE - [OPTIONAL] Audience used
*
* @param {Event} event - Details about the post challenge request.
* @param {PasswordResetPostChallengeAPI} api - Interface whose methods can be used to change the behavior of the post challenge flow.
Expand Down Expand Up @@ -33,43 +39,89 @@ 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 authenticationClientOptions = {
domain: event.secrets.TENANT_DOMAIN,
clientId: event.secrets.CLIENT_ID,
clientSecret: event.secrets.CLIENT_SECRET,
timeoutDuration: HTTP_TIMEOUT,
};

const management = new ManagementClient({
domain,
clientId,
clientSecret,
httpTimeout: HTTP_TIMEOUT,
});
// if event.secrets.AUDIENCE is set, make use of the parameter for validating JWT is being used by intended Audience
if (event.secrets.AUDIENCE) {
authenticationClientOptions.audience = event.secrets.AUDIENCE;
}

const management = await getManagementApiClient(
api.cache,
authenticationClientOptions
);

await management.users.update(
{ id: event.user.user_id },
{
user_metadata: {
[metadataKey]: metadataValue || metadataDefaultValue,
[metadataKey]: metadataDefaultValue,
},
}
);
};

/**
* Handler that will be invoked when this action is resuming after an external redirect. If your
* onExecutePostChallenge function does not perform a redirect, this function can be safely ignored.
* Get an AccessToken
*
* @param {Event} event - Details about the user and the context in which they are logging in.
* @param {PasswordResetPostChallengeAPI} api - Interface whose methods can be used to change the behavior of the post challenge flow.
* @param {CacheAPI} cache
* @param {{domain: string, clientId: string, clientSecret: string, audience?: string, timeoutDuration: number}} options - AuthenticationClient options to fetch the token
* @return {Promise<string>}
*/
async function getAccessToken(cache, options) {
let key = `access_token_${options.clientId}`;

if (options.audience) {
key += `_${options.audience}`;
}

// 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, timeoutDuration: number}} options - AuthenticationClient options to fetch the token
*/
// exports.onContinuePostChallenge = async (event, api) => {
// };
async function getManagementApiClient(cache, options) {
const token = await getAccessToken(cache, options);

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

const HTTP_TIMEOUT = 1000; // 1s
const HTTP_TIMEOUT = 1000; // 1s time to timeout on web requests to auth

// --- AUTH0 ACTIONS TEMPLATE https://github.com/auth0/opensource-marketplace/blob/main/templates/add-persistence-attribute-POST_CHANGE_PASSWORD ---
/**
* Handler that will be called during the execution of a PostChangePassword flow.
* Handler that will be called during the execution of a PostChangePassword flow. Makes use of a few SECRETS:
* METADATA_KEY - object key value to be set for the user
* METADATA_DEFAULT_VALUE - value to set for METADATA_KEY on initialization
* TENANT_DOMAIN - Domain used for auth in AuthenticationClientOptions (See https://auth0.github.io/node-auth0/interfaces/auth.AuthenticationClientOptions.html for deetails on object)
* CLIENT_ID - Client ID used for auth in AuthenticationClientOptions
* CLIENT_SECRET - Client Secret used for auth in AuthenticationClientOptions
* AUDIENCE - [OPTIONAL] Audience used
*
* @param {Event} event - Details about the user and the context in which the change password is happening.
* @param {PostChangePasswordAPI} api - Methods and utilities to help change the behavior after a user changes their password.
Expand Down Expand Up @@ -36,35 +42,91 @@ 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 authenticationClientOptions = {
domain: event.secrets.TENANT_DOMAIN,
clientId: event.secrets.CLIENT_ID,
clientSecret: event.secrets.CLIENT_SECRET,
timeoutDuration: HTTP_TIMEOUT,
};

const management = new ManagementClient({
domain,
clientId,
clientSecret,
httpTimeout: HTTP_TIMEOUT,
});
// if event.secrets.AUDIENCE is set, make use of the parameter for validating JWT is being used by intended Audience
if (event.secrets.AUDIENCE) {
authenticationClientOptions.audience = event.secrets.AUDIENCE;
}

const management = await getManagementApiClient(
api.cache,
authenticationClientOptions
);

await management.users.update(
{ id: event.user.user_id },
{
user_metadata: {
[metadataKey]: metadataValue || metadataDefaultValue,
[metadataKey]: metadataDefaultValue,
},
}
);
};

/**
* Get an AccessToken
*
* @param {CacheAPI} cache
* @param {{domain: string, clientId: string, clientSecret: string, audience?: string, timeoutDuration: number}} options - AuthenticationClient options to fetch the token
* @return {Promise<string>}
*/
async function getAccessToken(cache, options) {
let key = `access_token_${options.clientId}`;

if (options.audience) {
key += `_${options.audience}`;
}

// 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, timeoutDuration: number}} 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,
});
}
90 changes: 76 additions & 14 deletions templates/add-persistence-attribute-POST_USER_REGISTRATION/code.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
const { ManagementClient } = require('auth0');
const { ManagementClient, AuthenticationClient } = require('auth0');

const HTTP_TIMEOUT = 1000; // 1s

// --- AUTH0 ACTIONS TEMPLATE https://github.com/auth0/opensource-marketplace/blob/main/templates/add-persistence-attribute-POST_USER_REGISTRATION ---
/**
* Handler that will be called during the execution of a PostUserRegistration flow.
* Handler that will be called during the execution of a PostUserRegistration flow.. Makes use of a few SECRETS:
* METADATA_KEY - object key value to be set for the user
* METADATA_DEFAULT_VALUE - value to set for METADATA_KEY on initialization
* TENANT_DOMAIN - Domain used for auth in AuthenticationClientOptions (See https://auth0.github.io/node-auth0/interfaces/auth.AuthenticationClientOptions.html for deetails on object)
* CLIENT_ID - Client ID used for auth in AuthenticationClientOptions
* CLIENT_SECRET - Client Secret used for auth in AuthenticationClientOptions
* AUDIENCE - [OPTIONAL] Audience used
*
* @param {Event} event - Details about the context and user that has registered.
* @param {PostUserRegistrationAPI} api - Methods and utilities to help change the behavior after a signup.
Expand Down Expand Up @@ -36,35 +42,91 @@ 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 authenticationClientOptions = {
domain: event.secrets.TENANT_DOMAIN,
clientId: event.secrets.CLIENT_ID,
clientSecret: event.secrets.CLIENT_SECRET,
timeoutDuration: HTTP_TIMEOUT,
};

const management = new ManagementClient({
domain,
clientId,
clientSecret,
httpTimeout: HTTP_TIMEOUT,
});
// if event.secrets.AUDIENCE is set, make use of the parameter for validating JWT is being used by intended Audience
if (event.secrets.AUDIENCE) {
authenticationClientOptions.audience = event.secrets.AUDIENCE;
}

const management = await getManagementApiClient(
api.cache,
authenticationClientOptions
);

await management.users.update(
{ id: event.user.user_id },
{
user_metadata: {
[metadataKey]: metadataValue || metadataDefaultValue,
[metadataKey]: metadataDefaultValue,
},
}
);
};

/**
* Get an AccessToken
*
* @param {CacheAPI} cache
* @param {{domain: string, clientId: string, clientSecret: string, audience?: string, timeoutDuration: number}} options - AuthenticationClient options to fetch the token
* @return {Promise<string>}
*/
async function getAccessToken(cache, options) {
let key = `access_token_${options.clientId}`;

if (options.audience) {
key += `_${options.audience}`;
}

// 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, timeoutDuration: number}} 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,
});
}
Loading

0 comments on commit 76016c6

Please sign in to comment.