Use API Gateway Lambda authorizers - Amazon API Gateway

Use API Gateway Lambda authorizers

A Lambda authorizer (formerly known as a custom authorizer) is an API Gateway feature that uses a Lambda function to control access to your API.

A Lambda authorizer is useful if you want to implement a custom authorization scheme that uses a bearer token authentication strategy such as OAuth or SAML, or that uses request parameters to determine the caller's identity.

When a client makes a request to one of your API's methods, API Gateway calls your Lambda authorizer, which takes the caller's identity as input and returns an IAM policy as output.

There are two types of Lambda authorizers:

  • 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. For an example application, see Open Banking Brazil - Authorization Samples on GitHub.

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

    For WebSocket APIs, only request parameter-based authorizers are supported.

It is possible to use an AWS Lambda function from an AWS account that is different from the one in which you created your API. For more information, see Configure a cross-account Lambda authorizer.

For example Lambda functions, see aws-apigateway-lambda-authorizer-blueprints on GitHub.

Note

You can create a token-based Lambda authorizer that authenticates users using Amazon Cognito user pools and authorizes callers based on a policy store using Verified Permissions.

For more information, see Create a policy store with a connected API and identity provider in the Amazon Verified Permissions User Guide.

Lambda authorizer Auth workflow

The following diagram illustrates the authorization workflow for Lambda authorizers.


        API Gateway Lambda authorization workflow
API Gateway Lambda authorization workflow
  1. The client calls a method on an API Gateway API method, passing a bearer token or request parameters.

  2. API Gateway checks whether a Lambda authorizer is configured for the method. If it is, API Gateway calls the Lambda function.

  3. The Lambda function authenticates the caller by means such as the following:

    • Calling out to an OAuth provider to get an OAuth access token.

    • Calling out to a SAML provider to get a SAML assertion.

    • Generating an IAM policy based on the request parameter values.

    • Retrieving credentials from a database.

  4. If the call succeeds, the Lambda function grants access by returning an output object containing at least an IAM policy and a principal identifier.

  5. API Gateway evaluates the policy.

    • If access is denied, API Gateway returns a suitable HTTP status code, such as 403 ACCESS_DENIED.

    • If access is allowed, API Gateway invokes the method. If caching is enabled in the authorizer settings, API Gateway also caches the policy so that the Lambda authorizer function doesn't need to be invoked again.

  6. The call can fail if the Lambda function returns a 401 Unauthorized response. You can customize the 401 Unauthorized gateway response. To learn more, see Gateway responses in API Gateway.

Steps to create an API Gateway Lambda authorizer

To create a Lambda authorizer, you need to perform the following tasks:

  1. Create the Lambda authorizer function in the Lambda console as described in Create an API Gateway Lambda authorizer function in the Lambda console. You can use one of the blueprint examples as a starting point and customize the input and output as desired.

  2. Configure the Lambda function as an API Gateway authorizer and configure an API method to require it, as described in Configure a Lambda authorizer using the API Gateway console. Alternatively, if you need a cross-account Lambda authorizer, see Configure a cross-account Lambda authorizer.

    Note

    You can also configure an authorizer by using the AWS CLI or an AWS SDK.

  3. Test your authorizer by using Postman as described in Call an API with API Gateway Lambda authorizers.

Create an API Gateway Lambda authorizer function in the Lambda console

Before configuring a Lambda authorizer, you must first create the Lambda function that implements the logic to authorize and, if necessary, to authenticate the caller. The Lambda console provides a Python blueprint, which you can use by choosing Use a blueprint and choosing the api-gateway-authorizer-python blueprint. Otherwise, you'll want to use one of the blueprints in the awslabs GitHub repository as a starting point.

For the example Lambda authorizer functions in this section, which don't call other services, you can use the built-in AWSLambdaBasicExecutionRole. When creating the Lambda function for your own API Gateway Lambda authorizer, you'll need to assign an IAM execution role to the Lambda function if it calls other AWS services. To create the role, follow the instructions in AWS Lambda Execution Role.

For more example Lambda functions, see aws-apigateway-lambda-authorizer-blueprints on GitHub. For an example application, see Open Banking Brazil - Authorization Samples on GitHub.

EXAMPLE: Create a token-based Lambda authorizer function

To create a token-based Lambda authorizer function, enter the following Node.js code for the most recent runtime in the Lambda console. Then, you test the authorizer in the API Gateway console.

To create the token-based Lambda authorizer function
  1. In the Lambda console, choose Create function.

  2. Choose Author from scratch.

  3. Enter a name for the function.

  4. For Runtime, choose either the latest supported Node.js or Python runtime.

  5. Choose Create function.

  6. Copy/paste the following code into the code editor.

    Node.js
    // A simple token-based authorizer example to demonstrate how to use an authorization token // to allow or deny a request. In this example, the caller named 'user' is allowed to invoke // a request if the client-supplied token value is 'allow'. The caller is not allowed to invoke // the request if the token value is 'deny'. If the token value is 'unauthorized' or an empty // string, the authorizer function returns an HTTP 401 status code. For any other token value, // the authorizer returns an HTTP 500 status code. // Note that token values are case-sensitive. export const handler = function(event, context, callback) { var token = event.authorizationToken; switch (token) { case 'allow': callback(null, generatePolicy('user', 'Allow', event.methodArn)); break; case 'deny': callback(null, generatePolicy('user', 'Deny', event.methodArn)); break; case 'unauthorized': callback("Unauthorized"); // Return a 401 Unauthorized response break; default: callback("Error: Invalid token"); // Return a 500 Invalid token response } }; // Help function to generate an IAM policy var generatePolicy = function(principalId, effect, resource) { var authResponse = {}; authResponse.principalId = principalId; if (effect && resource) { var policyDocument = {}; policyDocument.Version = '2012-10-17'; policyDocument.Statement = []; var statementOne = {}; statementOne.Action = 'execute-api:Invoke'; statementOne.Effect = effect; statementOne.Resource = resource; policyDocument.Statement[0] = statementOne; authResponse.policyDocument = policyDocument; } // Optional output with custom properties of the String, Number or Boolean type. authResponse.context = { "stringKey": "stringval", "numberKey": 123, "booleanKey": true }; return authResponse; }
    Python
    # A simple token-based authorizer example to demonstrate how to use an authorization token # to allow or deny a request. In this example, the caller named 'user' is allowed to invoke # a request if the client-supplied token value is 'allow'. The caller is not allowed to invoke # the request if the token value is 'deny'. If the token value is 'unauthorized' or an empty # string, the authorizer function returns an HTTP 401 status code. For any other token value, # the authorizer returns an HTTP 500 status code. # Note that token values are case-sensitive. import json def lambda_handler(event, context): token = event['authorizationToken'] if token == 'allow': print('authorized') response = generatePolicy('user', 'Allow', event['methodArn']) elif token == 'deny': print('unauthorized') response = generatePolicy('user', 'Deny', event['methodArn']) elif token == 'unauthorized': print('unauthorized') raise Exception('Unauthorized') # Return a 401 Unauthorized response return 'unauthorized' try: return json.loads(response) except BaseException: print('unauthorized') return 'unauthorized' # Return a 500 error def generatePolicy(principalId, effect, resource): authResponse = {} authResponse['principalId'] = principalId if (effect and resource): policyDocument = {} policyDocument['Version'] = '2012-10-17' policyDocument['Statement'] = [] statementOne = {} statementOne['Action'] = 'execute-api:Invoke' statementOne['Effect'] = effect statementOne['Resource'] = resource policyDocument['Statement'] = [statementOne] authResponse['policyDocument'] = policyDocument authResponse['context'] = { "stringKey": "stringval", "numberKey": 123, "booleanKey": True } authResponse_JSON = json.dumps(authResponse) return authResponse_JSON
  7. Choose Deploy.

After you create your Lambda function, you create and test a token-based Lambda authorizer in the API Gateway console.

To create a token-based Lambda authorizer
  1. In the API Gateway console, create a simple API if you don't already have one.

  2. Choose your API from the API list.

  3. Choose Authorizers.

  4. Choose Create authorizer.

  5. For Authorizer name, enter a name.

  6. For Authorizer type, select Lambda.

  7. For Lambda function, select the AWS Region where you created your Lambda authorizer function, and then enter the function name.

  8. Keep Lambda invoke role blank.

  9. For Lambda event payload, select Token.

  10. For Token source, enter authorizationToken.

  11. Choose Create authorizer.

To test your authorizer
  1. Select the name of the authorizer.

  2. Under Test authorizer, for the authorizationToken value, enter allow.

  3. Choose Test authorizer.

In this example, when the API receives a method request, API Gateway passes the source token to this Lambda authorizer function in the event.authorizationToken attribute. The Lambda authorizer function reads the token and acts as follows:

  • If the token value is 'allow', the test of the authorizer function returns a 200 OK HTTP response and an IAM policy that looks like the following, and the method request succeeds:

    { "Version": "2012-10-17", "Statement": [ { "Action": "execute-api:Invoke", "Effect": "Allow", "Resource": "arn:aws:execute-api:us-east-1:123456789012:ivdtdhp7b5/ESTestInvoke-stage/GET/" } ] }
  • If the token value is 'deny', the test of the authorizer function returns a 200 OK HTTP response and a Deny IAM policy that looks like the following, and the method request fails:

    { "Version": "2012-10-17", "Statement": [ { "Action": "execute-api:Invoke", "Effect": "Deny", "Resource": "arn:aws:execute-api:us-east-1:123456789012:ivdtdhp7b5/ESTestInvoke-stage/GET/" } ] }
    Note

    Outside of the test environment, the authorizer function returns a 403 Forbidden HTTP response and the method request fails.

  • If the token value is 'unauthorized' or an empty string, the test of the authorizer function returns a 401 Unauthorized HTTP response, and the method call fails.

  • If the token is anything else, the client receives a 500 Invalid token response, and the method call fails.

Note

In production code, you may need to authenticate the user before granting authorization. If so, you can add authentication logic in the Lambda function as well by calling an authentication provider as directed in the documentation for that provider.

In addition to returning an IAM policy, the Lambda authorizer function must also return the caller's principal identifier. It can also optionally return a context object containing additional information that can be passed into the integration backend. For more information, see Output from an Amazon API Gateway Lambda authorizer.

EXAMPLE: Create a request-based Lambda authorizer function

To create a request-based Lambda authorizer function, enter the following Node.js code for the most recent runtime in the Lambda console. Then, you test the authorizer in the API Gateway console.

  1. In the Lambda console, choose Create function.

  2. Choose Author from scratch.

  3. Enter a name for the function.

  4. For Runtime, choose either the latest supported Node.js or Python runtime.

  5. Choose Create function.

  6. Copy/paste the following code into the code editor.

    Node.js
    // A simple request-based authorizer example to demonstrate how to use request // parameters to allow or deny a request. In this example, a request is // authorized if the client-supplied headerauth1 header, QueryString1 // query parameter, and stage variable of StageVar1 all match // specified values of 'headerValue1', 'queryValue1', and 'stageValue1', // respectively. export const handler = function(event, context, callback) { console.log('Received event:', JSON.stringify(event, null, 2)); // Retrieve request parameters from the Lambda function input: var headers = event.headers; var queryStringParameters = event.queryStringParameters; var pathParameters = event.pathParameters; var stageVariables = event.stageVariables; // Parse the input for the parameter values var tmp = event.methodArn.split(':'); var apiGatewayArnTmp = tmp[5].split('/'); var awsAccountId = tmp[4]; var region = tmp[3]; var restApiId = apiGatewayArnTmp[0]; var stage = apiGatewayArnTmp[1]; var method = apiGatewayArnTmp[2]; var resource = '/'; // root resource if (apiGatewayArnTmp[3]) { resource += apiGatewayArnTmp[3]; } // Perform authorization to return the Allow policy for correct parameters and // the 'Unauthorized' error, otherwise. var authResponse = {}; var condition = {}; condition.IpAddress = {}; if (headers.headerauth1 === "headerValue1" && queryStringParameters.QueryString1 === "queryValue1" && stageVariables.StageVar1 === "stageValue1") { callback(null, generateAllow('me', event.methodArn)); } else { callback("Unauthorized"); } } // Help function to generate an IAM policy var generatePolicy = function(principalId, effect, resource) { // Required output: var authResponse = {}; authResponse.principalId = principalId; if (effect && resource) { var policyDocument = {}; policyDocument.Version = '2012-10-17'; // default version policyDocument.Statement = []; var statementOne = {}; statementOne.Action = 'execute-api:Invoke'; // default action statementOne.Effect = effect; statementOne.Resource = resource; policyDocument.Statement[0] = statementOne; authResponse.policyDocument = policyDocument; } // Optional output with custom properties of the String, Number or Boolean type. authResponse.context = { "stringKey": "stringval", "numberKey": 123, "booleanKey": true }; return authResponse; } var generateAllow = function(principalId, resource) { return generatePolicy(principalId, 'Allow', resource); } var generateDeny = function(principalId, resource) { return generatePolicy(principalId, 'Deny', resource); }
    Python
    # A simple request-based authorizer example to demonstrate how to use request # parameters to allow or deny a request. In this example, a request is # authorized if the client-supplied headerauth1 header, QueryString1 # query parameter, and stage variable of StageVar1 all match # specified values of 'headerValue1', 'queryValue1', and 'stageValue1', # respectively. import json def lambda_handler(event, context): print(event) # Retrieve request parameters from the Lambda function input: headers = event['headers'] queryStringParameters = event['queryStringParameters'] pathParameters = event['pathParameters'] stageVariables = event['stageVariables'] # Parse the input for the parameter values tmp = event['methodArn'].split(':') apiGatewayArnTmp = tmp[5].split('/') awsAccountId = tmp[4] region = tmp[3] restApiId = apiGatewayArnTmp[0] stage = apiGatewayArnTmp[1] method = apiGatewayArnTmp[2] resource = '/' if (apiGatewayArnTmp[3]): resource += apiGatewayArnTmp[3] # Perform authorization to return the Allow policy for correct parameters # and the 'Unauthorized' error, otherwise. authResponse = {} condition = {} condition['IpAddress'] = {} if (headers['HeaderAuth1'] == "headerValue1" and queryStringParameters['QueryString1'] == "queryValue1" and stageVariables['StageVar1'] == "stageValue1"): response = generateAllow('me', event['methodArn']) print('authorized') return json.loads(response) else: print('unauthorized') raise Exception('Unauthorized') # Return a 401 Unauthorized response return 'unauthorized' # Help function to generate IAM policy def generatePolicy(principalId, effect, resource): authResponse = {} authResponse['principalId'] = principalId if (effect and resource): policyDocument = {} policyDocument['Version'] = '2012-10-17' policyDocument['Statement'] = [] statementOne = {} statementOne['Action'] = 'execute-api:Invoke' statementOne['Effect'] = effect statementOne['Resource'] = resource policyDocument['Statement'] = [statementOne] authResponse['policyDocument'] = policyDocument authResponse['context'] = { "stringKey": "stringval", "numberKey": 123, "booleanKey": True } authResponse_JSON = json.dumps(authResponse) return authResponse_JSON def generateAllow(principalId, resource): return generatePolicy(principalId, 'Allow', resource) def generateDeny(principalId, resource): return generatePolicy(principalId, 'Deny', resource)
  7. Choose Deploy.

After you create your Lambda function, you create and test a request-based Lambda authorizer in the API Gateway console.

To create a request-based Lambda authorizer
  1. In the API Gateway console, create a simple API if you don't already have one.

  2. Choose your API from the API list.

  3. Choose Authorizers.

  4. Choose Create authorizer.

  5. For Authorizer name, enter a name.

  6. For Authorizer type, select Lambda.

  7. For Lambda function, select the AWS Region where you created your Lambda authorizer function, and then enter the function name.

  8. Keep Lambda invoke role blank.

  9. For Lambda event payload, select Request.

  10. Under Identity source type, enter the following:

    1. Select Header and enter headerauth1, and then choose Add parameter.

    2. Under Identity source type, select Query string and enter QueryString1, and then choose Add parameter.

    3. Under Identity source type, select Stage variable and enter StageVar1.

  11. Choose Create authorizer.

To test your authorizer
  1. Select the name of the authorizer.

  2. Under Test authorizer, enter the following:

    1. Select Header and enter headerValue1, and then choose Add parameter.

    2. Under Identity source type, select Query string and enter queryValue1, and then choose Add parameter.

    3. Under Identity source type, select Stage variable and enter stageValue1.

    You can't modify the context variables for the test invocation, but you can modify the API Gateway Authorizer test event template for your Lambda function. Then, you can test your Lambda authorizer function with modified context variables. For more information, see Testing Lambda functions in the console in the AWS Lambda Developer Guide.

  3. Choose Test authorizer.

In this example, the Lambda authorizer function checks the input parameters and acts as follows:

  • If all the required parameter values match the expected values, the authorizer function returns a 200 OK HTTP response and an IAM policy that looks like the following, and the method request succeeds:

    { "Version": "2012-10-17", "Statement": [ { "Action": "execute-api:Invoke", "Effect": "Allow", "Resource": "arn:aws:execute-api:us-east-1:123456789012:ivdtdhp7b5/ESTestInvoke-stage/GET/" } ] }
  • Otherwise, the authorizer function returns a 401 Unauthorized HTTP response, and the method call fails.

Note

In production code, you may need to authenticate the user before granting authorization. If so, you can add authentication logic in the Lambda function as well by calling an authentication provider as directed in the documentation for that provider.

In addition to returning an IAM policy, the Lambda authorizer function must also return the caller's principal identifier. It can also optionally return a context object containing additional information that can be passed into the integration backend. For more information, see Output from an Amazon API Gateway Lambda authorizer.