Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JavaScript (v3): Cognito - Add the "auto-confirm user" scenario. Part of the Pools and Triggers workflow. #7056

Merged
merged 11 commits into from
Nov 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions .doc_gen/metadata/cognito-identity-provider_metadata.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -753,6 +753,14 @@ cognito-identity-provider_DeleteUser:
snippet_tags:
- gov2.cognito-identity-provider.CognitoActions.struct
- gov2.cognito-identity-provider.DeleteUser
JavaScript:
versions:
- sdk_version: 3
github: javascriptv3/example_code/cross-services/wkflw-pools-triggers
excerpts:
- description:
snippet_tags:
- javascript.v3.cognito-idp.actions.DeleteUser
services:
cognito-identity-provider: {DeleteUser}
cognito-identity-provider_CreateUserPool:
Expand Down Expand Up @@ -793,6 +801,15 @@ cognito-identity-provider_UpdateUserPool:
snippet_tags:
- gov2.cognito-identity-provider.CognitoActions.struct
- gov2.cognito-identity-provider.UpdateUserPool
JavaScript:
versions:
- sdk_version: 3
github: javascriptv3/example_code/cross-services/wkflw-pools-triggers
sdkguide:
excerpts:
- description:
snippet_tags:
- javascript.v3.cognito-idp.actions.UpdateUserPool
services:
cognito-identity-provider: {UpdateUserPool}
cognito-identity-provider_ForgotPassword:
Expand Down
32 changes: 32 additions & 0 deletions .doc_gen/metadata/cross_metadata.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -822,6 +822,38 @@ cross_CognitoAutoConfirmUser:
- description: Clean up resources.
snippet_tags:
- gov2.cognito-identity-provider.Resources.complete
JavaScript:
versions:
- sdk_version: 3
github: javascriptv3/example_code/cross-services/wkflw-pools-triggers
sdk_guide:
excerpts:
- description: |
Configure an interactive "Scenario" run. The JavaScript (v3) examples
share a Scenario runner to streamline complex examples. The complete
source code is on GitHub.
snippet_tags:
- javascript.v3.wkflw.pools-triggers.index
- description: |
This Scenario demonstrates auto-confirming a known user.
It orchestrates the example steps.
snippet_tags:
- javascript.v3.wkflw.pools-triggers.AutoConfirm
- description: These are steps that are shared with other Scenarios.
snippet_tags:
- javascript.v3.wkflw.pools-triggers.common
- description: A handler for the <code>PreSignUp</code> trigger with a &LAM; function.
snippet_tags:
- javascript.v3.wkflw.pools-triggers.handler.AutoConfirm
- description: Module of &CWL; actions.
snippet_files:
- javascriptv3/example_code/cross-services/wkflw-pools-triggers/actions/cloudwatch-logs-actions.js
- description: Module of &COG; actions.
snippet_files:
- javascriptv3/example_code/cross-services/wkflw-pools-triggers/actions/cognito-actions.js
- description: Module of &DDB; actions.
snippet_files:
- javascriptv3/example_code/cross-services/wkflw-pools-triggers/actions/dynamodb-actions.js
services:
cognito-identity-provider: {UpdateUserPool, SignUp, InitiateAuth, DeleteUser}
lambda: {}
Expand Down
4 changes: 3 additions & 1 deletion javascriptv3/biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
"./example_code/kinesis/kinesis-cdk",
"./example_code/medical-imaging/scenarios/health-image-sets/pixel-data-verification/openjphjs/openjphjs.js",
"./example_code/cross-services/textract-react",
"**/dist"
"**/dist",
"**/cdk.out",
"cdk.json"
]
},
"formatter": {
Expand Down
19 changes: 19 additions & 0 deletions javascriptv3/example_code/cognito-identity-provider/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,18 +44,21 @@ Code excerpts that show you how to call individual service functions.
- [AssociateSoftwareToken](actions/associate-software-token.js#L9)
- [ConfirmDevice](actions/confirm-device.js#L9)
- [ConfirmSignUp](actions/confirm-sign-up.js#L9)
- [DeleteUser](../cross-services/wkflw-pools-triggers/actions/cognito-actions.js#L122)
- [InitiateAuth](actions/initiate-auth.js#L10)
- [ListUsers](actions/list-users.js#L9)
- [ResendConfirmationCode](actions/resend-confirmation-code.js#L9)
- [RespondToAuthChallenge](actions/respond-to-auth-challenge.js#L10)
- [SignUp](actions/sign-up.js#L9)
- [UpdateUserPool](../cross-services/wkflw-pools-triggers/actions/cognito-actions.js#L13)
- [VerifySoftwareToken](actions/verify-software-token.js#L9)

### Scenarios

Code examples that show you how to accomplish a specific task by calling multiple
functions within the same service.

- [Automatically confirm known users with a Lambda function](../cross-services/wkflw-pools-triggers/index.js)
- [Sign up a user with a user pool that requires MFA](actions/admin-initiate-auth.js)


Expand Down Expand Up @@ -104,6 +107,22 @@ node ./hello.js
```


#### Automatically confirm known users with a Lambda function

This example shows you how to automatically confirm known Amazon Cognito users with a Lambda function.

- Configure a user pool to call a Lambda function for the <code>PreSignUp</code> trigger.
- Sign up a user with Amazon Cognito.
- The Lambda function scans a DynamoDB table and automatically confirms known users.
- Sign in as the new user, then clean up resources.

<!--custom.scenario_prereqs.cross_CognitoAutoConfirmUser.start-->
<!--custom.scenario_prereqs.cross_CognitoAutoConfirmUser.end-->


<!--custom.scenarios.cross_CognitoAutoConfirmUser.start-->
<!--custom.scenarios.cross_CognitoAutoConfirmUser.end-->

#### Sign up a user with a user pool that requires MFA

This example shows you how to do the following:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# Customize Amazon Cognito authentication behavior with Lambda functions

## Overview

This example shows how to use AWS SDKs to customize Amazon Cognito authentication behavior. You can configure
your Amazon Cognito user pool to automatically invoke AWS Lambda functions at various points in the authentication
process, such as before sign-up, during sign-in, and after authentication.

There are three workflows demonstrated by this example:

* Automatically confirm and verify the email of known users by using a pre sign-up trigger.
* [Not yet implemented] Automatically add known users at sign-in by using a migrate user trigger.
* [Not yet implemented] Write custom information to an Amazon DynamoDB table after users are authenticated by using a post authentication trigger.

These workflows are described in more detail in the main [README](../../../../workflows/user_pools_and_lambda_triggers/README.md)
for these examples.

## Automatically confirm known users

A [pre sign-up Lambda trigger](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-pre-sign-up.html)
is invoked when a user starts the sign-up process and lets your Lambda function
take action before Amazon Cognito adds the user to the user pool.

## Automatically migrate known users

A [migrate user Lambda trigger](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-migrate-user.html)
is invoked when a user doesn't exist in the user pool at sign-in with a password.
After the Lambda function returns successfully, Amazon Cognito creates the user in the user pool.

## Write custom activity after authentication

A [post authentication Lambda trigger](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-post-authentication.html)
is invoked after signing in a user, so you can add custom logic after Amazon Cognito authenticates the user.

## ⚠ Important

* Running this code might result in charges to your AWS account.
* Running the tests might result in charges to your AWS account.
* We recommend that you grant your code least privilege. At most, grant only the minimum permissions required to perform the task. For more information, see [Grant least privilege](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege).
* This code is not tested in every AWS Region. For more information, see [AWS Regional Services](https://aws.amazon.com/about-aws/global-infrastructure/regional-product-services).

## Run the examples

### Prerequisites

For general prerequisites, see the [README](../../../README.md#prerequisites) in the `javascriptv3` folder.

### Setup

This example deploys several resources by using an AWS CloudFormation stack. This stack
deploys the following resources:

* An Amazon DynamoDB table named `doc-example-custom-users` that has a `UserEmail` primary key.
This table functions as an external user store.
* An Amazon Cognito user pool that requires an email, sends an email with verification code
when a new user is added, does not require MFA, and allows account recovery with a verified email.
* An Amazon Cognito client application. This is required for client calls to sign-up and
authentication users.
* An AWS Identity and Access Management (IAM) role that can be assumed by Lambda.
This role grants permission to Lambda to read from and write to the DynamoDB table and
write to CloudWatch Logs.

### Deploy AWS resources

The AWS resources for this example are deployed by using the AWS Cloud Development Kit (AWS CDK).

To install the AWS CDK, follow the instructions in the
[Developer Guide](https://docs.aws.amazon.com/cdk/v2/guide/home.html).

Deploy resources at a command prompt from the [cdk](./cdk/) folder:

```
npm install
cdk deploy
```

### Instructions

Run `./index --help` for instructions on running a scenario.

### Cleanup

Delete resources deployed for this example by deleting the stack.

Delete the stack at a command prompt from the [cdk](./cdk/) folder:

```
cdk destroy
```

## Additional resources

- [Amazon Cognito Identity Provider Developer Guide](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-identity-pools.html)
- [Amazon Cognito Identity Provider API Reference](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/Welcome.html)
- [SDK for JavaScript V3 Amazon Cognito Identity Provider reference](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/cognito-identity-provider/)

---

Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. SPDX-License-Identifier: Apache-2.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

import {
CloudWatchLogsClient,
GetLogEventsCommand,
OrderBy,
paginateDescribeLogStreams,
} from "@aws-sdk/client-cloudwatch-logs";

/**
* Get the latest log stream for a Lambda function.
* @param {{ functionName: string, region: string }} config
* @returns {Promise<[import("@aws-sdk/client-cloudwatch-logs").LogStream | null, unknown]>}
*/
export const getLatestLogStreamForLambda = async ({ functionName, region }) => {
try {
const logGroupName = `/aws/lambda/${functionName}`;
const cwlClient = new CloudWatchLogsClient({ region });
const paginator = paginateDescribeLogStreams(
{ client: cwlClient },
{
descending: true,
limit: 1,
orderBy: OrderBy.LastEventTime,
logGroupName,
},
);

for await (const page of paginator) {
return [page.logStreams[0], null];
}
} catch (err) {
return [null, err];
}
};

/**
* Get the log events for a Lambda function's log stream.
* @param {{
* functionName: string,
* logStreamName: string,
* eventCount: number,
* region: string
* }} config
* @returns {Promise<[import("@aws-sdk/client-cloudwatch-logs").OutputLogEvent[] | null, unknown]>}
*/
export const getLogEvents = async ({
functionName,
logStreamName,
eventCount,
region,
}) => {
try {
const cwlClient = new CloudWatchLogsClient({ region });
const logGroupName = `/aws/lambda/${functionName}`;
const response = await cwlClient.send(
new GetLogEventsCommand({
logStreamName: logStreamName,
limit: eventCount,
logGroupName: logGroupName,
}),
);

return [response.events, null];
} catch (err) {
return [null, err];
}
};
Loading
Loading