auth0-lambda-authorizer v2.0.6
Auth0 Lambda Authorizer
This is a simple custom authorizer for AWS lambda.
Requirements
- jwks-rsa
Motivation
When writing FaaS applications on AWS lambda that
have an http endpoint, we sometimes want to
secure these endpoints and only allow authenticated
and authorized users to access them. We use JWT for
this and for the past FaaS projects we have just copy
pasted this custom authorizer across projects. Extracting
it into a library will give us the ability to share
improvements and bugs across projects without having
to copy paste the code around.
Usage
We need to first create a jwksClient using jwks-rsa.
const client = jwksClient({
cache: true,
jwksRequestsPerMinute: 10,
jwksUri: process.env.JWKS_URI,
rateLimit: true,
});The JWKS_URI should be fetched from the Auth0 dashboard.
Here we have added it as an environment variable.
We also need to decode the auth0 secret. The approach we normally
take is to save the PUBLIC_PEM using kms and then decrypt it,
and convert it to a Buffer.
//Given a function for decrypting a KMS string:
const encodedString = await getDecryptedKmsString(process.env.AUTH0_WEB_PUBLIC_PEM);
const auth0Secret = new Buffer(encodedSecret, "base64").toString();Then we need to create a callback that will be executed once
we have decoded the token. This callback is also responsible
for returning control to the lambda environment by calling context.succeed
or context.fail:
const authenticateCallback = (err, authResponse: AuthResponse) => {
if (err) {
if (!err) {
log.error("Failed to authenticate with an unhandled error", err);
context.fail("Unauthorized");
} else {
log.error("Recieved an unauthorized request", err);
context.fail("Unauthorized");
}
} else {
log.info({ msg: "Successfully authenticated a request" });
context.succeed(authResponse);
}
}This callback will get either an error or a response from our authenticate function.
AuthResponse looks like this:
export interface AuthResponse {
policyDocument: PolicyDocument;
principalId: string;
context: any;
}This includes a policyDocument, the principalId and the context.
The context is a map that will contain the payload along with the scope.
A default policyDocument is created that allows access to execute
any lambda. However, we might not always want to do this.
We can create our own policyDocument if we want more fine grained control
by using the getPolicyDocument function.
//given that we have imported `ramda` as R.
if (R.contains("admin", context.roles) || R.contains("premiumUser", context.roles)) {
const policyDocument = getPolicyDocument("Allow", [event.methodArn])
authResponse.policyDocument = policyDocument;
} else {
const policyDocument = getPolicyDocument("Deny", [event.methodArn])
authResponse.policyDocument = policyDocument;
}7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago