UNPKG

auth0-lambda-authorizer

Version:

An Auth0 Authorizer for AWS Lambda

98 lines (79 loc) 3.14 kB
# 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`. ```typescript 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. ```typescript //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`: ```typescript 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: ```typescript 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. ```typescript //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; } ```