Function specific ApiKeyRequired Auth property does not override the global API default
The documentation states that if you have specified ApiKeyRequired: true globally on the API and want to make a specific Function public, you can override it with the following in the Function's event source:
ApiKeyRequired: false
However, this does not seem to function as stated.
Steps to reproduce the issue: Here's the template I used.
AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Description: >
sam-app
Sample SAM Template for sam-app
Globals:
Function:
Timeout: 3
Runtime: nodejs12.x
Resources:
MyAPI:
Type: AWS::Serverless::Api
Properties:
Name: MyAPI
StageName: Default
EndpointConfiguration: REGIONAL
Auth:
ApiKeyRequired: true
DefinitionBody:
openapi: 3.0.0
x-amazon-apigateway-api-key-source: "HEADER"
paths:
/public:
get:
x-amazon-apigateway-integration:
type: aws_proxy
httpMethod: POST
uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${PublicFunction.Arn}/invocations
/private:
get:
x-amazon-apigateway-integration:
type: aws_proxy
httpMethod: POST
uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${PrivateFunction.Arn}/invocations
PublicFunction:
Type: AWS::Serverless::Function
Properties:
FunctionName: PublicFunction
Role: !GetAtt LambdaRole.Arn
Handler: src/public.handler
Events:
API:
Type: Api
Properties:
Path: /public
Method: ANY
RestApiId:
Ref: MyAPI
Auth:
ApiKeyRequired: false
PrivateFunction:
Type: AWS::Serverless::Function
Properties:
FunctionName: PrivateFunction
Role: !GetAtt LambdaRole.Arn
Handler: src/private.handler
Events:
API:
Type: Api
Properties:
Path: /private
Method: ANY
RestApiId:
Ref: MyAPI
LambdaRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action:
- sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
ApiKey:
Type: AWS::ApiGateway::ApiKey
Properties:
Name: !Join [ "-", [ MyAPI, "ApiKey" ]]
Description: "APIkey"
Enabled: true
GenerateDistinctId: false
ApiUsagePlan:
Type: AWS::ApiGateway::UsagePlan
DependsOn: MyAPIDefaultStage
Properties:
ApiStages:
- ApiId: !Ref MyAPI
Stage: Default
Description: !Join [ "-", [ MyAPI, "UsagePlan" ] ]
UsagePlanName: !Join [ "-", [ MyAPI, "UsagePlan" ] ]
ApiUsagePlanKey:
Type: AWS::ApiGateway::UsagePlanKey
Properties:
KeyId: !Ref ApiKey
KeyType: API_KEY
UsagePlanId: !Ref ApiUsagePlan
Outputs:
APi:
Description: "API Gateway endpoint URL"
Value: !Sub "https://${MyAPI}.execute-api.${AWS::Region}.amazonaws.com/Default/public"
Observed result:

Expected result:
The /public route should have API Key Required = False.
I am having the same issue. did you find a solution? the only other solution I am seeing is having auth at method level and security and use of securityDefinitions for definationBody instead of global Auth
@gaurang171 I went with the swagger route for now. Note: Here's the detailed solution if you are interested.
Hi, @piyushjaware I can confirm that I was able to reproduce this, after deployment the API gateway does show "API Key Required" for the public GET, will investigate on the cause. Thanks for reporting this!
Hey @piyushjaware and @gaurang171 here's what is going on: SAM do support overriding Function specific ApiKeyRequired Auth property over the global API default, but this only happens when you do not have an explicit definition for the API's definition body. When you do not have a definition body provided, SAM will generate it for you, which will support the overriding that you want. But we do not touch the settings that customers define in their template's API definition so far. So a template like this actually achieves what you want:
Resources:
MyAPI:
Type: AWS::Serverless::Api
Properties:
Name: MyAPI
StageName: Default
EndpointConfiguration: REGIONAL
Auth:
ApiKeyRequired: true
PublicFunction:
Type: AWS::Serverless::Function
Properties:
FunctionName: PublicFunction
Role: !GetAtt LambdaRole.Arn
InlineCode: "code"
Handler: index.handler
Events:
API:
Type: Api
Properties:
Path: /public
Method: get
RestApiId:
Ref: MyAPI
Auth:
ApiKeyRequired: false
PrivateFunction:
Type: AWS::Serverless::Function
Properties:
FunctionName: PrivateFunction
Role: !GetAtt LambdaRole.Arn
InlineCode: "code"
Handler: index.handler
Events:
API:
Type: Api
Properties:
Path: /private
Method: get
RestApiId:
Ref: MyAPI
I have verified that deployments with this actually works with ApiGateway's ApiKeyRequired field correctly set up. Currently SAM does not support overriding if you have a definition body defined. Let me know if you want SAM to override over your own defined definition body, I will view this as a feature request. Right now the workaround would be to not input your definition body and let SAM do it for you. If this does not satisfy your need, I would recommend after the translation use the translated template to modify the swagger yourself (just change
"security": [
{
"api_key": []
}
],
to
"security": [],
I hope this helps!
@qingchm Your answer helped me in the scenario where I wanted API Key required for HTTP (GET, POST) methods except OPTIONS (for CORS support.)
I have been struggling with this issue for a couple days now. It seems that no matter how I try to set the api key config - either in the definition body or via the sam template, I cannot get the appropriate settings to deploy. I have tried removing the API Key config from my template and only setting in the definition doc:
x-amazon-apigateway-api-key-source: "HEADER" paths: : security: - api_key: [] - AccountApiAuthorizerFunction: []
securitySchemes: api_key: type: apiKey name: x-api-key in: header x-amazon-apigateway-api-key-source : HEADER
I have tried only setting the API key via the template: MyApi: Name: MyApi Type: AWS::Serverless::Api Properties: : Auth: ApiKeyRequired: false # turns off API Key for all methods Authorizers: : ResourcePolicy: :
MyFunction: Type: AWS::Serverless::Function Properties: CodeUri: lambdas/src/handlers/junk/ Handler: handler.lambdaHandler Events: MyFunctionEvent: Type: Api Properties: Path: /mypath Method: put RestApiId: !Ref MyApi Auth: ApiKeyRequired: true # overrides and turns on API Key for just this method
I have tried various combinations of the above and so far no magic. It seems whatever I set as the value for the API trumps any further configuration. I have also tried not setting the ApiKeyRequired at all for the API and that doesn't work either.
I can manually adjust the configuration in the console and get things working the way I want but I cannot for the life of me get the sam deploy to deploy that configuration. I have even tried creating the configuration that I want, exporting the definition and then deploying that. Still doesn't work. Really don't want to build 2 separate APIs just because I can't get the deployment to work as intended.
What am I doing wrong??