We launched new developer portal. For the latest documentation visit developer.cloudentity.com

Acquiring authentication context from Lambda Authorizers

Instructions on how to use the INJECT_CONTEXT variable to enable the services to retrieve authentication context from ACP's access tokens.

About getting authentication context data

If ACP is set to provide opaque access tokens as a mean of authenticating client applications that make requests to services deployed behind the AWS API Gateway, it is impossible to retrieve any information on the user from the token itself. Because of that ACP’s Lambda Authorizer can inject authentication context to additional Lambda Functions that retrieve the context passed from the authorizer.

In a traditional setup of AWS API Gateway and ACP’s AWS Lambda Authorizer, request transformation, response transformation and status code setting is done in the API Gateway. If your API gateway integration is set to Lambda Function and uses Lambda Proxy integration, your Lambda Function receives the whole request (such as query parameters, request body, and variables) including the authentication context passed by the AWS Lambda Authorizer. Additionally, the response is sent from your custom Lambda Function.

Using Lambda functions instead of the traditional setup is easier to configure. Both the status code and the response messages are in your custom Lambda control. You can prototype rapidly as you do not need to set up your API Gateway. Additionally, you can retrieve the information on the users from the AWS Lambda Authorizer and use them according to your needs.

Below, you can find a simplified diagram of the Lambda Authorizer - API Gateway - Lambda Proxy integration.

[mermaid-begin]
sequenceDiagram participant app as Client application participant gw as AWS API Gateway participant authz as ACP AWS Lambda Authorizer participant lambda as Lambda Proxy Function app->>gw: Request to /api gw->>authz: Invoke Lambda Authorizer authz->>gw: Enforce access control and inject authN context gw->>lambda: Proxy the request and provide authN context lambda->>app: Provide response and status code

When a client application makes a request to an API deployed behind the AWS API Gateway, the gateway invokes ACP AWS Lambda Authorizer that is responsible for policy decisioning and enforcing access control. After the authorizer responds to the gateway and injects authentication context to the response, the gateway proxies the request to the Lambda Function that is responsible for providing the request response and status codes.

Prerequisites

  1. You have an AWS console account with all required permissions to manage your Lambda Functions and API gateways.

  2. APIs are deployed behind your AWS API Gateway.

  3. You had set up access control enforcement for your APIs deployed behind the AWS API Gateway and use ACP’s Lambda Authorizer as described in the Protecting APIs deployed behind the AWS API Gateway article.

Retrieve authentication context from Lambda Authorizer

  1. In your AWS Management Console Lambda Authorizer’s settings, add the AWS_INJECT_CONTEXT environment variable with value set to true.

    AWS_INJECT_CONTEXT variable

    If the AWS_INJECT_CONTEXT variable is set to true, it is possible to inject base64-encoded authentication context to the target service in order to, for example, provide the target service with information on logged in user.

    To learn how to configure your environment variables for your authorizer, see the Create a function section, step 7.

    To learn about ACP AWS Lambda Authorizer configuration, see its configuration reference.

  2. Prepare a Lambda Function that will serve as your Lambda Proxy integration.

    Your custom Lambda Function should follow the guidelines present in the AWS Setting up Lambda custom integrations article. Adjust the event handler according to your needs. For example, you can provide your request responses and status codes.

    Below, you can find a simple example of a lambda_handler that responds with the HTTP 200 status code and dumps a JSON response body. The body includes the base64-encoded authentication context that the Lambda Function receives from the Lambda Authorizer.

    import json
    
    def lambda_handler(event, context):
    print(json.dumps(event))
    return {'statusCode': 200, 'body': json.dumps(event)}
    
  3. Go to your AWS API Gateway > Resources, choose a particular method and add an Integration Request.

    1. Set the integration type to Lambda Function.

    2. Enable the Use Lambda Proxy integration checkbox.

      Lambda Proxy integration

      The request to your APIs will be proxied to your Lambda Function that you created in the second step with the request details available in the event object of your handler function.

    3. Provide the identifier of your custom Lambda Function that you created in the second step as the value for the Lambda Function input field.

    AWS Custom Lambda Function integration

  4. Make a request to the API that you protect with the ACP AWS Lambda Authorizer and that you had applied with a custom Lambda Function integration.

If you used the custom lambda_handler Lambda Function provided in the second step, you can see that the request response contains the following response body in the JSON format:

                
                    
{
    "resource": "/",
    "path": "/",
    "httpMethod": "GET",
    "headers": {
        "Accept": "*/*",
        "Accept-Encoding": "gzip,deflate",
        "Authorization": "bearer {AT}",
        "Host": "v4npdwpiab.execute-api.us-east-1.amazonaws.com",
        "jaeger-baggage": "correlation-id=integration-tests-861d4f6a-c28a-438a-9497-349ee9d417ca",
        "X-Amzn-Trace-Id": "Root=1-5fbf8e67-0d372b7e46b9eb9b611d3a8f",
        "X-Forwarded-For": "54.172.92.11",
        "X-Forwarded-Port": "443",
        "X-Forwarded-Proto": "https"
    },
    "multiValueHeaders": {
        "Accept": [
        "*/*"
        ],
        "Accept-Encoding": [
        "gzip,deflate"
        ],
        "Authorization": [
        "bearer {AT}"
        ],
        "Host": [
        "v4npdwpiab.execute-api.us-east-1.amazonaws.com"
        ],
        "jaeger-baggage": [
        "correlation-id=integration-tests-861d4f6a-c28a-438a-9497-349ee9d417ca"
        ],
        "X-Amzn-Trace-Id": [
        "Root=1-5fbf8e67-0d372b7e46b9eb9b611d3a8f"
        ],
        "X-Forwarded-For": [
        "54.172.92.11"
        ],
        "X-Forwarded-Port": [
        "443"
        ],
        "X-Forwarded-Proto": [
        "https"
        ]
    },
    "queryStringParameters": null,
    "multiValueQueryStringParameters": null,
    "pathParameters": null,
    "stageVariables": null,
    "requestContext": {
        "resourceId": "is27l9o1a2",
        "authorizer": {
        "authnCtx": "eyJhY3IiOiIxIiwiYWlkIjoiZGVmYXVsdCIsImFtciI6WyJwd2QiXSwiYXVkIjpbImJ1dm9zbjg0bXEwZG52YzMwc2wwIiwic3BpZmZlOi8vZGV2LmFjcC5pbnQuY2xvdWRlbnRpdHkuY29tL3FreTFmemhnOG9vNmcxMGRseXFwL2RlZmF1bHQvYnV2b3NmODRtcTBkbnZjMzBydWciXSwiZXhwIjoxNjA2MzkyOTUwLCJpYXQiOjE2MDYzODkzNDksImlkcCI6ImRlZmF1bHQiLCJpc3MiOiJodHRwczovL2Rldi5hY3AuaW50LmNsb3VkZW50aXR5LmNvbTo4NDQzL3FreTFmemhnOG9vNmcxMGRseXFwL2RlZmF1bHQiLCJqdGkiOiJlNjcwZjQyMS1iMDQ3LTQ5MzItYTBiMi0zYTQzM2FkNzk0NjkiLCJuYmYiOjE2MDYzODkzNDksInNjcCI6WyJhbWF6b25fYXBpX3Njb3BlIl0sInN0IjoicHVibGljIiwic3ViIjoidXNlciIsInRpZCI6InFreTFmemhnOG9vNmcxMGRseXFwIn0=",
        "principalId": "user",
        "integrationLatency": 9637
        },
        "resourcePath": "/",
        "httpMethod": "GET",
        "extendedRequestId": "WnMwMGmXIAMFkgw=",
        "requestTime": "26/Nov/2020:11:15:51 +0000",
        "path": "/stage/",
        "accountId": "863611872174",
        "protocol": "HTTP/1.1",
        "stage": "stage",
        "domainPrefix": "v4npdwpiab",
        "requestTimeEpoch": 1606389351579,
        "requestId": "aea1cf05-c864-452c-a9cd-90ca90f992ae",
        "identity": {
        "cognitoIdentityPoolId": null,
        "accountId": null,
        "cognitoIdentityId": null,
        "caller": null,
        "sourceIp": "54.172.92.11",
        "principalOrgId": null,
        "accessKey": null,
        "cognitoAuthenticationType": null,
        "cognitoAuthenticationProvider": null,
        "userArn": null,
        "userAgent": null,
        "user": null
        },
        "domainName": "v4npdwpiab.execute-api.us-east-1.amazonaws.com",
        "apiId": "v4npdwpiab"
    },
    "body": null,
    "isBase64Encoded": false
    }

Under the requestContext and authorizer objects, you can find the base-64 encoded authentication context (authnCtx) that was passed firstly to your API Gateway and then proxied to your custom Lambda Function.

For demonstration purposes, you can decode the authentication context using, for example, the BASE64 decoder and encoder or a different online tool. If you need to, for example, modify the context in your Lambda Function or extract information for any purpose, you can decode the authentication context in your Lambda Function. Below, you can find an example of decoded authentication context.

                
                    
{
"acr": "1",
"aid": "default",
"amr": [
    "pwd"
],
"aud": [
    "buvosn84mq0dnvc30sl0",
    "spiffe://dev.acp.int.cloudentity.com/qky1fzhg8oo6g10dlyqp/default/buvosf84mq0dnvc30rug"
],
"exp": 1606392950,
"iat": 1606389349,
"idp": "default",
"iss": "https://dev.acp.int.cloudentity.com:8443/qky1fzhg8oo6g10dlyqp/default",
"jti": "e670f421-b047-4932-a0b2-3a433ad79469",
"nbf": 1606389349,
"scp": [
    "amazon_api_scope"
],
"st": "public",
"sub": "user",
"tid": "qky1fzhg8oo6g10dlyqp"
}