NodeJS Lambda Authorizer for JWT Access Tokens

Chris Concannon
The Golden Gate Bridge at sunset — photo taken by me while on my bike commute home the other night

I recently created a Lambda Authorizer to secure AWS API Gateway endpoints with JSON Web Tokens (JWTs). I found that many tutorials exist for Lambda Authorizer creation, but I found a lack of examples for such a script in NodeJS. Here’s a nice diagram I created that depicts the Authentication and Authorization process using a web or mobile app, AWS API Gateway, a Lambda Authorizer, and OAuth2-issued JWT access tokens.



I wrote the authorizer function with two npm dependencies, both maintained by Auth0:

The jsonwebtoken package handles the logic behind token decoding, verification of the signature, checking for expiration, and checking for other options which you specify. Customize the verificationOptions variable to your liking (and make sure that you check the “audience” property to be sure that this token was issued for use at your resource server).

The jwks-rsa package handles the retrieval of your ID Provider’s signing keys. The code assumes that your ID Provider uses solely the RSA256 signing algorithm, but this can be changed in the verificationOptions algorithms parameter if it is not the case.


The code can be found below, and also at https://github.com/cconcannon/lambda-authorizer-jwt

const jwt = require('jsonwebtoken');
const jwksClient = require('jwks-rsa');
const keyClient = jwksClient({
cache: true,
cacheMaxAge: 86400000, //value in ms
rateLimit: true,
jwksRequestsPerMinute: 10,
strictSsl: true,
jwksUri: process.env.JWKS_URI
})
const verificationOptions = {
// verify claims, e.g.
// "audience": "urn:audience"
"algorithms": "RS256"
}
const allow = {
"principalId": "user",
"policyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Action": "execute-api:Invoke",
"Effect": "Allow",
"Resource": process.env.RESOURCE
}
]
}
}
function getSigningKey (header = decoded.header, callback) {
keyClient.getSigningKey(header.kid, function(err, key) {
const signingKey = key.publicKey || key.rsaPublicKey;
callback(null, signingKey);
})
}
function extractTokenFromHeader(e) {
if (e.authorizationToken && e.authorizationToken.split(' ')[0] === 'Bearer') {
return e.authorizationToken.split(' ')[1];
} else {
return e.authorizationToken;
}
}
function validateToken(token, callback) {
jwt.verify(token, getSigningKey, verificationOptions, function (error) {
if (error) {
callback("Unauthorized")
} else {
callback(null, allow)
}
})
}
exports.handler = (event, context, callback) => {
let token = extractTokenFromHeader(event) || '';
validateToken(token, callback);
}

If you make changes to the code, you will need to run npm i in your root folder, then zip the index.js file and the node_modules/ folder to upload to Lambda.

Chris Concannon

Written by

former biomedical engineer, current web application developer

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade