Skip to content

Commit c34b11a

Browse files
author
Shaun Guo
committed
Add pattern for apigw-lambda-authorizer-custom-header
1 parent c6f19e5 commit c34b11a

File tree

4 files changed

+238
-0
lines changed

4 files changed

+238
-0
lines changed
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# Amazon API Gateway API using Lambda Token Authorizer and Mapping Template to add custom header
2+
3+
The SAM template deploys an Amazon API Gateway API endpoint that uses a Lambda Token Authorizer for access control as well as added logic in the Authorizer function to enrich the request with additional data.
4+
5+
This aproach can be used to inject data that downstream legacy systems expect and that is dependent on data that is available to authorizer.
6+
7+
* If the request to the endpoint does not include a 'authorizationToken' header, the Lambda Authorizer will not be invoked and API Gateway will return a 401 Forbidden.
8+
* If the request to the endpoint includes a 'authorizationToken' header, the Lambda Authorizer will be invoked and its response will depend on the value of the 'authorizationToken' header.
9+
* If the value of 'authorizationToken' header is 'unauthorized', API Gateway will return a 401 Unauthorized error.
10+
* If the value of 'authorizationToken' header is 'deny', API Gateway will return a 403 error.
11+
* Only if the value of 'authorizationToken' header is 'allow', API Gateway will successfully call the HTTP backend and return a 200.
12+
* For any other case, API Gateway will return a 403 error.
13+
14+
TODO: Learn more about this pattern at Serverless Land Patterns: [https://serverlessland.com/patterns/apigw-lambda-authorizer](https://serverlessland.com/patterns/apigw-lambda-authorizer)
15+
16+
Important: this application uses various AWS services and there are costs associated with these services after the Free Tier usage - please see the [AWS Pricing page](https://aws.amazon.com/pricing/) for details. You are responsible for any AWS costs incurred. No warranty is implied in this example.
17+
18+
## Requirements
19+
20+
* [Create an AWS account](https://portal.aws.amazon.com/gp/aws/developer/registration/index.html) if you do not already have one and log in. The IAM user that you use must have sufficient permissions to make necessary AWS service calls and manage AWS resources.
21+
* [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html) installed and configured
22+
* [Git Installed](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
23+
* [AWS Serverless Application Model](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html) (AWS SAM) installed
24+
25+
## Deployment Instructions
26+
27+
1. Create a new directory, navigate to that directory in a terminal and clone the GitHub repository:
28+
```
29+
git clone https://github.com/aws-samples/serverless-patterns
30+
```
31+
2. Change directory to the pattern directory:
32+
```
33+
TODO cd apigw-lambda-authorizer
34+
```
35+
3. From the command line, use AWS SAM to deploy the AWS resources for the pattern as specified in the template.yml file:
36+
```
37+
sam deploy -g
38+
```
39+
1. During the prompts:
40+
* Enter a stack name
41+
* Select the desired AWS Region
42+
* Allow SAM to create roles with the required permissions if needed.
43+
44+
Once you have run guided mode once, you can use `sam deploy` in future to use these defaults.
45+
46+
1. Note the outputs from the SAM deployment process. These contain the resource names and/or ARNs which are used for testing.
47+
48+
## Testing
49+
50+
The stack will output the **api endpoint**. Use *curl* to make a HTTP request to the API Gateway that includes a header with the authorization token to test the Resource Lambda Token Authorizer.
51+
52+
```
53+
curl -i https://12345abcde.execute-api.{region}.amazonaws.com/Prod -H "authorizationToken: allow"
54+
```
55+
56+
will successfully return a 200 HTTP code and the request from API Gateway to the HTTP endpoint in the response body. You should see a header named `enrichmentHeader` with a string provided from the Lambda Token Authorizer `This data comes from Lambda Authorizer`
57+
58+
59+
## Cleanup
60+
61+
1. Delete the stack
62+
```bash
63+
sam delete
64+
```
65+
1. Confirm the stack has been deleted
66+
```bash
67+
aws cloudformation list-stacks --query "StackSummaries[?contains(StackName,'STACK_NAME')].StackStatus"
68+
```
69+
----
70+
71+
## Author bio
72+
Shaun Guo
73+
https://www.linkedin.com/in/shaun-guo/
74+
Senior Technical Account Manager
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
{
2+
"title": "AWS API Gateway API with AWS Lambda Token Authorizer and mapping template adding custom headers",
3+
"description": "Create an API with a mapping template that enriches the request with additional data from Lambda Token Authorizer.",
4+
"language": "Node.js",
5+
"level": "200",
6+
"framework": "SAM",
7+
"introBox": {
8+
"headline": "How it works",
9+
"text": [
10+
"This SAM template creates an API that uses additional logic from the Lambda Token Authorizer to add data to the request.",
11+
"The data is passed to the HTTP endpoint in the form of a custom header.",
12+
"This aproach can be used to inject data that downstream legacy systems expect and that is dependent on data that is available to authorizer.",
13+
"The HTTP endpoint in the example returns a response showing the headers that are received."
14+
]
15+
},
16+
"gitHub": {
17+
"template": {
18+
"repoURL": "https://github.com/aws-samples/serverless-patterns/tree/main/apigw-lambda-authorizer-custom-header",
19+
"templateURL": "serverless-patterns/apigw-lambda-authorizer-custom-header",
20+
"projectFolder": "apigw-lambda-authorizer-custom-header",
21+
"templateFile": "apigw-lambda-authorizer-custom-header/template.yml"
22+
}
23+
},
24+
"resources": {
25+
"bullets": [
26+
{
27+
"text": "Working with API Gateway and mapping templates",
28+
"link": "https://docs.aws.amazon.com/apigateway/latest/developerguide/models-mappings.html"
29+
}
30+
]
31+
},
32+
"deploy": {
33+
"text": [
34+
"sam deploy"
35+
]
36+
},
37+
"testing": {
38+
"text": [
39+
"Once the application is deployed, retrieve the API URL and a request from Postman or from a terminal using the curl command with an AuthorizationToken header of 'allow'."
40+
]
41+
},
42+
"cleanup": {
43+
"text": [
44+
"Delete the stack: <code>sam delete</code>."
45+
]
46+
},
47+
"authors": [
48+
{
49+
"headline": "Presented by Shaun Guo, Technical Account Manager",
50+
"name": "Shaun Guo",
51+
"image": "https://media.licdn.com/dms/image/C5103AQG3KMyMdEIKpA/profile-displayphoto-shrink_800_800/0/1517283953925?e=1692835200&v=beta&t=AxJ9ST_8K_bw8nqTPDaJB2F5dnQspES9FuJ64DBScC8",
52+
"bio": "Shaun is a Senior Technical Account Manager at Amazon Web Services based in Australia",
53+
"linkedin": "https://www.linkedin.com/in/shaun-guo/"
54+
}
55+
]
56+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
export const handler = function(event, context, callback) {
2+
console.log(event);
3+
var token = event.authorizationToken;
4+
5+
switch (token) {
6+
case 'allow':
7+
// callback(null, generatePolicy('user', 'Allow', event.methodArn));
8+
callback(null, generatePolicy('user', 'Allow', event.methodArn));
9+
break;
10+
case 'deny':
11+
// callback(null, generatePolicy('user', 'Deny', event.methodArn));
12+
callback(null, generatePolicy('user', 'Deny', event.methodArn));
13+
break;
14+
case 'unauthorized':
15+
callback("Unauthorized"); // Return a 401 Unauthorized response
16+
break;
17+
default:
18+
callback(null, generatePolicy('user', 'Deny', event.methodArn));
19+
}
20+
};
21+
22+
// Help function to generate an IAM policy
23+
var generatePolicy = function(principalId, effect, resource) {
24+
var authResponse = {};
25+
26+
authResponse.principalId = principalId;
27+
if (effect && resource) {
28+
var policyDocument = {};
29+
policyDocument.Version = '2012-10-17';
30+
policyDocument.Statement = [];
31+
var statementOne = {};
32+
statementOne.Action = 'execute-api:Invoke';
33+
statementOne.Effect = effect;
34+
statementOne.Resource = resource;
35+
policyDocument.Statement[0] = statementOne;
36+
authResponse.policyDocument = policyDocument;
37+
}
38+
39+
// enrichment stub, add code here to add enrichment data
40+
authResponse.context = {
41+
"enrichment": "This data comes from Lambda Authorizer"
42+
};
43+
return authResponse;
44+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
AWSTemplateFormatVersion: 2010-09-09
2+
Description: Serverless Pattern - Amazon API Gateway using Lambda Authorizer and Mapping Template to inject customer HTTP headers
3+
Transform: AWS::Serverless-2016-10-31
4+
Globals:
5+
Function:
6+
Runtime: nodejs18.x
7+
Resources:
8+
# REST API
9+
AppApi:
10+
Type: AWS::Serverless::Api
11+
Properties:
12+
Name: apigw-lambda-authorizer-mapping-template
13+
Description: API Gateway using Lambda Authorizer and Mapping Template to inject customer HTTP headers with additional data.
14+
StageName: Prod
15+
Auth:
16+
DefaultAuthorizer: MyLambdaTokenAuthorizer
17+
Authorizers:
18+
MyLambdaTokenAuthorizer:
19+
FunctionArn: !GetAtt AuthorizerFunction.Arn
20+
Identity:
21+
Header: AuthorizationToken
22+
AuthorizerPayloadFormatVersion: 2.0
23+
EnableSimpleResponses: true
24+
DefinitionBody:
25+
swagger: "2.0"
26+
paths:
27+
/:
28+
get:
29+
x-amazon-apigateway-integration:
30+
httpMethod: GET
31+
passthroughBehavior: when_no_templates
32+
type: http
33+
uri: "https://httpbin.org/get"
34+
responses:
35+
"200":
36+
statusCode: '200'
37+
requestTemplates:
38+
application/json: |
39+
{
40+
#set($enrichmentHeaderValue = "$context.authorizer.enrichment")
41+
#set($context.requestOverride.header.enrichmentHeader = $enrichmentHeaderValue)
42+
}
43+
responses:
44+
"200":
45+
statusCode: '200'
46+
47+
# Authorizer function
48+
AuthorizerFunction:
49+
Type: AWS::Serverless::Function
50+
Properties:
51+
CodeUri: src/
52+
Handler: authorizer.handler
53+
Metadata: # Manage esbuild properties
54+
BuildMethod: esbuild
55+
BuildProperties:
56+
Minify: false
57+
Target: "es2020"
58+
EntryPoints:
59+
- authorizer.js
60+
Outputs:
61+
# API Gateway endpoint to be used during tests
62+
AppApiEndpoint:
63+
Description: API Endpoint
64+
Value: !Sub "https://${AppApi}.execute-api.${AWS::Region}.amazonaws.com/Prod"

0 commit comments

Comments
 (0)