- Newest
- Most votes
- Most comments
To set up AWS Cognito for user authentication and JWT authorization in your Serverless Framework serverless.yml file, you'll need to make a few modifications and additions. Here's an updated version of your serverless.yml file with comments explaining each section:
service: my-service
frameworkVersion: '3'
provider:
name: aws
stage: dev
region: us-west-2
profile: my-api
runtime: python3.9
iam:
role:
statements:
- Effect: Allow
Action:
- cognito-idp:AdminInitiateAuth
- cognito-idp:AdminRespondToAuthChallenge
- cognito-idp:AdminUserGlobalSignOut
- cognito-idp:AdminUpdateUserAttributes
- cognito-idp:ListUsers
functions:
private_function:
handler: private_function.lambda_handler
events:
- httpApi:
path: '/private_function'
method: 'GET'
authorizer:
name: CognitoAuthorizer # Reference to your custom authorizer
identitySource: "$request.header.Authorization" # The source of JWT tokens in the request
package:
exclude:
- node_modules/**
- venv/**
plugins:
- serverless-python-requirements
resources:
Resources:
CognitoUserPool:
Type: AWS::Cognito::UserPool
Properties:
UserPoolName: ${self:service}_${sls:stage}_user_pool
UsernameAttributes:
- email
CognitoUserPoolClient:
Type: AWS::Cognito::UserPoolClient
Properties:
ClientName: ${self:service}_${sls:stage}_client
UserPoolId:
Ref: CognitoUserPool
ExplicitAuthFlows:
- ADMIN_NO_SRP_AUTH
GenerateSecret: false
CognitoAuthorizer:
Type: AWS::ApiGateway::Authorizer # Use AWS::ApiGateway instead of AWS::ApiGatewayV2
Properties:
Name: CognitoAuthorizer
RestApiId: # Add your API Gateway RestApiId here
Type: COGNITO_USER_POOLS
IdentitySource: "method.request.header.Authorization" # Adjust the source
ProviderARNs:
- Fn::Sub: arn:aws:cognito-idp:${self:provider.region}:${AWS::AccountId}:userpool/${self:resources.Resources.CognitoUserPool.Properties.UserPoolName}
# Define a CognitoUserPoolDomain resource to configure the Cognito Hosted UI
CognitoUserPoolDomain:
Type: AWS::Cognito::UserPoolDomain
Properties:
Domain: your-cognito-domain # Replace with your desired domain name
UserPoolId:
Ref: CognitoUserPool
Here are the changes and explanations:
- In the
private_function
definition, I added anauthorizer
property to specify that this function should use theCognitoAuthorizer
you defined. - I replaced the
AWS::ApiGatewayV2::Authorizer
type withAWS::ApiGateway::Authorizer
. The authorizer type depends on the version of AWS API Gateway you are using. If you are using the first version of API Gateway, useAWS::ApiGateway::Authorizer
. - I added a
RestApiId
property to theCognitoAuthorizer
definition. You need to specify the API Gateway ID to which this authorizer is associated. - I modified the
IdentitySource
in theCognitoAuthorizer
to match the expected format of the JWT token source. - Added a
CognitoUserPoolDomain
resource to configure the Cognito Hosted UI with your desired domain name. Replaceyour-cognito-domain
with the actual domain you want to use.
With these modifications, your serverless.yml
should create a Cognito User Pool, User Pool Client, and a Cognito Authorizer for JWT tokens. It also associates the authorizer with the private_function
, which requires authentication to access.
I apologize for the confusion. It seems there was an error in my previous response regarding the identitySource
property. The correct property for specifying the source of JWT tokens in an HTTP event is identitySourceHeader
. Here's the corrected serverless.yml
snippet:
functions:
private_function:
handler: private_function.lambda_handler
events:
- httpApi:
path: '/private_function'
method: 'GET'
authorizer:
name: CognitoAuthorizer
identitySourceHeader: Authorization # Specify the source header for JWT tokens
Regarding the RestApiId
, you can use the Fn::GetAtt
function to retrieve the RestApiId dynamically. Here's how you can modify the CognitoAuthorizer
section to use Fn::GetAtt
:
CognitoAuthorizer:
Type: AWS::ApiGateway::Authorizer
Properties:
Name: CognitoAuthorizer
RestApiId:
Fn::GetAtt:
- ApiGatewayRestApi # Replace with the actual logical name of your API Gateway resource
- Id
Type: COGNITO_USER_POOLS
IdentitySource: method.request.header.Authorization
ProviderARNs:
- Fn::Sub: arn:aws:cognito-idp:${self:provider.region}:${AWS::AccountId}:userpool/${self:resources.Resources.CognitoUserPool.Properties.UserPoolName}
Make sure to replace "ApiGatewayRestApi"
with the actual logical name of your API Gateway resource in the Fn::GetAtt
function.
With these changes, your CognitoAuthorizer
will use the RestApiId dynamically, and the identitySourceHeader
property is set correctly.
Hi Narnacle, thank you for helping me. However, I am still getting a warning and an error: Error: Event references not configured authorizer 'CognitoAuthorizer' I updated the question to include the changes I made.
I apologize for the confusion earlier. It appears that the Serverless Framework version you are using doesn't support the identitySourceHeader
property directly in the serverless.yml
file.
To set up a Cognito User Pool Authorizer for your HTTP API, you can use a separate AWS CloudFormation template (a .yaml
or .json
file) to define your API Gateway and the authorizer, and then reference that template in your serverless.yml
. Here's how you can do it:
- Create a separate CloudFormation template, for example,
api-gateway-template.yaml
, with the following content:
AWSTemplateFormatVersion: '2010-09-09'
Description: API Gateway and Cognito User Pool Authorizer
Resources:
MyApi:
Type: AWS::ApiGateway::RestApi
Properties:
Name: MyApi
CognitoAuthorizer:
Type: AWS::ApiGateway::Authorizer
Properties:
Name: CognitoAuthorizer
RestApiId: !Ref MyApi
Type: COGNITO_USER_POOLS
IdentitySource: method.request.header.Authorization
ProviderARNs:
- Fn::Sub: arn:aws:cognito-idp:${AWS::Region}:${AWS::AccountId}:userpool/${CognitoUserPoolId}
In this template:
MyApi
is your API Gateway.CognitoAuthorizer
is the Cognito User Pool Authorizer. Note that${CognitoUserPoolId}
is a placeholder that you need to replace with the actual User Pool ID.
- In your
serverless.yml
, reference the CloudFormation template and pass the User Pool ID as a variable:
service: my-service
frameworkVersion: '3'
provider:
name: aws
stage: dev
region: us-west-2
profile: my-api
runtime: python3.9
iam:
role:
statements:
- Effect: Allow
Action:
- cognito-idp:AdminInitiateAuth
- cognito-idp:AdminRespondToAuthChallenge
- cognito-idp:AdminUserGlobalSignOut
- cognito-idp:AdminUpdateUserAttributes
- cognito-idp:ListUsers
functions:
private_function:
handler: private_function.lambda_handler
events:
- httpApi:
path: '/private_function'
method: 'GET'
authorizer:
arn: !GetAtt CognitoAuthorizer.Arn
package:
exclude:
- node_modules/**
- venv/**
plugins:
- serverless-python-requirements
resources:
- ${file(api-gateway-template.yaml)} # Include the external CloudFormation template
# Add a variable to pass the Cognito User Pool ID
custom:
cognitoUserPoolId: ${self:resources.CognitoUserPool.Properties.UserPoolName}
In this serverless.yml
file:
- We include the external CloudFormation template using
${file(api-gateway-template.yaml)}
. - We pass the Cognito User Pool ID as a custom variable using
${self:resources.CognitoUserPool.Properties.UserPoolName}
.
This separation allows you to define the Cognito Authorizer separately and then reference it in your Serverless service.
Relevant content
- asked a year ago
- AWS OFFICIALUpdated 3 years ago
- AWS OFFICIALUpdated a year ago
- AWS OFFICIALUpdated 4 months ago
Hi @Narnacle. I tried implementing the changes you made however
Also for the RestApiID I want it to be set automatically to the one created by the private function: to do that I found resources that suggested using RestApiId: Fn::GetAtt: - ApiGatewayRestApi - RootResourceId