nicoes
nicoes

Reputation: 93

Only add header on proxied API Gateway request with Lambda authorizer

At the moment I have an architecture in mind with AWS ApiGateway + Lambda for server HTML based on if a user is properly authenticated or not. I am trying to achieve this Cognito and a custom Lambda Authorizer. I'd like my Lambda to always return HTML and based on the cookie that is passed, generate HTML for a logged in / logged out state. In my mind that would be ideal to have a separate authorizer that does the token validation and pass a header to the HTML generating Lambda.

How can one achieve this?

I'm using AWS Sam template to define my CF stack. See my current template:

AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Description: A Lambda function for rendering HTML pages with authentication
Resources:
  WebAppGenerator:
    Type: 'AWS::Serverless::Function'
    Properties:
      Handler: app.handler
      Runtime: nodejs12.x
      CodeUri: .
      Description: A Lambda that generates HTML pages dynamically
      MemorySize: 128
      Timeout: 20
      Events:
        ProxyRoute:
          Type: Api
          Properties:
            RestApiId: !Ref WebAppApi
            Path: /{proxy+}
            Method: GET
  WebAppApi:
    Type: AWS::Serverless::Api
    Properties:
      StageName: Prod
      Auth:
        DefaultAuthorizer: WebTokenAuthorizer
        Authorizers:
          WebTokenAuthorizer:
            FunctionArn: !GetAtt WebAppTokenAuthorizer.Arn
  WebAppTokenAuthorizer:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: .
      Handler: authorizer.handler
      Runtime: nodejs12.x

In my authorizer (Typescript) I was thinking of generating a policy that always has an 'allow' effect. But if an authorization token (not cookie-based yet) is missing, it's already returning a 403. See:


function generatePolicy(principalId: string, isAuthorized: boolean, resource): APIGatewayAuthorizerResult {
    const result: APIGatewayAuthorizerResult = {
        principalId,
        policyDocument: {
            Version: '2012-10-17',
            Statement: []
        }
    };

    if (resource) {
        result.policyDocument.Statement[0] = {
            Action: 'execute-api:Invoke',
            Effect: 'Allow',
            Resource: resource
        };
    }

    result.context = {
        isAuthorized
    };

    return result
}

Upvotes: 0

Views: 1121

Answers (2)

Ari Waisberg
Ari Waisberg

Reputation: 1303

You cannot change the headers directly in the Authorizer Lambda... I achieved this using a Middleware in the lambdas and catching the "After" event...

You can check a popular middleware for lambdas: Middy

Upvotes: 0

Ashan
Ashan

Reputation: 19748

With Custom Authorizer, I'm not sure whether the functionality you mentioned is directly possible to achieve.

Can you check whether you can define a mapping template with content type text/html, following this guide? (Make sure your Lambda integration is not a proxy integration)

However, there are two alternative approaches that would work, if it's an option to you.

  • Use AWS Cloudfront, infront of API Gateway and configure error responses to show a HTML based on error status code.
  • Use Lambda Layers to authorize and decide on the response.

Upvotes: 0

Related Questions