skip to Main Content

I have a listUsers function which was working perfectly with cognito authorizer.

Since I’ve changed it to a Lambda Authorizer, it returns a 500 HTTP status code.

serverless.yml:

provider:
    httpApi:
        cors: true
        authorizers:
          customAuthorizer:
            type: request
            functionName: custom-authorizer
functions:
    custom-authorizer:
        handler: authorizer.handler

listUsers:
  handler: src/users/index.listUsersHandler
  events:
    - httpApi:
        path: /users
        method: get
        authorizer: customAuthorizer

authorizer.js:

const { CognitoJwtVerifier } = require('aws-jwt-verify');
const Cognito = require('../shared/Cognito');

module.exports.handler = async (event) => {
    const authHeader = event.headers.authorization;
    if (!authHeader) {
        console.log('No auth header');
        return {
            isAuthorized: false,
        };
    }
    const token = authHeader.split(' ')[1];
    console.log(token);
    const verifier = CognitoJwtVerifier.create({
        userPoolId: Cognito.UserPoolId,
        tokenUse: 'access',
        clientId: Cognito.ClientId,
    });
    let payload = null;
    try {
        payload = await verifier.verify(token);
        console.log('Token is valid. Payload:', payload);
        return {
            isAuthorized: true,
        };
    } catch {
        console.log('Token is invalid.');
        return { isAuthorized: false };
    }
};

When I make a GET request to /users it correctly redirects to my custom-authorizer & in the logs I can see that the token is valid.

However, it never runs the actual listUsers function and in Postman I get:

{
    "message": "Internal Server Error"
}

2

Answers


  1. Chosen as BEST ANSWER

    I fixed this by adding this:

    authorizers:
          customAuhtorizer:
             enableSimpleResponses: true
    

  2. The expected output of a Lambda authoriser is essentially a principal identifier & a policy document:

    • Effect: … Allow/Deny the API Gateway execution service
    • Action: … to invoke (execute-api:Invoke)
    • Resource: … the specified API method

    Therefore, the current Lambda authoriser response is completely incorrect, which is why you get an internal server error:

    return {isAuthorized: true};
    

    As a good starting point, use the methodArn property on the event object (event.methodArn) as the resource. This is the the ARN of the method that the caller is requesting, provided by AWS.

    This method will return a minimal but correct authoriser response:

    function generatePolicy(principalId, effect, resource) {
        return {
            principalId,
            policyDocument: {
                Version: '2012-10-17',
                Statement: [{
                    Action: 'execute-api:Invoke',
                    Effect: effect,
                    Resource: resource
                }]
            }
        };
    }
    

    Usage:

    const authHeader = event.headers.authorization;
    
    if (!authHeader) {
        console.log('No auth header');
        return generatePolicy('user', 'Deny', event.methodArn);
    }
    
    ...
    
    try {
        const payload = await verifier.verify(token);
        return generatePolicy('user', 'Allow', event.methodArn);
    } catch {
        return generatePolicy('user', 'Deny', event.methodArn);
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search