Feature: More Extensible Machine-to-machine Flow
Description: Currently actions can only be implemented for use after the provided client_id
and client_secret
have been validated by the “Auth0 Authorization Server”. Enabling actions to be implemented at an earlier point in the M2M flow would allow for the implementation of more complex M2M flows.
Use-case: I’m currently developing a proof-of-concept application that is hosted as an AWS Lambda, and requires the use of the Auth0 Management API. Implementing this securely requires storing the client_secret
within something like AWS Secrets Manager, meaning when making a request to the Auth0 Management API the Lambda needs to retrieve the secret from AWS Secrets Manager, then contacting the Auth0 Authentication API to get an access token, and then actually making the request to the Auth0 Management API.
For a serverless application, this is a decent amount of overhead, so I have attempted to create an action that would supplement the M2M flow allowing for the Lambda to supply AWS IAM credentials and have them validated instead (somewhat similar to MongoDB Atlas).
However, when supplying AWS IAM credentials in place of the normal client_id
and client_secret
is invalidated before the action can run.
Here’s an example of the action’s implementation:
const { STSClient, GetCallerIdentityCommand } = require("@aws-sdk/client-sts");
const allowedArns = ["arn:aws:iam::<AWS account id>:<user | role>/<name>"];
/**
* Handler that will be called during the execution of a Client Credentials exchange.
*
* @param {Event} event - Details about client credentials grant request.
* @param {CredentialsExchangeAPI} api - Interface whose methods can be used to change the behavior of client credentials grant.
*/
exports.onExecuteCredentialsExchange = async (event, api) => {
const body = event.request.body;
const clientId = body["client_id"];
const clientSecret = body["client_secret"];
const iamAuth = body["method"] === "aws";
if(clientId && clientSecret && iamAuth){
const client = new STSClient({
region: "<AWS region>",
credentials: {
accessKeyId: clientId,
secretAccessKey: clientSecret
}
});
let success = false;
try{
const result = await client.send(new GetCallerIdentityCommand({}))
success = allowedArns.includes(result.Arn);
}
catch{
success = false;
}
if(!success){
api.access.deny("invalid_request", "AWS IAM credentials invalid");
}
}
};