- What is cognito
With Amazon Cognito, you can quickly and easily add user registration, login, and access control to your web and mobile applications. Amazon Cognito scales to millions of users and supports sign-in with social identity providers such as Apple, Facebook, Google, and Amazon, as well as enterprise identity providers, via SAML 2.0 and OpenID Connect.
- Pro and Cons
- Pros
- Secure Passwords
- OAuth, SAML, and More
- Simple Integration
- Quick Startup
- Cons
- Limited Configurability
- Better Setup Your Pool Correctly
- Integration with Outside Services
- Disaster Recovery
- User Pool
A user pool is a user directory in Amazon Cognito. With a user pool, your users can sign in to your web or mobile app through Amazon Cognito. Your users can also sign in through social identity providers like Google, Facebook, Amazon, or Apple, and through SAML identity providers.
- Identity pools
Amazon Cognito identity pools (federated identities) enable you to create unique identities for your users and federate them with identity providers. With an identity pool, you can obtain temporary, limited-privilege AWS credentials to access other AWS services.
All the infrastructure code is stored in the folder of IaC
-
initialization: Initialize the terraform environment
terraform init
-
Validation: Check the syntax error
terraform validation
-
Plan: check the deploy plan
terraform plan
-
Apply: deploy the infrastructure
terraform apply
-
Destroy: Delete all the infrastructure
terraform destroy
The resources we need are listed below.
-
API Gateway
We need a API Gateway to deal with the request. And We must config the integration and route.
-
Lambda
We need a Lambda Handler to process the request event from the API Gateway.
-
S3
We need a Bucket to store the code of the Lambda Function.
-
Cognito User Pool
We need the user pool to act as authorizer for API Gateway.
You must provide your AWS key and secret, and give the value in the terraform.tfvars
as below:
# provider
aws_region = "us-east-1"
aws_access_key = "xxxxxx"
aws_secret_key = "xxxxxx"
When the infrastructure build successfully, you will see the output as below.
Apply complete! Resources: 22 added, 0 changed, 0 destroyed.
Outputs:
api_gateway_endpoint = "https://090oq9xisg.execute-api.us-east-1.amazonaws.com/serverless_lambda_stage"
function_name = "api-backend-demo"
lambda_function_name = "api-backend-demo"
s3_bucket_name = "demo-rationally-eminently-epic-tapir"
We use the github action workflow to automate the deployment of code to the cloud. You can check and view the github action configuration in the folder of ".github" in this Repo
The workflow as below:
- CI
- Checkout the Code to the github runner
- Lint the code, you can run flake8 or other tools to check the code format.
- Run the unittest, you can use tox, pytets, unittest or some tools to implement the unit test of the code.
- CD
- Checkout the Code to the github runner
- Configure AWS credentials
- Generate zip package
- Upload the zip file to S3.
- Update Lambda Function Code
- You need to add your secret key in the Repo.(Click settings of the Repo you will find the place to add secret key)
- We use Terraform build and run the minimum usable program, so the in the CI jobs, we just need to update the lambda handler code and update the file to AWS S3, then update the lambda function code.
- You must update the
env
parameters in the.github.yml
file.
__We need to open Cognito's Hosted UI in order to register users.__You can customize the style of the UI interface, such as CSS styles, etc. You can also use your existing user registration and login interfaces, such as pages built with React or Vue.js.
Of course, as a demo project, we use the Hosted UI that comes with Cognito, which requires us to login to the AWS console and open the Cognito service. We can select manage user pools in the Cognito service manage console. And then we chose the app client setting, then we can launch the Host UI.
- The App client settings page.(Launch Hosted UI)
According to the prompts on the Launched user login page, we need register users first. We can input the Email and Password, and after submitting the form, the system will send a verification code to our email.
- Confirm Account
- The Code in the Email
Then, we input the code in the form and confirm the account. Then we can use the email to login.
After we login, the URL will change to the callback url which is configured by us(You can found it in the main.tf
file). The URL show as below.
https://tsztwozeroone/callback?code=306e77fe-c5d1-4aaa-9629-31734b7029c5
The tsztwozeroone
is the Cognito Domain we configured. And the code
in the URL is important and we need to use it to apply the id token and access token from Cognito.
As we config the cognito client generate secret, we need to checkout the client_id and client_secret in the page of App client(General settings
>> App client
). My client id and secret as below.
client_id: 6vo4qadm0jp3e8kkk0c2d2l8im
client_secret: 1s3pth9n1trt2aejtarj81a4d707fjmrbenrnb08raiih8v37he5
Then we need to retrieve the token, and the url and request parameters as below.
- Request URL: https://tsztwozeroone.auth.us-east-1.amazoncognito.com/oauth2/token
- Request Parameters
- grant_type: authorization_code
- client_id: <Your client id>
- code: <Your user login code>
- redirect_uri: <Your callback url>
- Headers
- Authorization: Basic <Base64Encode(client_id:client_secret)>
- Content-Type: application/x-www-form-urlencoded
For example:
I use the postman to post my request to the Cognito identity server.
- The POST Request
POST https://tsztwozeroone.auth.us-east-1.amazoncognito.com/oauth2/token&
Content-Type='application/x-www-form-urlencoded'&
Authorization=Basic NnZvNHFhZG0wanAzZThra2swYzJkMmw4aW06MXMzcHRoOW4xdHJ0MmFlanRhcmo4MWE0ZDcwN2ZqbXJiZW5ybmIwOHJhaWloOHYzN2hlNQ==
grant_type=authorization_code&
client_id=6vo4qadm0jp3e8kkk0c2d2l8im&
code=100f0672-b6d2-4d22-921b-d21179a00499&
redirect_uri=https://tsztwozeroone/callback
- The Response
{
"id_token": "eyJraWQiOiJjQnlwaE42cGFxZ3FHVTAyQk9Me...",
"access_token": "eyJraWQiOiJkZmNsUkd2WFp3cW16K...",
"refresh_token": "eyJjdHkiOiJKV1QiLCJlbmMiOiJBMj...",
"expires_in": 3600,
"token_type": "Bearer"
}
We can decode the JWT id_token as below.
-
Decoded Header
{ "kid": "cByphN6paqgqGU02BOLyWMDMfsPLTX/hebRvC2G0VKs=", "alg": "RS256" }
-
Decoded Payload
{ "at_hash": "9ggweZJ8oRpVKQ6SRCyv6g", "sub": "035c1d45-48c5-418e-9421-eddfa3eb145a", "email_verified": true, "iss": "https://cognito-idp.us-east-1.amazonaws.com/us-east-1_c2Z1Qxxx", "cognito:username": "035c1d45-48c5-418e-9421-eddfa3eb145a", "origin_jti": "9656305e-aa6c-4c71-8694-1f0ae3df0a43", "aud": "6vo4qadm0jp3e8kkk0c2d2l8im", "token_use": "id", "auth_time": 1657190158, "exp": 1657193758, "iat": 1657190159, "jti": "164fa925-57a5-4285-85d1-e87d8bd3b001", "email": "xxxxxx@xxxxxx.com" }
Since each Route of API Gateway is configured with an authorizer, we need to put the JWT in the request header so that it can be routed to the specified backend resource after authorization.
The request header we configured that must take the Authorization Key (you can see how we configured it in main.tf
file), so the request header is as follows.
Then we can get the response successfully.
- When we apply for a token, the Authorization in the request header must be the Base64 encoded string of client_id and client_secret.
- The Cognito uses client_id as audience in the JWT by default, so when we configure the authorizer of API Gateway, we need to use client_id as audience.