After creating the User pool, we create an API and a Lambda function to handle user registration and login requests.
Add needed parameters for function to be executed.
Copy the below code blocks to template.yaml file in source of fcj-book-shop-sam-ws3.zip file that downloaded in preparation.
cognitoClientID:
Type: String
Default: APP_CLIENT_ID
cognitoClientSecret:
Type: String
Default: APP_CLIENT_SECRET
Change APP_CLIENT_ID and APP_CLIENT_SECRET to the Cognito app clients recorded value before.
Create a new sam
deployment.
Open template.yaml file in source of fcj-book-shop-sam-ws3.zip file that downloaded in preparation.
Comment the code blocks as below.
Run the below commands.
sam build
sam validate
sam deploy
At template.yaml file in source of fcj-book-shop-sam-ws3.zip file that downloaded in preparation.
Create Registration parameter.
Copy and paste the below code block as image below.
registerPathPart:
Type: String
Default: register
Create Registration function.
Copy and paste the below code blocks to the bottom of the file.
Register:
Type: AWS::Serverless::Function
Properties:
CodeUri: fcj-book-shop/register
Handler: register.lambda_handler
Runtime: python3.11
FunctionName: register
Architectures:
- x86_64
Environment:
Variables:
CLIENT_ID: !Ref cognitoClientID
CLIENT_SECRET: !Ref cognitoClientSecret
RegisterApiResource:
Type: AWS::ApiGateway::Resource
Properties:
RestApiId: !Ref BookApi
ParentId: !GetAtt BookApi.RootResourceId
PathPart: !Ref registerPathPart
RegisterApiOptions:
Type: AWS::ApiGateway::Method
Properties:
HttpMethod: OPTIONS
RestApiId: !Ref BookApi
ResourceId: !Ref RegisterApiResource
AuthorizationType: NONE
Integration:
Type: MOCK
IntegrationResponses:
- StatusCode: "200"
ResponseParameters:
method.response.header.Access-Control-Allow-Origin: "'*'"
method.response.header.Access-Control-Allow-Methods: "'OPTIONS,POST,GET,DELETE'"
method.response.header.Access-Control-Allow-Headers: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'"
MethodResponses:
- StatusCode: "200"
ResponseParameters:
method.response.header.Access-Control-Allow-Origin: true
method.response.header.Access-Control-Allow-Methods: true
method.response.header.Access-Control-Allow-Headers: true
RegisterApi:
Type: AWS::ApiGateway::Method
Properties:
HttpMethod: POST
RestApiId: !Ref BookApi
ResourceId: !Ref RegisterApiResource
AuthorizationType: NONE
Integration:
Type: AWS_PROXY
IntegrationHttpMethod: POST # For Lambda integrations, you must set the integration method to POST
Uri: !Sub >-
arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${Register.Arn}/invocations
MethodResponses:
- StatusCode: "200"
ResponseParameters:
method.response.header.Access-Control-Allow-Origin: true
method.response.header.Access-Control-Allow-Methods: true
method.response.header.Access-Control-Allow-Headers: true
RegisterApiInvokePermission:
Type: AWS::Lambda::Permission
Properties:
FunctionName: !Ref Register
Action: lambda:InvokeFunction
Principal: apigateway.amazonaws.com
SourceAccount: !Ref "AWS::AccountId"
The directory structure is as below.
fcj-book-shop-sam-ws3
├── fcj-book-shop
│ ├── register
│ │ └── register.py
│ ├── ...
│
└── template.yaml
Create register folder in fcj-book-shop-sam-ws3/fcj-book-shop/ folder.
Create register.py file and copy the following code to it.
import json
import boto3
import os
import hmac
import hashlib
import base64
# Initialize the Cognito client
client = boto3.client("cognito-idp")
headers = {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "OPTIONS,POST,GET,DELETE",
"Access-Control-Allow-Headers": "Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token"
}
def lambda_handler(event, context):
# Get the body from the event and parse it as JSON
body = json.loads(event["body"])
# Get the username and password from the body
username = body["username"]
password = body["password"]
# Get Client ID and Client Secret from environment variables
client_id = os.environ["CLIENT_ID"]
client_secret = os.environ["CLIENT_SECRET"]
# Generate the secret hash
message = bytes(username + client_id, 'utf-8')
key = bytes(client_secret, 'utf-8')
secret_hash = base64.b64encode(
hmac.new(key, message, digestmod=hashlib.sha256).digest()).decode()
try:
# Sign up the user
client.sign_up(
ClientId=client_id,
SecretHash=secret_hash,
Username=username,
Password=password
)
return {
"statusCode": 200,
"headers": headers,
"body": json.dumps("User registration successful")
}
except Exception as e:
print(f"Error registering user: {e}")
raise Exception(f"Error registering user: {e}")
At template.yaml file in source of fcj-book-shop-sam-ws3.zip file that downloaded in preparation.
Create Confirm parameter.
Copy and paste the below code block as image below.
confirmPathPart:
Type: String
Default: confirm_user
Create Confirm function.
Copy and paste the below code blocks to the bottom of the file.
Confirm:
Type: AWS::Serverless::Function
Properties:
CodeUri: fcj-book-shop/confirm_user
Handler: confirm_user.lambda_handler
Runtime: python3.11
FunctionName: confirm
Architectures:
- x86_64
Environment:
Variables:
CLIENT_ID: !Ref cognitoClientID
CLIENT_SECRET: !Ref cognitoClientSecret
ConfirmApiResource:
Type: AWS::ApiGateway::Resource
Properties:
RestApiId: !Ref BookApi
ParentId: !GetAtt BookApi.RootResourceId
PathPart: !Ref confirmPathPart
ConfirmApiOptions:
Type: AWS::ApiGateway::Method
Properties:
HttpMethod: OPTIONS
RestApiId: !Ref BookApi
ResourceId: !Ref ConfirmApiResource
AuthorizationType: NONE
Integration:
Type: MOCK
IntegrationResponses:
- StatusCode: "200"
ResponseParameters:
method.response.header.Access-Control-Allow-Origin: "'*'"
method.response.header.Access-Control-Allow-Methods: "'OPTIONS,POST,GET,DELETE'"
method.response.header.Access-Control-Allow-Headers: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'"
MethodResponses:
- StatusCode: "200"
ResponseParameters:
method.response.header.Access-Control-Allow-Origin: true
method.response.header.Access-Control-Allow-Methods: true
method.response.header.Access-Control-Allow-Headers: true
ConfirmApi:
Type: AWS::ApiGateway::Method
Properties:
HttpMethod: POST
RestApiId: !Ref BookApi
ResourceId: !Ref ConfirmApiResource
AuthorizationType: NONE
Integration:
Type: AWS_PROXY
IntegrationHttpMethod: POST # For Lambda integrations, you must set the integration method to POST
Uri: !Sub >-
arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${Confirm.Arn}/invocations
MethodResponses:
- StatusCode: "200"
ResponseParameters:
method.response.header.Access-Control-Allow-Origin: true
method.response.header.Access-Control-Allow-Methods: true
method.response.header.Access-Control-Allow-Headers: true
ConfirmApiInvokePermission:
Type: AWS::Lambda::Permission
Properties:
FunctionName: !Ref Confirm
Action: lambda:InvokeFunction
Principal: apigateway.amazonaws.com
SourceAccount: !Ref "AWS::AccountId"
The directory structure is as below.
fcj-book-shop-sam-ws3
├── fcj-book-shop
│ ├── register
│ │ └── register.py
│ ├── confirm_user
│ │ └── confirm_user.py
│ ├── ...
│
└── template.yaml
Create confirm_user folder in fcj-book-shop-sam-ws3/fcj-book-shop/ folder.
Create confirm_user.py file and copy the following code to it.
import json
import boto3
import os
import hmac
import hashlib
import base64
# Initialize the Cognito client
client = boto3.client("cognito-idp")
headers = {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "OPTIONS,POST,GET,DELETE",
"Access-Control-Allow-Headers": "Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token"
}
def lambda_handler(event, context):
# Get the body from the event and parse it as JSON
body = json.loads(event["body"])
# Extract the necessary information from the event
username = body["username"]
confirmation_code = body["confirmation_code"]
# Get Client ID and Client Secret from environment variables
client_id = os.environ["CLIENT_ID"]
client_secret = os.environ["CLIENT_SECRET"]
# Generate the secret hash
message = bytes(username + client_id, "utf-8")
key = bytes(client_secret, "utf-8")
secret_hash = base64.b64encode(
hmac.new(key, message, digestmod=hashlib.sha256).digest()).decode()
try:
# Confirm the user
response = client.confirm_sign_up(
ClientId=client_id,
SecretHash=secret_hash,
Username=username,
ConfirmationCode=confirmation_code
)
return {
"statusCode": 200,
"headers": headers,
"body": json.dumps("User confirmed successfully")
}
except Exception as e:
print(f"Error confirming user: {e}")
raise Exception(f"Error confirming user: {e}")
At template.yaml file in source of fcj-book-shop-sam-ws3.zip file that downloaded in preparation.
Create Login parameter.
Copy and paste the below code block as image below.
loginPathPart:
Type: String
Default: login
Create Login function.
Copy and paste the below code blocks to the bottom of the file.
Login:
Type: AWS::Serverless::Function
Properties:
CodeUri: fcj-book-shop/login
Handler: login.lambda_handler
Runtime: python3.11
FunctionName: login
Architectures:
- x86_64
Environment:
Variables:
CLIENT_ID: !Ref cognitoClientID
CLIENT_SECRET: !Ref cognitoClientSecret
LoginApiResource:
Type: AWS::ApiGateway::Resource
Properties:
RestApiId: !Ref BookApi
ParentId: !GetAtt BookApi.RootResourceId
PathPart: !Ref loginPathPart
LoginApiOptions:
Type: AWS::ApiGateway::Method
Properties:
HttpMethod: OPTIONS
RestApiId: !Ref BookApi
ResourceId: !Ref LoginApiResource
AuthorizationType: NONE
Integration:
Type: MOCK
IntegrationResponses:
- StatusCode: "200"
ResponseParameters:
method.response.header.Access-Control-Allow-Origin: "'*'"
method.response.header.Access-Control-Allow-Methods: "'OPTIONS,POST,GET,DELETE'"
method.response.header.Access-Control-Allow-Headers: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'"
MethodResponses:
- StatusCode: "200"
ResponseParameters:
method.response.header.Access-Control-Allow-Origin: true
method.response.header.Access-Control-Allow-Methods: true
method.response.header.Access-Control-Allow-Headers: true
LoginApi:
Type: AWS::ApiGateway::Method
Properties:
HttpMethod: POST
RestApiId: !Ref BookApi
ResourceId: !Ref LoginApiResource
AuthorizationType: NONE
Integration:
Type: AWS_PROXY
IntegrationHttpMethod: POST # For Lambda integrations, you must set the integration method to POST
Uri: !Sub >-
arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${Login.Arn}/invocations
MethodResponses:
- StatusCode: "200"
ResponseParameters:
method.response.header.Access-Control-Allow-Origin: true
method.response.header.Access-Control-Allow-Methods: true
method.response.header.Access-Control-Allow-Headers: true
LoginApiInvokePermission:
Type: AWS::Lambda::Permission
Properties:
FunctionName: !Ref Login
Action: lambda:InvokeFunction
Principal: apigateway.amazonaws.com
SourceAccount: !Ref "AWS::AccountId"
The directory structure is as below.
fcj-book-shop-sam-ws3
├── fcj-book-shop
│ ├── register
│ │ └── register.py
│ ├── confirm_user
│ │ └── confirm_user.py
│ ├── login
│ │ └── login.py
│ ├── ...
│
└── template.yaml
Create login folder in fcj-book-shop-sam-ws3/fcj-book-shop/ folder.
Create login.py file and copy the following code to it.
import json
import boto3
import os
import hmac
import hashlib
import base64
client = boto3.client("cognito-idp")
headers = {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "OPTIONS,POST,GET,DELETE",
"Access-Control-Allow-Headers": "Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token"
}
def lambda_handler(event, context):
# Get the body from the event and parse it as JSON
body = json.loads(event["body"])
# Get the username and password from the body
username = body["username"]
password = body["password"]
# Get Client ID and Client Secret from environment variables
client_id = os.environ["CLIENT_ID"]
client_secret = os.environ["CLIENT_SECRET"]
# Generate the secret hash
message = bytes(username + client_id, 'utf-8')
key = bytes(client_secret, 'utf-8')
secret_hash = base64.b64encode(
hmac.new(key, message, digestmod=hashlib.sha256).digest()).decode()
try:
response = client.initiate_auth(
AuthFlow="USER_PASSWORD_AUTH",
AuthParameters={
"USERNAME": username,
"PASSWORD": password,
"SECRET_HASH": secret_hash
},
ClientId=client_id,
)
return {
"statusCode": 200,
"headers": headers,
"body": json.dumps({
"message": "Login successful",
"id_token": response["AuthenticationResult"]["IdToken"],
"access_token": response["AuthenticationResult"]["AccessToken"],
"refresh_token": response["AuthenticationResult"]["RefreshToken"]
})
}
except Exception as e:
print(f"Error login: {e}")
raise Exception(f"Error login: {e}")
Uncomment and edit this code block.
BookApiDeployment:
Type: AWS::ApiGateway::Deployment
Properties:
RestApiId: !Ref BookApi
DependsOn:
- BookApiGet
- BookApiCreate
- BookApiDelete
- RegisterApi
- ConfirmApi
- LoginApi
BookApiStage:
Type: AWS::ApiGateway::Stage
Properties:
RestApiId: !Ref BookApi
StageName: !Ref stage
DeploymentId: !Ref BookApiDeployment
Run the below commands. Leave as default.
sam build
sam validate
sam deploy
We have completed the implementation of the APIs and Lambda functions.