Skip to content

Commit f9e7f29

Browse files
fyockmmostekcm
authored andcommitted
Update for Lambda 8.10 (auth0-samples#5)
1 parent f92d341 commit f9e7f29

File tree

5 files changed

+1533
-95
lines changed

5 files changed

+1533
-95
lines changed

README.md

+13-13
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# AWS API Gateway Custom Authorizer for RS256 JWTs
22

3-
An AWS API Gateway [Custom Authorizer](http://docs.aws.amazon.com/apigateway/latest/developerguide/use-custom-authorizer.html) that authorizes API requests by requiring
3+
An AWS API Gateway [Custom Authorizer](http://docs.aws.amazon.com/apigateway/latest/developerguide/use-custom-authorizer.html) that authorizes API requests by requiring
44
that the OAuth2 [bearer token](https://tools.ietf.org/html/rfc6750) is a JWT that can be validated using the RS256 (asymmetric) algorithm with a public key that is obtained from a [JWKS](https://tools.ietf.org/html/rfc7517) endpoint.
55

66
## About
@@ -13,7 +13,7 @@ One popular use case is to provide an interface to AWS Lambda functions to deliv
1313

1414
### What are "Custom Authorizers"?
1515

16-
In February 2016 Amazon
16+
In February 2016 Amazon
1717
[announced](https://aws.amazon.com/blogs/compute/introducing-custom-authorizers-in-amazon-api-gateway/)
1818
a new feature for API Gateway -
1919
[Custom Authorizers](http://docs.aws.amazon.com/apigateway/latest/developerguide/use-custom-authorizer.html). This allows a Lambda function to be invoked prior to an API Gateway execution to perform custom authorization of the request, rather than using AWS's built-in authorization. This code can then be isolated to a single centralized Lambda function rather than replicated across every backend Lambda function.
@@ -181,7 +181,7 @@ Now we can finally create the lamda function itself in AWS. Start by going to [c
181181

182182
* Name: `jwtRsaCustomAuthorizer`
183183
* Description: `JWT RSA Custom Authorizer`
184-
* Runtime: `Node.js 4.3`
184+
* Runtime: `Node.js 8.10`
185185
* _Lambda function code_
186186
* Code entry type: `Update a .ZIP file`
187187
* Function package: (upload the `custom-authorizer.zip` file created earlier)
@@ -230,7 +230,7 @@ You can then test the new custom authorizer by providing an **Identity Token** a
230230
```
231231
Bearer ACCESS_TOKEN
232232
```
233-
233+
234234
A successful test will look something like:
235235
236236
```
@@ -241,14 +241,14 @@ Policy
241241
"Version": "2012-10-17",
242242
"Statement": [
243243
{
244-
"Sid": "Stmt1459758003000",
245-
"Effect": "Allow",
246-
"Action": [
247-
"execute-api:Invoke"
248-
],
249-
"Resource": [
250-
"arn:aws:execute-api:*"
251-
]
244+
"Sid": "Stmt1459758003000",
245+
"Effect": "Allow",
246+
"Action": [
247+
"execute-api:Invoke"
248+
],
249+
"Resource": [
250+
"arn:aws:execute-api:*"
251+
]
252252
}
253253
]
254254
}
@@ -305,7 +305,7 @@ The above command is performed using the `GET` method.
305305
306306
```
307307
fetch( 'INVOKE_URL/your/resource', { method: 'GET', headers: { Authorization : 'Bearer ACCESS_TOKEN' }}).then(response => { console.log( response );});
308-
```
308+
```
309309
310310
311311
---

index.js

+11-15
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,14 @@
1-
'use strict';
2-
3-
var lib = require('./lib');
4-
1+
const lib = require('./lib');
2+
let data;
53

64
// Lambda function index.handler - thin wrapper around lib.authenticate
7-
module.exports.handler = function (event, context) {
8-
lib.authenticate(event, function (err, data) {
9-
if (err) {
10-
if (!err) context.fail("Unhandled error");
11-
context.fail("Unauthorized");
12-
13-
}
14-
else context.succeed(data);
15-
16-
});
17-
5+
module.exports.handler = async (event) => {
6+
try {
7+
data = await lib.authenticate(event);
8+
}
9+
catch (err) {
10+
console.log(err);
11+
return `Unauthorized: ${err.message}`;
12+
}
13+
return data;
1814
};

lib.js

+43-58
Original file line numberDiff line numberDiff line change
@@ -1,85 +1,70 @@
1-
'use strict';
2-
31
require('dotenv').config({ silent: true });
4-
var jwksClient = require('jwks-rsa');
5-
var jwt = require('jsonwebtoken');
6-
7-
var getPolicyDocument = function (effect, resource) {
82

9-
var policyDocument = {};
10-
policyDocument.Version = '2012-10-17'; // default version
11-
policyDocument.Statement = [];
12-
var statementOne = {};
13-
statementOne.Action = 'execute-api:Invoke'; // default action
14-
statementOne.Effect = effect;
15-
statementOne.Resource = resource;
16-
policyDocument.Statement[0] = statementOne;
3+
const jwksClient = require('jwks-rsa');
4+
const jwt = require('jsonwebtoken');
5+
const util = require('util');
6+
7+
const getPolicyDocument = (effect, resource) => {
8+
const policyDocument = {
9+
Version: '2012-10-17', // default version
10+
Statement: [{
11+
Action: 'execute-api:Invoke', // default action
12+
Effect: effect,
13+
Resource: resource,
14+
}]
15+
};
1716
return policyDocument;
1817
}
1918

2019

2120
// extract and return the Bearer Token from the Lambda event parameters
22-
var getToken = function (params) {
23-
var token;
24-
21+
const getToken = (params) => {
2522
if (!params.type || params.type !== 'TOKEN') {
26-
throw new Error("Expected 'event.type' parameter to have value TOKEN");
23+
throw new Error('Expected "event.type" parameter to have value "TOKEN"');
2724
}
2825

29-
var tokenString = params.authorizationToken;
26+
const tokenString = params.authorizationToken;
3027
if (!tokenString) {
31-
throw new Error("Expected 'event.authorizationToken' parameter to be set");
28+
throw new Error('Expected "event.authorizationToken" parameter to be set');
3229
}
3330

34-
var match = tokenString.match(/^Bearer (.*)$/);
31+
const match = tokenString.match(/^Bearer (.*)$/);
3532
if (!match || match.length < 2) {
36-
throw new Error("Invalid Authorization token - '" + tokenString + "' does not match 'Bearer .*'");
33+
throw new Error(`Invalid Authorization token - ${tokenString} does not match "Bearer .*"`);
3734
}
3835
return match[1];
3936
}
4037

41-
module.exports.authenticate = function (params, cb) {
38+
const jwtOptions = {
39+
audience: process.env.AUDIENCE,
40+
issuer: process.env.TOKEN_ISSUER
41+
};
42+
43+
module.exports.authenticate = (params) => {
4244
console.log(params);
43-
var token = getToken(params);
45+
const token = getToken(params);
4446

45-
var client = jwksClient({
47+
const decoded = jwt.decode(token, { complete: true });
48+
if (!decoded || !decoded.header || !decoded.header.kid) {
49+
throw new Error('invalid token');
50+
}
51+
52+
const client = jwksClient({
4653
cache: true,
4754
rateLimit: true,
4855
jwksRequestsPerMinute: 10, // Default value
4956
jwksUri: process.env.JWKS_URI
5057
});
5158

52-
var decoded = jwt.decode(token, { complete: true });
53-
var kid = decoded.header.kid;
54-
client.getSigningKey(kid, function (err, key) {
55-
if(err)
56-
{
57-
cb(err);
58-
}
59-
else
60-
{
61-
var signingKey = key.publicKey || key.rsaPublicKey;
62-
jwt.verify(token, signingKey, { audience: process.env.AUDIENCE, issuer: process.env.TOKEN_ISSUER },
63-
function (err, decoded) {
64-
if (err) {
65-
cb(err);
66-
67-
}
68-
else {
69-
70-
cb(null, {
71-
principalId: decoded.sub,
72-
policyDocument: getPolicyDocument('Allow', params.methodArn),
73-
context: {
74-
scope: decoded.scope
75-
}
76-
});
77-
}
78-
});
79-
}
80-
81-
});
82-
83-
84-
59+
const getSigningKey = util.promisify(client.getSigningKey);
60+
return getSigningKey(decoded.header.kid)
61+
.then((key) => {
62+
const signingKey = key.publicKey || key.rsaPublicKey;
63+
return jwt.verify(token, signingKey, jwtOptions);
64+
})
65+
.then((decoded)=> ({
66+
principalId: decoded.sub,
67+
policyDocument: getPolicyDocument('Allow', params.methodArn),
68+
context: { scope: decoded.scope }
69+
}));
8570
}

0 commit comments

Comments
 (0)