Search code examples
node.jsaws-lambdaaws-api-gatewayamazon-cognitoaws-amplify

Cognito "Authorizer" element not appearing in RequestContext in a Lambda triggered via API Gateway


Possibly inexperience with the AWS/Amplify side: I have an app built using Amplify, where I have a userbase controlled with Cognito. In my Cognito user pool I have created a custom attribute, that I want to pass to my API to be used in custom logic. I have access to that custom attribute in the front-end, but for security concerns I do not want to expose it there.

In my app I am calling my resource in my API Gateway:

let restCall = post({
        apiName: MY_API_NAME,
        path: "/MY_PATH",
        options: {body : parameters},
        headers: {"Authorization": "user_ID_Token"}
    });

    const {body} = await restCall.response;

I am using my Cognito Pool as an authorizer for that resource. "Authorization" is the authentication header I've defined as per this guide, and "user_ID_Token" is the attribute I get when calling "fetchAuthSession().tokens.idToken" which I (believe) am using to authorize the call.

This then calls my lambda that is triggered via this request

In it, I have the below code the logs out the request context:

app.post('/MY_PATH', async function(req, res) {

console.log(`requestContext ${JSON.stringify(req.apiGateway)}`);
console.log(`requestContext ${JSON.stringify(req.apiGateway.event.requestContext)}`);

From other resources I have seen, I would expect the "req.apiGateway.event.requestContext" to contain an "authorizer" object, under which would be a "claims" object that then contains details of my user, including attributes. I'm aware there are some steps required to get the specific custom attributes I want in there, but my issue is that there is no authorizer object in the first place! Below is an extract from a recent log in cloudwatch for that lmabda

"requestContext": {
            "resourceId": "xxx",
            "resourcePath": "/MY_PATH",
            "httpMethod": "POST",
            "extendedRequestId": "xxx=",
            "requestTime": "25/Jun/2024:14:54:00 +0000",
            "path": "/dev/MY_PATH",
            "accountId": "xxx",
            "protocol": "HTTP/1.1",
            "stage": "dev",
            "domainPrefix": "xxx",
            "requestTimeEpoch": 1719327240217,
            "requestId": "xx",
            "identity": {
                "cognitoIdentityPoolId": null,
                "accountId": null,
                "cognitoIdentityId": null,
                "caller": null,
                "sourceIp": "51.198.135.75",
                "principalOrgId": null,
                "accessKey": null,
                "cognitoAuthenticationType": null,
                "cognitoAuthenticationProvider": null,
                "userArn": null,
                "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36",
                "user": null
            },
            "domainName": "xo92e4470h.execute-api.eu-north-1.amazonaws.com",
            "deploymentId": "sa27pp",
            "apiId": "xo92e4470h"
        },

I note that cognitoIdentityPoolId is null, however I am unsure of the relevance.

Can anyone shed any light on what I'm missing to expose the attributes of the calling user to the API that is being called?

I was epxecting to get an "authorizer" object in lambda requestContext logs, but none appears, even after setting cognito authorizer in API Gateway.


Solution

  • The post method does not take a "headers" parameter how you would normally expect, headers instead goes as in as a key in the options object instead

    post({
            apiName: MY_API_NAME,
            path: "/MY_PATH",
            options: { 
                body: params,
                headers
            },
        });
    

    Thankfully a simple (albeit silly) mistake