We have the following scenario:
We want with single Cloud Formation stack to deploy an API Gateway having methods secured with Lambda based Custom Authorizer. The API must be defined with Swagger file.
The Custom Authorizer Lambda must be created within the same Cloud Formation stack. The question is if or how we can reference the Custom Authorizer Lambda function within the Swagger file?
For example:
securityDefinitions:
OktaCustomAuthorizer:
type: "apiKey"
name: "Authorization"
in: "header"
x-amazon-apigateway-authtype: "custom"
x-amazon-apigateway-authorizer:
authorizerResultTtlInSeconds: 300
authorizerUri: "arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/<<FUNCTION_ARN>>/invocations"
type: "token"
If Authorizer Lambda have been created previously, we can statically reference it in the construct above. However, what if Custom Authorizer function is part of the current stack? The API method Lambda request integrations can handle these kind of scenarios with stage variables substitutions, i.e. ${stageVariables.LambdaFunctionName}. But for Custom Authorizers it is not the case.
Any opinion? The requirement for having everything in one stack seems very reasonable.
Best Regards,
I'm having the same issue. I would expect stage variables to work for custom authorizers like they do for request integrations, but it seems they don't.
APIGateway doesn't support this feature, at the moment. Unfortunately there is nothing SAM/CloudFormation can do about it until then.
@sanathkr unless this is a "won't fix", why close this issue when it hasn't been resolved? This is a reasonable feature (in fact, trying to solve this problem led me here).
I have a similar setup and it works as expected:
SAM Template has:
Resources:
AuthorizerFn:
Type: AWS::Serverless::Function
Properties:
Handler: index.handler
Runtime: nodejs6.10
CodeUri: <URI>
FunctionName: my-request-authorizer-fn
MyApi:
Type: AWS::Serverless::Api
Properties:
StageName: prod
DefinitionUri: swagger.yaml
Variables:
AuthorizerFnName: !Ref AuthorizerFn
Then in my swagger file:
securityDefinitions:
MyCustomAuthorizer:
type: apiKey
name: Authorization
in: header
x-amazon-apigateway-authtype: custom
x-amazon-apigateway-authorizer:
authorizerResultTtlInSeconds: 300
authorizerUri: !Sub arn:aws:apigateway:<REGION>:lambda:path/2015-03-31/functions/arn:aws:lambda:<REGION>:<ACCOUNT>:function:${stageVariables.AuthorizerFnName}/invocations
type: token
All requests on resources and methods this authorizer is enabled on are indeed authorized.
You have to hard code the function name. SAM works better when you allow the function names to be assigned dynamically.
On 22 Apr 2017, at 07:11, Bruno Morency notifications@github.com wrote:
I have a similar setup and it works as expected:
SAM Template has (under Resources:):
Resources:
AuthorizerFn:
Type: AWS::Serverless::Function
Properties:
Handler: index.handler
Runtime: nodejs6.10
CodeUri:
FunctionName: my-request-authorizer-fn
MyApi:
Type: AWS::Serverless::Api
Properties:
StageName: prod
DefinitionUri: swagger.yaml
Variables:
AuthorizerFnName: !Ref AuthorizerFn
Then in my swagger file:securityDefinitions:
MyCustomAuthorizer:
type: apiKey
name: Authorization
in: header
x-amazon-apigateway-authtype: custom
x-amazon-apigateway-authorizer:
authorizerResultTtlInSeconds: 300
authorizerUri: !Sub arn:aws:apigateway::lambda:path/2015-03-31/functions/arn:aws:lambda: : :function:${stageVariables.AuthorizerFnName}/invocations
type: token
All requests on resources and methods this authorizer is enabled on are indeed authorized.—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub, or mute the thread.
The actual line in the template is FunctionName: !Sub ${AWS::StackName}-request-authorizer but you're right, it isn't SAML giving it any name it wants. What does setting the name block/remove that you want to have?
My understanding (based on this) is that hard-coding the FunctionName limits flexibility. Admittedly, I haven't run into any issues yet. Nonetheless, where I can, I like to be pro-active and avoid issues entirely.
Hmmm, strange. It wasn't working a couple of months ago, it was ok for integration functions only. I can see the !Sub function in the swagger file. I thought that the CF functions along with the template version are processed by the CloudFormation. On the contrary, the swagger file is processed by the API Gateway that substitutes stage variables using the ${} placeholders only (no CF !Sub used).
The swagger used to be part of the main template, I had to move it out to
avoid the 51,200 bytes limit. I forgot to move the !Sub part out which was
there to place in the AWS::Region and accountid which need to be hardcoded
now that it's outside the template :-/
On Sat, Apr 22, 2017 at 18:49 marjanSterjev notifications@github.com
wrote:
Hmmm, strange. It wasn't working a couple of months ago, it was ok for
integration functions only. I can see the !Sub function in the swagger
file. I thought that the CF functions along with the template version are
processed by the CloudFormation. On the contrary, the swagger file is
processed by the API Gateway that substitutes stage variables using the ${}
placeholders only (no CF !Sub used).—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/awslabs/serverless-application-model/issues/66#issuecomment-296406579,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAGCP5cKV05Jw3wS6cBlBug38dSDJd72ks5ryoQOgaJpZM4LpmvG
.
Strange again... !Sub ${stageVariables.functionName} shouldn't be resolved inside CF template, CF doesn't know what stageVarables are.
Are you sure that the whole approach works (external swagger file) if you delete your CF and deploy again. Can you see the custom authorizer configured for an API method in the API Gateway console?
I haven't tried deleting everything but I've deployed numerous times since
that change all everything works well, including the authorizer.
On Sat, Apr 22, 2017 at 19:13 marjanSterjev notifications@github.com
wrote:
Strange again... !Sub ${stageVariables.functionName} shouldn't be resolved
inside CF template, CF doesn't know what stageVarables are.Are you sure that the whole approach works (external swagger file) if you
delete your CF and deploy again. Can you see the custom authorizer
configured for an API method in the API Gateway console?—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/awslabs/serverless-application-model/issues/66#issuecomment-296407619,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAGCPxa3__pZxpM4Pi1ILijQ-vIr9_oRks5ryombgaJpZM4LpmvG
.
If you set the FunctionName you can use it as a hard-coded reference. The below set-up works for me (single .yml file with inline swagger)
This works for me:
AuthoriseUserFunction:
Type: AWS::Serverless::Function
Properties:
Handler: authorise.user
FunctionName: AuthoriseUserFunction
Runtime: nodejs4.3
Policies: AmazonDynamoDBReadOnlyAccess
Environment:
Variables:
TABLE_NAME: !Ref AccountTable
Api:
Type: AWS::Serverless::Api
Properties:
...
DefinitionBody:
...
securityDefinitions:
AuthoriseUserCustom:
type: "apiKey"
name: "Authorization"
in: "header"
x-amazon-apigateway-authtype: "custom"
x-amazon-apigateway-authorizer:
type: "token"
authorizerUri: "arn:aws:apigateway:XXX:lambda:path/2015-03-31/functions/arn:aws:lambda:XXX:XXX:function:AuthoriseUserFunction/invocations"
authorizerResultTtlInSeconds: 60
Yes, hard coded approach normally works. The issue is related to stage variables replacement in the custom authorizers. In CI/CD scenario with multiple environments, hard coded function name is not an option.
I assume the replacement still doesn't work. And this is not a SAM problem, it is an API Gateway enhacement that will be introduced sooner or later.
I have written an article on LinkedIn that illustrates a possible temporary solution:
https://www.linkedin.com/pulse/aws-serverless-application-model-api-custom-automated-marjan-sterjev
@brunomorency and @noilly, what's the difference between x-amazon-apigateway-authtype: custom and x-amazon-apigateway-authtype: oauth2? I will be verifying the JWT token in my Lambda function (the real logic), does the amazon-apigateway-authtype field matter at all? (I feel this field is only for placeholder purpose, but I am not sure)
I would like to ask if injecting variables into swagger docs has already been addressed. We have a scenario where we need to inject/insert the ARN of the cognito user pool into our swagger file, as follows (snippets only):
Parameters:
AuthNamePrefix:
Type: String
Description: prefix for cognito user pool name (required).
Resources:
APIDefinitions:
Type: AWS::Serverless::Api
Properties:
DefinitionUri: swagger.yaml
StageName: v1
Variables:
MyAPIAuth: !Ref MyUserPool
MyUserPool:
Type: "AWS::Cognito::UserPool"
Properties:
UserPoolName: !Sub ${AuthNamePrefix}-UserPool
AutoVerifiedAttributes:
- email
AdminCreateUserConfig:
AllowAdminCreateUserOnly: True
and my swagger file looks like this:
paths:
/:
get:
summary: "Get API version metadata"
consumes:
- "application/json"
produces:
- "application/json"
security:
- cognitoAuthorizer: []
securityDefinitions:
cognitoAuthorizer:
type: "apiKey"
name: "Authorization"
in: "header"
x-amazon-apigateway-authtype: "cognito_user_pools"
x-amazon-apigateway-authorizer:
providerARNs:
- arn:aws:cognito-idp:REGION:AWS_ACCOUNT_NO:userpool/${stageVariables.MyAPIAuth}
type: "cognito_user_pools"
It successfully deploys but i get this on the api gateway's Authorizers page console:

The API Gateway should work, right? What happens instead is when i get to test the Authorizer/API, it gets an Unauthorized response. But updating the Authorizer with the actual cognito user pool ID, it will work. Hardcoding is not an option for us, so we have to make the stage variable work.
If anyone can shed a light, would be much appreciated.
@miojoffey The issue you've posted on is already closed, so this might not be the most effective place to ask your question.
I have encountered similar scenarios of having to inject resource IDs into the swagger file. This has led me to always use inline-swagger in the SAM template. While that makes our SAM template much much larger, it enables us to use the same template across multiple stages/environments without hardcoding resource IDs. Hopefully this helps.
@michaelj-smith I think this makes sense as there is no easy way with this on a separate swagger file. Thank you very much for your response. Appreciate it.
Cheers
For those who might be interesting, I am using sed command as a workaround in my buildspec.yml.
I renamed swagger.yaml to swagger.template.yaml. Then I am using:
securityDefinitions:
'Authorizer':
type: 'apiKey'
name: 'Authorization'
in: 'header'
'x-amazon-apigateway-authtype': 'cognito_user_pools'
'x-amazon-apigateway-authorizer':
providerARNs:
- Fn::Sub: arn:aws:cognito-idp:eu-west-1:xxxxxxxxxxxxxx:userpool/@USER_POOL_ID@
type: 'cognito_user_pools'
The key here is @USER_POOL_ID@.
Then in my buildspec.yml I just replace it as the first step:
commands:
- sed "s/@USER_POOL_ID@/$USER_POOL_ID/g" swagger-template.yaml > swagger.yaml
......
Most helpful comment
@sanathkr unless this is a "won't fix", why close this issue when it hasn't been resolved? This is a reasonable feature (in fact, trying to solve this problem led me here).