401 return from an API Gateway Custom Authorizer is missing 'Access-Control-Allow-Origin' header

Amazon Web-ServicesCorsAws LambdaAws Api-Gateway

Amazon Web-Services Problem Overview


In order to prevent users who have not logged in to call my lambda function through the AWS API Gateway, I'm using the Custom Authorizer lambda solution.

If the request is authorized (200) and I get a response from the called lambda everything works fine and I get the Access-Control-Allow-Origin header.

But if the request is not authorized, I get a 401 that has no Access-Control-Allow-Origin header, therefore preventing me from reading the 401 status of the response and redirecting the user to the log-in page.

I believe this is because the Custom Autorization mechanism is unaware that the request needs to use CORS. Does anyone know that this is actually the issue? Are you aware of any possible solution?

Amazon Web-Services Solutions


Solution 1 - Amazon Web-Services

I'm happy to announce the new Gateway Responses feature which allows you to customize the error responses for requests that don't call your integration. This allows you to ensure that CORS headers are included, even on failed auth requests.

Read more in our documentation, which includes a CORS example.

Solution 2 - Amazon Web-Services

Yes, this is a known bug with API Gateway custom authorizers. Thanks for bringing this to our attention. The team will update this post when we've deployed a fix. Apologies for the inconvenience.

Solution 3 - Amazon Web-Services

The easiest way to resolve this for all 4XX error (including 401 errors) is to go to "Gateway Responses" and then select "Default 4XX" and then add the the header "Access-Control-Allow-Origin" with the value '*'.

See screenshot:

Solution 4 - Amazon Web-Services

This works for me (inline in AWS::APIGateway: definition)

Resources:
  MyApi:
    Type: AWS::Serverless::Api
    Properties:
      StageName: Dev
      GatewayResponses:
        UNAUTHORIZED:
          StatusCode: 401
          ResponseParameters:
            Headers:
              Access-Control-Allow-Origin: "'*'"
        ACCESS_DENIED:
          StatusCode: 403
          ResponseParameters:
            Headers:
              Access-Control-Allow-Origin: "'*'"
        DEFAULT_5XX:
          StatusCode: 500
          ResponseParameters:
            Headers:
              Access-Control-Allow-Origin: "'*'"
        RESOURCE_NOT_FOUND:
          StatusCode: 404
          ResponseParameters:
            Headers:
              Access-Control-Allow-Origin: "'*'"  

The available GatewayResponses Naming are:

DEFAULT_INTERNAL
DEFAULT_4XX
DEFAULT_5XX
RESOURCE_NOT_FOUND
UNAUTHORIZED
ACCESS_DENIED
AUTHORIZER_FAILURE
AUTHORIZER_CONFIGURATION_ERROR
MISSING_AUTHENTICATION_TOKEN
INVALID_SIGNATURE
EXPIRED_TOKEN
INTEGRATION_FAILURE
INTEGRATION_TIMEOUT
API_CONFIGURATION_ERROR
UNSUPPORTED_MEDIA_TYPE
REQUEST_TOO_LARGE
BAD_REQUEST_PARAMETERS
BAD_REQUEST_BODY
THROTTLED
QUOTA_EXCEEDED
INVALID_API_KEY
WAF_FILTERED

So you could specify the Response customization for these Controlled AWS responses.

Solution 5 - Amazon Web-Services

Because it took me a while to figure out how to put it all together in Cloud Formation, here is a snippet showing how to set it up.

...
    MyApi:
      Type: "AWS::ApiGateway::MyApi"
      Properties:
        Description: My API
        Name: "my-api"
    MyApiAuthorizer:
      Type: "AWS::ApiGateway::Authorizer"
      Properties:
         Name: "my-api-authorizer"
         IdentitySource: "method.request.header.Authorization"
         ProviderARNs:
           - !GetAtt MyUserPool.Arn
         RestApiId: !Ref MyAApi
         Type: COGNITO_USER_POOLS
    MyApiGatewayResponse:
      Type: "AWS::ApiGateway::GatewayResponse"
      Properties:
        ResponseParameters:
          "gatewayresponse.header.Access-Control-Allow-Origin": "'*'"
          "gatewayresponse.header.Access-Control-Allow-Headers": "'*'"
        ResponseType: UNAUTHORIZED
        RestApiId: !Ref MyApi
        StatusCode: "401"
          

Solution 6 - Amazon Web-Services

If, like me, you are running into problems with API Gateway V2, specifically with an HTTP API - the ANY method doesn't seem to work with the plug and play CORS offering. I had to individually create a route for each method (annoying because they all call the same lambda function, but oh well).

Solution 7 - Amazon Web-Services

Adding to the answers above, if you're not using Cloudformation/SAM template, you can save yourself some manual steps using this python script:

import boto3
import sys

if len(sys.argv) != 3:
    print("usage: python script.py <API_ID> <STAGE>")
    exit()

client = boto3.client('apigateway')

response = client.put_gateway_response(
    restApiId=sys.argv[1],
    responseType='UNAUTHORIZED',
    statusCode='401',
    responseParameters={
        "gatewayresponse.header.Access-Control-Allow-Origin": "'*'",
        "gatewayresponse.header.Access-Control-Allow-Headers": "'*'"
    }
)
response = client.create_deployment(
    restApiId=sys.argv[1],
    stageName=sys.argv[2])

Solution 8 - Amazon Web-Services

To fix this for our SPA (we are using AWS Cognito authorizer) we added the next Response Headers in DEFAULT 4xxx and DEFAULT 5xxx Gateway responses:

Access-Control-Allow-Origin '{url_of_your_front-end}'
Access-Control-Allow-Headers '{url_of_your_front-end}'

we set {url_of_your_front-end} instead of '*', because the browser didn't like it :D

as an additional we set Access-Control-Allow-Credentials 'true' header to make a browser happy.

Picture with all headers

Solution 9 - Amazon Web-Services

Adding the response header "Access-Control-Allow-Origin" for the Unauthorized response should fix this issue

  • Select the Api
  • Select the Gateway Responses
  • Select Unauthorized
  • Edit the response header and add Access-Control-Allow-Origin with value "*"

enter image description here

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionhanbzuView Question on Stackoverflow
Solution 1 - Amazon Web-ServicesBob KinneyView Answer on Stackoverflow
Solution 2 - Amazon Web-ServicesLorenzo de LaraView Answer on Stackoverflow
Solution 3 - Amazon Web-ServicesAlex RobinsonView Answer on Stackoverflow
Solution 4 - Amazon Web-ServicesdanipenaperezView Answer on Stackoverflow
Solution 5 - Amazon Web-ServicespisomojadoView Answer on Stackoverflow
Solution 6 - Amazon Web-ServicesConrad SView Answer on Stackoverflow
Solution 7 - Amazon Web-ServicesamshView Answer on Stackoverflow
Solution 8 - Amazon Web-ServicesOlegMaksimovichView Answer on Stackoverflow
Solution 9 - Amazon Web-ServicesNgen CMSView Answer on Stackoverflow