2022-10-16

How to use AWS Cognito

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

https://docs.aws.amazon.com/cognito/latest/developerguide/what-is-amazon-cognito.html
https://aws.amazon.com/cognito/pricing/?nc1=h_ls
https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cognito_user_pool
https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/cognito-idp.html

Ryusei Kakujo

researchgatelinkedingithub

Focusing on data science for mobility

Bench Press 100kg!