What is AWS Cognito
Amazon Cognito is a service provided by AWS that allows you to implement user authentication in your web and mobile applications. Cognito supports authentication, authorization, and user management, allowing users to sign in with a username and password, or social login through third parties such as Google, Apple, and others.
Cognito Features
Amazon Cognito has two main components: the user pool and the identity pool.
User Pool
Cogito is a fully managed service, so it can be implemented without infrastructure awareness. Cogito is a fully managed service, so it can be implemented without any infrastructure awareness. The user pool provides the following functions
- Sign-up and sign-in services
- A built-in, customizable web UI to sign in users
- Social sign-in with Facebook, Google, Login with Amazon, and Sign in with Apple, and through SAML and OIDC identity providers from your user pool
- User directory management and user profiles
- Security features such as multi-factor authentication (MFA), checks for compromised credentials, account takeover protection, and phone and email verification
- Customized workflows and user migration through AWS Lambda triggers
Identity Pool
Identity Pools are an addition to Amazon Cognito's user pools and provide "authorization" for each AWS service, such as Amazon S3 and DynamoDB, while working with external identity providers. Users can obtain temporary AWS credentials to access other AWS services, and the identity pool supports anonymous guest users and the following identity providers that can be used to authenticate identity pool users
- Amazon Cognito user pools
- Social sign-in with Facebook, Google, Login with Amazon, and Sign in with Apple
- OpenID Connect (OIDC) providers
- SAML identity providers
- Developer authenticated identities
Note that the identity pool must be merged with the user pool in order to store user profile information.
Difference between user pool and identity pool
The difference is that user pools handle "authentication" while identity pools handle "authorization". Authentication is the process of determining who the accessing user is. Authorization, on the other hand, is the process of determining whether the user is allowed to use the service after authentication.
Cognito pricing
AWS Cognito charges based on monthly active users (MAU). If a signup, sign-in, token update, password change, or other operation occurs during the month, the user is counted as an MAU. However, the Cognito user pool has a free allowance of 50,000 MAUs per month. Below is the pricing structure for the Tokyo region.
Pricing Tier (MAUs) | Price per MAU |
---|---|
50,001-100,000 (after the 50,000 free tier) | 0.0055USD |
Next 900,000 | 0.0046USD |
Next 9,000,000 | 0.00325USD |
Greater than 10,000,000 | 0.0025USD |
Cognito implementation code
Here is the code for building the infrastructure part of Cognito with Terraform and the logic part with Python. This time, we will create Cognito without custom attributes, signing in with an email address and password.
Infrastructure in Terraform
The code for terraform is as follows
resource "aws_cognito_user_pool" "main" {
name = "cognito-demo-pool"
username_attributes = ["email"]
username_configuration {
case_sensitive = true
}
auto_verified_attributes = ["email"]
password_policy {
minimum_length = 8
require_lowercase = false
require_uppercase = false
require_numbers = false
require_symbols = false
temporary_password_validity_days = 7
}
mfa_configuration = "OFF"
admin_create_user_config {
allow_admin_create_user_only = false
}
account_recovery_setting {
recovery_mechanism {
name = "verified_email"
priority = 1
}
}
}
resource "aws_cognito_user_pool_domain" "main" {
domain = "cognito-demo-pool"
user_pool_id = aws_cognito_user_pool.main.id
}
resource "aws_cognito_user_pool_client" "main" {
name = "cognito-demo-pool-client"
user_pool_id = aws_cognito_user_pool.main.id
generate_secret = false
explicit_auth_flows = [
"ALLOW_USER_PASSWORD_AUTH",
"ALLOW_USER_SRP_AUTH",
"ALLOW_REFRESH_TOKEN_AUTH"
]
prevent_user_existence_errors = "ENABLED"
}
Logic in Python
To implement logic in Python, you need to install a library called boto3.
$ pip install boto3
Then, create a Cognito client with the following at the beginning of the source code
import boto3
sess = boto3.Session()
client = sess.client(
"cognito-idp",
region_name="ap-northeast-1",
)
Create New User
Create a new user. A temporary password will be sent to the email address.
def admin_create_user(email: str):
user_attributes = [
{"Name": "email_verified", "Value": "true"},
{"Name": "email", "Value": email},
]
client.admin_create_user(
UserPoolId=POOL_ID,
Username=email,
UserAttributes=user_attributes,
ForceAliasCreation=False,
DesiredDeliveryMediums=["EMAIL"],
)
Sign In
Creates a new user. If it is the first time signing in, a session will be returned, otherwise a token will be returned for authentication.
def user_password_auth(email: str, password: str):
resp = client.initiate_auth(
ClientId=CLIENT_ID,
AuthFlow="USER_PASSWORD_AUTH",
AuthParameters={"USERNAME": email, "PASSWORD": password},
)
if bool(resp["ChallengeParameters"]):
return {"session": resp["Session"]}
else:
return {
"id_token": resp["AuthenticationResult"]["IdToken"],
"access_token": resp["AuthenticationResult"]["AccessToken"],
"refresh_token": resp["AuthenticationResult"]["RefreshToken"],
}
Change password on first sign-in
Sign in with your session and new password the first time you sign in. A token will be returned.
def new_password_required(email: str, new_password: str, session: str):
resp = client.respond_to_auth_challenge(
ClientId=CLIENT_ID,
Session=session,
ChallengeName="NEW_PASSWORD_REQUIRED",
ChallengeResponses={"USERNAME": email, "NEW_PASSWORD": new_password},
)
return {
"id_token": resp["AuthenticationResult"]["IdToken"],
"access_token": resp["AuthenticationResult"]["AccessToken"],
"refresh_token": resp["AuthenticationResult"]["RefreshToken"],
}
Reissue Token from Refresh Token
Reissue access and identity tokens from a refresh token.
def refresh_token_auth(refresh_token: str):
resp = client.initiate_auth(
ClientId=CLIENT_ID,
AuthFlow="REFRESH_TOKEN_AUTH",
AuthParameters={"REFRESH_TOKEN": refresh_token},
)
return {
"id_token": resp["AuthenticationResult"]["IdToken"],
"access_token": resp["AuthenticationResult"]["AccessToken"],
}
Change Password
Change password.
def change_password(password: str, new_password: str, access_token: str):
"""Change password"""
client.change_password(
PreviousPassword=password,
ProposedPassword=new_password,
AccessToken=access_token,
)
Send confirmation code to change password
A confirmation code will be sent to your e-mail address to reset your password.
def forgot_password(email: str) -> None:
client.forgot_password(
ClientId=CLIENT_ID,
Username=email
)
Reset Password
Set a new password using the confirmation code.
def confirm_forgot_password(email: str, password: str, code: str) -> None:
client.confirm_forgot_password(
ClientId=CLIENT_ID,
Username=email,
Password=password,
ConfirmationCode=code
)
References