{"id":27288344,"url":"https://github.com/iwstkhr/aws-cognito-email-mfa-example","last_synced_at":"2025-04-11T20:33:06.438Z","repository":{"id":190979252,"uuid":"683624472","full_name":"iwstkhr/aws-cognito-email-mfa-example","owner":"iwstkhr","description":"Cognito custom authentication lamda triggers and an example script for Email MFA.","archived":false,"fork":false,"pushed_at":"2025-02-24T19:46:38.000Z","size":78,"stargazers_count":3,"open_issues_count":0,"forks_count":4,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-25T16:23:37.555Z","etag":null,"topics":["aws","cognito","custom-auth-challenge","lambda-triggers"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/iwstkhr.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-08-27T07:06:16.000Z","updated_at":"2025-02-24T19:52:48.000Z","dependencies_parsed_at":"2024-11-09T20:42:07.902Z","dependency_job_id":"3b138b2b-ca51-425a-8c80-f59e1943c0cb","html_url":"https://github.com/iwstkhr/aws-cognito-email-mfa-example","commit_stats":null,"previous_names":["iwstkhr/cognito-email-mfa-using-custom-auth-challenges","iwstkhr/aws-cognito-email-mfa-example"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iwstkhr%2Faws-cognito-email-mfa-example","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iwstkhr%2Faws-cognito-email-mfa-example/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iwstkhr%2Faws-cognito-email-mfa-example/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iwstkhr%2Faws-cognito-email-mfa-example/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/iwstkhr","download_url":"https://codeload.github.com/iwstkhr/aws-cognito-email-mfa-example/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248476447,"owners_count":21110285,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aws","cognito","custom-auth-challenge","lambda-triggers"],"created_at":"2025-04-11T20:32:13.082Z","updated_at":"2025-04-11T20:33:06.430Z","avatar_url":"https://github.com/iwstkhr.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"## Introduction\n\n\u003e [!IMPORTANT]\n\u003e Cognito user pools now supports email as a mfa option. For more information, please visit the [official announcement page](https://aws.amazon.com/about-aws/whats-new/2024/09/amazon-cognito-user-pools-email-authentication-option/).\n\nCognito comes with built-in support for the MFA feature, but developers can only choose from either SMS or TOTP options. However, many websites offer an additional email authentication. Developers can implement it using Cognito User Pool [custom authentication challenges](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-challenge.html).\n\n## Requirements\n\n- [Python 3.x](https://www.python.org/downloads/)\n- [boto3](https://github.com/boto/boto3)\n- [AWS SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/install-sam-cli.html)\n- Amazon Simple Email Service for sending OTP codes\n\nWhen you run the example script, you need to install the following:\n\n- [warrant](https://github.com/capless/warrant/)\n- [cryptography](https://github.com/pyca/cryptography/)\n- [python-jose](https://github.com/mpdavis/python-jose/)\n\n## Python Scripts\n\n### Lambda Layer\n\n[src/layers/python/layers/cognito_custom_challenge_helper.py](./src/layers/python/layers/cognito_custom_challenge_helper.py)\n\nIt is used to make it easy to handle custom challenge requests and responses.\n\n### Define Auth Challenge\n\n[src/define_auth_challenge/app.py](./src/define_auth_challenge/app.py)\n\nWhen starting the custom authentication flow, Cognito invokes [\"Define Auth challenge Lambda trigger\"](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-define-auth-challenge.html).\n\n### Create Auth Challenge\n\n[src/create_auth_challenge/app.py](./src/create_auth_challenge/app.py)\n\nWhen creating OTP codes which will be sent to users in the authentication challenge flow, Cognito invokes [\"Create Auth challenge Lambda trigger\"](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-create-auth-challenge.html).\n\nEnvironment variables [`CODE_LENGTH`](./src/create_auth_challenge/app.py#L12) and [`EMAIL_SENDER`](./src/create_auth_challenge/app.py#L13) in the script are specified by an AWS SAM template described later.\n\n\u003e [!TIP]\n\u003e By placing the OTP code issued from the last session into the response metadata, users can reuse the OTP code during the same authentication challenge session.\n\nYou can configure authentication flow session duration in Cognito.\n\n![](./docs/images/01.png)\n\n### Verify Auth Challenge\n\n[src/verify_auth_challenge/app.py](./src/verify_auth_challenge/app.py)\n\nWhen verifying OTP codes, Cognito invokes [\"Verify Auth challenge Lambda trigger\"](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-verify-auth-challenge-response.html).\n\n## Creating AWS Resources\n\n### AWS SAM Template\n\n[template.yaml](template.yaml)\n\nKey Points:\n\n- To enable custom authentication challenges, set [`ALLOW_CUSTOM_AUTH`](./template.yaml#L39) within `ExplicitAuthFlows`.\n- Please ensure that `CognitoEvent` within each `AWS::Serverless::Function` is linked to the Lambda functions to serve as Cognito Lambda triggers.\n- Setting [`Policies`](./template.yaml#L70-L75) in the `CreateAuthChallenge` function is required for sending emails using Amazon SES.\n\n### Build and Deploy\n\nReplace `\u003cYOUR_SES_EMAIL_SENDER\u003e` with a desired email address as a sender, and build and deploy with the following command.\nIf you want to change the length of OTP codes, also specify `CodeLength` parameter.\n\n```shell\nsam build\nsam deploy --parameter-overrides EmailSender=\u003cYOUR_SES_EMAIL_SENDER\u003e\n# sam deploy --parameter-overrides EmailSender=\u003cYOUR_SES_EMAIL_SENDER\u003e CodeLength=10\n```\n\nWhen completed, the following AWS resources are created in your AWS environment.\n\n| Logical ID| Type |\n| --------- | ---- |\n| CognitoUserPool | AWS::Cognito::UserPool |\n| CognitoUserPoolClient | AWS::Cognito::UserPoolClient |\n| LambdaLayer | AWS::Lambda::LayerVersion |\n| CreateAuthChallenge | AWS::Lambda::Function |\n| DefineAuthChallenge | AWS::Lambda::Function |\n| VerifyAuthChallenge | AWS::Lambda::Function |\n| CreateAuthChallengeCognitoPermission | AWS::Lambda::Permission |\n| DefineAuthChallengeCognitoPermission | AWS::Lambda::Permission |\n| VerifyAuthChallengeCognitoPermission | AWS::Lambda::Permission |\n| CreateAuthChallengeRole | AWS::IAM::Role |\n| DefineAuthChallengeRole | AWS::IAM::Role |\n| VerifyAuthChallengeRole | AWS::IAM::Role |\n\n## Testing\n\nReplace `\u003cYOUR_USER_POOL_ID\u003e` and `\u003cYOUR_EMAIL\u003e` with your values, and create a Cognito testing user with the following command.\n\n```shell\nPOOL_ID=\u003cYOUR_USER_POOL_ID\u003e\nEMAIL=\u003cYOUR_EMAIL\u003e\n\n# Add a Cognito user.\naws cognito-idp admin-create-user \\\n  --user-pool-id $POOL_ID \\\n  --username $EMAIL\n\n# Make the user confirmation status \"Confirmed\"\necho -n 'Password: '\nread password\naws cognito-idp admin-set-user-password \\\n  --user-pool-id $POOL_ID \\\n  --username $EMAIL \\\n  --password $password \\\n  --permanent\n```\n\nTo test the email MFA, run the following command.\n\n```shell\ncd src/example\npip install -r requirements.txt\npython main.py \\\n  --pool-id \u003cYOUR_USER_POOL_ID\u003e \\\n  --client-id \u003cYOUR_CLIENT_ID\u003e \\\n  --username \u003cYOUR_EMAIL\u003e \\\n  --password \u003cYOUR_PASSWORD\u003e\n```\n\nThe [`src/example/main.py`](./src/example/main.py) uses the following libraries to calculate values needed by [SRP - Secure Remote Password](https://en.wikipedia.org/wiki/Secure_Remote_Password_protocol).\n\n- [Warrant](https://github.com/capless/warrant/)\n- [pyca/cryptography](https://github.com/pyca/cryptography/)\n- [python-jose](https://github.com/mpdavis/python-jose/)\n\nYou may also refer to the AWS official [code example](https://docs.aws.amazon.com/cognito/latest/developerguide/example_cognito-identity-provider_RespondToAuthChallenge_section.html).\n\n## Cleaning Up\n\nClean up the provisioned AWS resources with the following command.\n\n```shell\nsam delete\n```\n\n---\n\n## (Optional) Unit Testing\n\nRun the following command in your shell.\n\n```shell\nexport PYTHONPATH=$PYTHONPATH:$(pwd)/src:$(pwd)/src/layers/python\npytest -vv\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fiwstkhr%2Faws-cognito-email-mfa-example","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fiwstkhr%2Faws-cognito-email-mfa-example","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fiwstkhr%2Faws-cognito-email-mfa-example/lists"}