FettFrank
FettFrank

Reputation: 279

CDK API Gateway default authorizer exclude OPTIONS method

I'm creating a LambdaRestApi in CDK and I want to have both CORS enabled and add an ANY proxy using the addProxy method.

I currently have the following CDK code:

  const api = new LambdaRestApi(...); // This API has CORS enabled in defaultCorsPreflightOptions
  const apiProxy = api.root.addProxy({
      defaultMethodOptions: {
        authorizationType: AuthorizationType.COGNITO,
        authorizer: new CognitoUserPoolsAuthorizer(...),
     }
  }); 

The problem I'm running into is that while a proxy is created with the ANY method, it also sets the OPTIONS method to require authentication. I tried to add an OPTIONS method to the proxy using addMethod to override the authorizer but I get an error that there's already a construct with the same name. I'm also trying to avoid having to set the anyMethod field in the proxy to be false and adding my own methods. Is there a way in the API Gateway CDK to set the default authorizer to only work for any method except the OPTIONS method?

Upvotes: 3

Views: 4380

Answers (2)

gustf
gustf

Reputation: 2017

There is also a possibility to remove the auth explicitly on the OPTIONS method, here I also remove requirement for X-API-Key in the requests

    const lambdaApi = new apigateway.LambdaRestApi(...) // This API has CORS enabled in defaultCorsPreflightOptions

    lambdaApi.methods
      .filter((method) => method.httpMethod === "OPTIONS")
      .forEach((method) => {
        const methodCfn = method.node.defaultChild as apigateway.CfnMethod;
        methodCfn.authorizationType = apigateway.AuthorizationType.NONE;
        methodCfn.authorizerId = undefined;
        methodCfn.authorizationScopes = undefined;
        methodCfn.apiKeyRequired = false;
      });

Upvotes: 3

edurogk
edurogk

Reputation: 21

I ran into the same issue when building a RestApi using the aws cdk. Here is a workaround where you can build the api piece by piece.

  1. Declare the api construct without the defaultCorsPreflightOptions property, otherwise you will not be able to override Authorization on the OPTIONS method.
import * as apigateway from '@aws-cdk/aws-apigateway';
import * as lambda from '@aws-cdk/aws-lambda';

const restAPI = new apigateway.RestApi(this, "sample-api");
  1. Add your resources and methods. In this case, I want to add an ANY method with a custom authorizer on the "data" resource. You can do this with any other supported authorization mechanism. The proxy handler is a lambda function created with NodeJs.
const dataProxyLambdaFunction = new lambda.Function(this, "data-handler", {
        code: lambda.Code.fromBucket(S3CODEBUCKET, "latest/js_data.zip"),
        handler: "index.handler",
        runtime: lambda.Runtime.NODEJS_14_X
    });

const dataProxy = restAPI.root.addResource("data")
        .addResource("{proxy+}");

dataProxy.addMethod("ANY", new apigateway.LambdaIntegration(dataProxyLambdaFunction , { 
        allowTestInvoke: true,
    }), { authorizationType: apigateway.AuthorizationType.CUSTOM, authorizer: customLambdaRequestAuthorizer });

  1. Now, you can add an OPTIONS method to this proxy, without authorization. I used a standardCorsMockIntegration and optionsMethodResponse object to reuse with other methods in my api.
const ALLOWED_HEADERS = ['Content-Type', 'X-Amz-Date', 'X-Amz-Security-Token', 'Authorization', 'X-Api-Key', 'X-Requested-With', 'Accept', 'Access-Control-Allow-Methods', 'Access-Control-Allow-Origin', 'Access-Control-Allow-Headers'];

const standardCorsMockIntegration = new apigateway.MockIntegration({
        integrationResponses: [{
          statusCode: '200',
          responseParameters: {
            'method.response.header.Access-Control-Allow-Headers': `'${ALLOWED_HEADERS.join(",")}'`,
            'method.response.header.Access-Control-Allow-Origin': "'*'",
            'method.response.header.Access-Control-Allow-Credentials': "'false'",
            'method.response.header.Access-Control-Allow-Methods': "'OPTIONS,GET,PUT,POST,DELETE'",
          },
        }],
        passthroughBehavior: apigateway.PassthroughBehavior.NEVER,
        requestTemplates: {
          "application/json": "{\"statusCode\": 200}"
        }
    });

const optionsMethodResponse = {
        statusCode: '200',
        responseModels: {
            'application/json': apigateway.Model.EMPTY_MODEL 
        },
        responseParameters: {
            'method.response.header.Access-Control-Allow-Headers': true,
            'method.response.header.Access-Control-Allow-Methods': true,
            'method.response.header.Access-Control-Allow-Credentials': true,
            'method.response.header.Access-Control-Allow-Origin': true,
        }
};

dataProxy.addMethod("OPTIONS", standardCorsMockIntegration, {
        authorizationType: apigateway.AuthorizationType.NONE,
        methodResponses: [
            optionsMethodResponse
        ]
    });

When you deploy the API, you can verify using the API Gateway console that your methods have been setup correctly. The proxy's ANY method has authorization enabled while the OPTIONS method does not.

Reference to the GitHub issue that helped: GitHub Issue 'apigateway: add explicit support for CORS'

Upvotes: 2

Related Questions