Securing API Gateway with Lambda Authorizers

AWS provides a number of options such as Resource Policies, API Keys and IAM —and then there are Lambda Authorizers.

Lambda Authorizers can either be token-based or request based.

Directly quoting the documentation:A token-based Lambda authorizer (also called a TOKEN authorizer) receives the caller's identity in a bearer token, such as a JSON Web Token (JWT) or an OAuth token.

A request parameter-based Lambda authorizer (also called a REQUEST authorizer) receives the caller's identity in a combination of headers, query string parameters, state variables, and context variables.

I’m going to focus on token-based Lambda Authorizers for this guide.

If you’ve never heard of JWT, check out jwt.

io.

For me, the magic is almost any user database or data source can be used as the source of truth for generating your tokens.

One really great example and probably one of the most popular Cognito alternatives is Auth0, which can act as the authentication source for API Gateway through the use of Lambda Authorizers.

To get started, I’m going to create a new serverless application:sls create –template aws-csharp –path customauthorizerOnce created, the next step is to create the classes which will help us generate and validate JWTs.

Thanks to Moshe Binieli for his code which formed the base to make this work.

We need to create 4 files in your service’s directory:Authorizer/Managers/IAuthService.

csAuthorizer/Managers/JWTService.

csAuthorizer/Models/IAuthContainerModel.

csAuthorizer/Models/JWTContainerModel.

csThen add the following environment variables to serverless.

yml — remember to change the signature to your own and set the token expiry to something which suits your use case!environment: ApiGatewayArn: Fn::Join: – "" – – "arn:aws:execute-api" – ":" – Ref: AWS::Region – ":" – Ref: AWS::AccountId – ":" – Ref: ApiGatewayRestApi – "/*/*/*" # Used for generating the JWT for the user into API Gateway HmacSignature: "ad94f8c800e4883ff7f6aa5ec96fbea34926b6ea5960c43a20941586e3f8eeb5" HmacExpiry: 10080 # Minutes, 10080 is 7 daysFor the authorizer to work, we’ll need to create two more Lambda functions:Authenticate: /Authorizer/Authenticate.

csYou would reference your logic in this file to authenticate the user before returning the JWT.

There is no authentication logic in the example, you can bring your own.

When working with modern web apps, store the returned token in the local storage of the browser to pass to your APIs on subsequent requests.

Check Token: /Authorizer/CheckToken.

csUsed to check the token being passed on subsequent requests is still valid.

If still valid, allow the user to invoke the API.

This will return a policy document.

These two Lambda functions also need to be referenced in serverless.

yml:functions: authorizerCheckToken: handler: CsharpHandlers::Authorizer.

CheckToken::FunctionHandler authorizerAuthenticate: handler: CsharpHandlers::Authorizer.

Authenticate::FunctionHandler events: – http: path: authenticate method: get integration: lambda cors: trueLast but not least, we’ll create a test function to try everything out.

The trick for this function’s definition is to include authorizer: authorizerCheckToken, as this will tell API Gateway to use the CheckToken function as our Lambda Authorizer when invoked:Handler.

cshello: handler: CsharpHandlers::Namespace.

Handler::FunctionHandler events: – http: path: hello method: get integration: lambda cors: true authorizer: authorizerCheckTokenTime to build and deploy…sh .

/build.

sh OR build.

cmd (depending if you're using Windows, Mac or Linux)sls deploy -vSo what has actually happened?.If we navigate to API Gateway, select the API, and go to Authorizers we can see the Lambda Authorizer has been created.

As I marked the hello function to be secured by the Lambda Authorizer, if we go to the method and select Method Request, Authorization has the Lambda Authorizer set.

I’m going to use Postman to test my APIs, any tool which invokes URLs is fine (eg.

curl).

I’ll invoke the hello function without including my token — the request should be denied.

To get a token, I’m going to invoke the authenticate function, it should return a SUCCESS code and the token in the response.

Take a copy of the token for the next step.

The next request to the hello function needs to include the Authorization header, including the token from the last step.

Assuming this has all been set up correctly, the request should be successful.

Have a play around by generating different tokens or by waiting for your token to expire, subsequent requests to API Gateway should be denied.

If you’d like to download the working project, I’ve uploaded it for use to GitHub!.

. More details

Leave a Reply