Skip to content

Latest commit

 

History

History
102 lines (64 loc) · 5.47 KB

README.md

File metadata and controls

102 lines (64 loc) · 5.47 KB

TODO - total rewrite - this one isn't based on Karl's example

Sample Lambda Authorizer for AWS API Gateway

This sample is based on https://github.com/mcguinness/node-lambda-oauth2-jwt-authorizer by Karl McGuinness. Karl's original README can be found on his github repo at https://github.com/mcguinness/node-lambda-oauth2-jwt-authorizer. A modified version, including changes made for this sample, is included below.

This project is sample implementation of an AWS Lambda custom authorizer for AWS API Gateway that works with a JWT bearer token (id_token or access_token) issued by an OAuth 2.0 Authorization Server. It can be used to secure access to APIs managed by AWS API Gateway.

Use Case

This authorize was built as a demo tool to show how to secure an API resource on AWS API Gateway using OAuth 2.0. The authorizer is specifically designed to work with mock_api_lambda, a Lambda Function that serves as a mock API endpoint. The authorizer adds data about the policy decision (success and failure) to the context object of it's response to the API Gateway. The mock_api_lambda function, in turn, returns that contextual information in it's response.

In addition to

Configuration

How it works

Scopes

The authorizer uses a simple json mapping object to define which scopes are required for each API resource/HTTP method. A scope is mapped to an HTTP method/resource pair (an endpoint). This can be a 1:1 mapping, or several scopes could be required for a single method/resource as shown below.

The authorizer will loop through the scopes in the mapping json object, comparing them with the scopes present in the bearer token. When a match is found, the method/resource is added to the policy document as an explicit allow. If a scope in the scope mapping JSON is not present in the bearer token, the access policy explicitly deny access to the method/resource, and add an error message to the authorizerMessage attribute of policy document's context indicating which scope(s) were missing. The authorizerMessage is used to provide more informative (demo purposes only) error message from the API Gateway. Here's a sample scope->method/resource mapping, where the scope fab:read is required to access the /banks resource via GET.

const scpMapping = {
  'fab:read': {
      method: 'GET',
      resource: '/banks'
  },
  'banks:read': {
      method: 'GET',
      resource: '/banks'
  }
};

Context Object and Messages

To use the messages returned in the authorizerMessage attribute, you'll need to modify the API's Gateway Response messages. I modified Default 4XX, and the 403 responses like this:

{
    "[Default 4XX] message": $context.error.messageString,
    "Authorizer Message": "$context.authorizer.authorizerMessage"
}

Where $context.authorizer.authorizerMessage is the authorizerMessage attribute returned on the policy document context object.

Environment Variables (.env)

Update the ISSUER and AUDIENCE variables in the .env file

ISSUER=https://example.oktapreview.com/oauth2/aus8o56xh1qncrlwT0h7
AUDIENCE=https://api.example.com

It is critical that the issuer and audience claims for JWT bearer tokens are properly validated using best practices. You can obtain these values from your OAuth 2.0 Authorization Server configuration.

The audience value should uniquely identify your AWS API Gateway deployment. You should assign unique audiences for each API Gateway authorizer instance so that a token intended for one gateway is not valid for another.

Signature Keys (keys.json)

Update keys.json with the JSON Web Key Set (JWKS) format for your issuer. You can usually obtain the JWKS for your issuer by fetching the jwks_uri published in your issuer's metadata such as ${issuer}/.well-known/openid-configuration.

The authorizer only supports RSA signature keys

Ensure that your issuer uses a pinned key for token signatures and does not automatically rotate signing keys. The authorizer currently does not support persistence of cached keys (e.g. dynamo) obtained via metadata discovery.

Deployment

Install Dependencies

Run npm install to download all of the authorizer's dependent modules. This is a prerequisite for deployment as AWS Lambda requires these files to be included in the uploaded bundle.

Create Bundle

There are several ways to deploy this lambda to AWS. This document won't go into those details, but you will need a bundle, so:

Run npm run bundle. This will create custom-authorizer.zip with all the source, configuration and node modules AWS Lambda needs.

Test your endpoint remotely

With Postman

You can use Postman to test the REST API

  • Method: < matching the Method in API Gateway >
  • URL https://<api-id>.execute-api.<region>.amazonaws.com/<stage>/<resource>
  • The base URL you can see in the Stages section of the API
  • Append the Resource name to get the full URL
  • Header - add an Authorization key
  • Authorization : Bearer

With curl from the command line

$ curl -X POST <url> -H 'Authorization: Bearer <token>'

In (modern) browsers console with fetch

fetch( '<url>', { method: 'POST', headers: { Authorization : 'Bearer <token>' }}).then(response => { console.log( response );});