aws / aws-lambda-go

Libraries, samples and tools to help Go developers develop AWS Lambda functions.
Apache License 2.0
3.6k stars 548 forks source link

Handler events.APIGatewayProxyRequest Cognito fields empty #133

Open jackwellsxyz opened 5 years ago

jackwellsxyz commented 5 years ago

I've deployed an API Gateway that calls a lambda_proxy handler. My handler function receives in a context and an events.APIGatewayProxyRequest. Inside the request, there are fields for the Cognito Identity ID and Pool ID, but both are empty. This may be related to Issue #106. While I saw a workaround to manually verify JWTs, that would seem to largely defeat the purpose of API Gateway Cognito authentication and certainly the request's cognito fields.

Code to reproduce the error:

package main

func Handler(ctx context.Context, request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
    lc, _ := lambdacontext.FromContext(ctx)

    fmt.Println("Context cognito identity id:", lc.Identity.CognitoIdentityID)
    fmt.Println("Context Cognito pool:", lc.Identity.CognitoIdentityPoolID)
    fmt.Println("Request context cognito id:", request.RequestContext.Identity.CognitoIdentityID)

    return events.APIGatewayProxyResponse{}, nil
}

func main() {
  lambda.Start(Handler)
}

I also dug into the aws-lambda-go/lambda/function.go Invoke() function and verified that the req.CognitoIdentityID and req.CognitoIdentityPoolId are both empty strings. I verified this using a deployed Lambda function that I tested using API Gateway and Postman (with valid JWT Cognito tokens) using Printlns also in the function.go Invoke() function.

piotrkubisa commented 5 years ago

Whether you define AuthorizationType in API Gateway method as a COGNITO_USER_POOLS then you don't need write logic to validate JWT by yourself. Below an extract from CloudFormation template written in yaml syntax:

# snip...

  ApiGatewayMethodCreateItem:
    Type: AWS::ApiGateway::Method
    Properties:
      RestApiId: !Ref ApiGatewayApi
      ResourceId: !GetAtt ApiGatewayApi.RootResourceId
      HttpMethod: POST
      AuthorizationType: "COGNITO_USER_POOLS"
      AuthorizerId: !Ref ApiGatewayAuthorizer
      Integration:
        Type: AWS_PROXY
        IntegrationHttpMethod: POST
        Uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${LambdaFunction.Arn}/invocations

  ApiGatewayAuthorizer:
    Type: AWS::ApiGateway::Authorizer
    Properties:
      Name: !Sub "${AWS::StackName}-authorizer"
      Type: "COGNITO_USER_POOLS"
      ProviderARNs:
        - Fn::Sub:
          - "arn:aws:cognito-idp:${AWS::Region}:${AWS::AccountId}:userpool/${UserPool}"
          - UserPool: "XXXXX"
      IdentitySource: "method.request.header.Authorization"
      RestApiId: !Ref ApiGatewayApi

  LambdaApiGatewayExecutionPermission:
    Type: AWS::Lambda::Permission
    Properties:
      Action: lambda:InvokeFunction
      FunctionName: !GetAtt LambdaFunction.Arn
      Principal: apigateway.amazonaws.com
      SourceArn: !Sub "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${ApiGatewayApi}/*/*"

If do recall correctly, also request.RequestContext.Identity.CognitoIdentityID (and other fields related to Cognito) are populated whether you use AuthorizationType: "AWS_IAM" and you are using the IAM keys obtained from AWS Cognito Identity Pool.