Amazon Cognito Identity Provider examples using SDK for JavaScript (v3) (original) (raw)
Configure an interactive "Scenario" run. The JavaScript (v3) examples share a Scenario runner to streamline complex examples. The complete source code is on GitHub.
import { AutoConfirm } from "./scenario-auto-confirm.js";
/**
* The context is passed to every scenario. Scenario steps
* will modify the context.
*/
const context = {
errors: [],
users: [
{
UserName: "test_user_1",
UserEmail: "test_email_1@example.com",
},
{
UserName: "test_user_2",
UserEmail: "test_email_2@example.com",
},
{
UserName: "test_user_3",
UserEmail: "test_email_3@example.com",
},
],
};
/**
* Three Scenarios are created for the workflow. A Scenario is an orchestration class
* that simplifies running a series of steps.
*/
export const scenarios = {
// Demonstrate automatically confirming known users in a database.
"auto-confirm": AutoConfirm(context),
};
// Call function if run directly
import { fileURLToPath } from "node:url";
import { parseScenarioArgs } from "@aws-doc-sdk-examples/lib/scenario/index.js";
if (process.argv[1] === fileURLToPath(import.meta.url)) {
parseScenarioArgs(scenarios, {
name: "Cognito user pools and triggers",
description:
"Demonstrate how to use the AWS SDKs to customize Amazon Cognito authentication behavior.",
});
}
This Scenario demonstrates auto-confirming a known user. It orchestrates the example steps.
import { wait } from "@aws-doc-sdk-examples/lib/utils/util-timers.js";
import {
Scenario,
ScenarioAction,
ScenarioInput,
ScenarioOutput,
} from "@aws-doc-sdk-examples/lib/scenario/scenario.js";
import {
getStackOutputs,
logCleanUpReminder,
promptForStackName,
promptForStackRegion,
skipWhenErrors,
} from "./steps-common.js";
import { populateTable } from "./actions/dynamodb-actions.js";
import {
addPreSignUpHandler,
deleteUser,
getUser,
signIn,
signUpUser,
} from "./actions/cognito-actions.js";
import {
getLatestLogStreamForLambda,
getLogEvents,
} from "./actions/cloudwatch-logs-actions.js";
/**
* @typedef {{
* errors: Error[],
* password: string,
* users: { UserName: string, UserEmail: string }[],
* selectedUser?: string,
* stackName?: string,
* stackRegion?: string,
* token?: string,
* confirmDeleteSignedInUser?: boolean,
* TableName?: string,
* UserPoolClientId?: string,
* UserPoolId?: string,
* UserPoolArn?: string,
* AutoConfirmHandlerArn?: string,
* AutoConfirmHandlerName?: string
* }} State
*/
const greeting = new ScenarioOutput(
"greeting",
(/** @type {State} */ state) => `This demo will populate some users into the \
database created as part of the "${state.stackName}" stack. \
Then the AutoConfirmHandler will be linked to the PreSignUp \
trigger from Cognito. Finally, you will choose a user to sign up.`,
{ skipWhen: skipWhenErrors },
);
const logPopulatingUsers = new ScenarioOutput(
"logPopulatingUsers",
"Populating the DynamoDB table with some users.",
{ skipWhenErrors: skipWhenErrors },
);
const logPopulatingUsersComplete = new ScenarioOutput(
"logPopulatingUsersComplete",
"Done populating users.",
{ skipWhen: skipWhenErrors },
);
const populateUsers = new ScenarioAction(
"populateUsers",
async (/** @type {State} */ state) => {
const [_, err] = await populateTable({
region: state.stackRegion,
tableName: state.TableName,
items: state.users,
});
if (err) {
state.errors.push(err);
}
},
{
skipWhen: skipWhenErrors,
},
);
const logSetupSignUpTrigger = new ScenarioOutput(
"logSetupSignUpTrigger",
"Setting up the PreSignUp trigger for the Cognito User Pool.",
{ skipWhen: skipWhenErrors },
);
const setupSignUpTrigger = new ScenarioAction(
"setupSignUpTrigger",
async (/** @type {State} */ state) => {
const [_, err] = await addPreSignUpHandler({
region: state.stackRegion,
userPoolId: state.UserPoolId,
handlerArn: state.AutoConfirmHandlerArn,
});
if (err) {
state.errors.push(err);
}
},
{
skipWhen: skipWhenErrors,
},
);
const logSetupSignUpTriggerComplete = new ScenarioOutput(
"logSetupSignUpTriggerComplete",
(
/** @type {State} */ state,
) => `The lambda function "${state.AutoConfirmHandlerName}" \
has been configured as the PreSignUp trigger handler for the user pool "${state.UserPoolId}".`,
{ skipWhen: skipWhenErrors },
);
const selectUser = new ScenarioInput(
"selectedUser",
"Select a user to sign up.",
{
type: "select",
choices: (/** @type {State} */ state) => state.users.map((u) => u.UserName),
skipWhen: skipWhenErrors,
default: (/** @type {State} */ state) => state.users[0].UserName,
},
);
const checkIfUserAlreadyExists = new ScenarioAction(
"checkIfUserAlreadyExists",
async (/** @type {State} */ state) => {
const [user, err] = await getUser({
region: state.stackRegion,
userPoolId: state.UserPoolId,
username: state.selectedUser,
});
if (err?.name === "UserNotFoundException") {
// Do nothing. We're not expecting the user to exist before
// sign up is complete.
return;
}
if (err) {
state.errors.push(err);
return;
}
if (user) {
state.errors.push(
new Error(
`The user "${state.selectedUser}" already exists in the user pool "${state.UserPoolId}".`,
),
);
}
},
{
skipWhen: skipWhenErrors,
},
);
const createPassword = new ScenarioInput(
"password",
"Enter a password that has at least eight characters, uppercase, lowercase, numbers and symbols.",
{ type: "password", skipWhen: skipWhenErrors, default: "Abcd1234!" },
);
const logSignUpExistingUser = new ScenarioOutput(
"logSignUpExistingUser",
(/** @type {State} */ state) => `Signing up user "${state.selectedUser}".`,
{ skipWhen: skipWhenErrors },
);
const signUpExistingUser = new ScenarioAction(
"signUpExistingUser",
async (/** @type {State} */ state) => {
const signUp = (password) =>
signUpUser({
region: state.stackRegion,
userPoolClientId: state.UserPoolClientId,
username: state.selectedUser,
email: state.users.find((u) => u.UserName === state.selectedUser)
.UserEmail,
password,
});
let [_, err] = await signUp(state.password);
while (err?.name === "InvalidPasswordException") {
console.warn("The password you entered was invalid.");
await createPassword.handle(state);
[_, err] = await signUp(state.password);
}
if (err) {
state.errors.push(err);
}
},
{ skipWhen: skipWhenErrors },
);
const logSignUpExistingUserComplete = new ScenarioOutput(
"logSignUpExistingUserComplete",
(/** @type {State} */ state) =>
`"${state.selectedUser} was signed up successfully.`,
{ skipWhen: skipWhenErrors },
);
const logLambdaLogs = new ScenarioAction(
"logLambdaLogs",
async (/** @type {State} */ state) => {
console.log(
"Waiting a few seconds to let Lambda write to CloudWatch Logs...\n",
);
await wait(10);
const [logStream, logStreamErr] = await getLatestLogStreamForLambda({
functionName: state.AutoConfirmHandlerName,
region: state.stackRegion,
});
if (logStreamErr) {
state.errors.push(logStreamErr);
return;
}
console.log(
`Getting some recent events from log stream "${logStream.logStreamName}"`,
);
const [logEvents, logEventsErr] = await getLogEvents({
functionName: state.AutoConfirmHandlerName,
region: state.stackRegion,
eventCount: 10,
logStreamName: logStream.logStreamName,
});
if (logEventsErr) {
state.errors.push(logEventsErr);
return;
}
console.log(logEvents.map((ev) => `\t${ev.message}`).join(""));
},
{ skipWhen: skipWhenErrors },
);
const logSignInUser = new ScenarioOutput(
"logSignInUser",
(/** @type {State} */ state) => `Let's sign in as ${state.selectedUser}`,
{ skipWhen: skipWhenErrors },
);
const signInUser = new ScenarioAction(
"signInUser",
async (/** @type {State} */ state) => {
const [response, err] = await signIn({
region: state.stackRegion,
clientId: state.UserPoolClientId,
username: state.selectedUser,
password: state.password,
});
if (err?.name === "PasswordResetRequiredException") {
state.errors.push(new Error("Please reset your password."));
return;
}
if (err) {
state.errors.push(err);
return;
}
state.token = response?.AuthenticationResult?.AccessToken;
},
{ skipWhen: skipWhenErrors },
);
const logSignInUserComplete = new ScenarioOutput(
"logSignInUserComplete",
(/** @type {State} */ state) =>
`Successfully signed in. Your access token starts with: ${state.token.slice(0, 11)}`,
{ skipWhen: skipWhenErrors },
);
const confirmDeleteSignedInUser = new ScenarioInput(
"confirmDeleteSignedInUser",
"Do you want to delete the currently signed in user?",
{ type: "confirm", skipWhen: skipWhenErrors },
);
const deleteSignedInUser = new ScenarioAction(
"deleteSignedInUser",
async (/** @type {State} */ state) => {
const [_, err] = await deleteUser({
region: state.stackRegion,
accessToken: state.token,
});
if (err) {
state.errors.push(err);
}
},
{
skipWhen: (/** @type {State} */ state) =>
skipWhenErrors(state) || !state.confirmDeleteSignedInUser,
},
);
const logErrors = new ScenarioOutput(
"logErrors",
(/** @type {State}*/ state) => {
const errorList = state.errors
.map((err) => ` - <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mrow><mi>e</mi><mi>r</mi><mi>r</mi><mi mathvariant="normal">.</mi><mi>n</mi><mi>a</mi><mi>m</mi><mi>e</mi></mrow><mo>:</mo></mrow><annotation encoding="application/x-tex">{err.name}: </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.02778em;">err</span><span class="mord">.</span><span class="mord mathnormal">nam</span><span class="mord mathnormal">e</span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">:</span></span></span></span>{err.message}`)
.join("\n");
return `Scenario errors found:\n${errorList}`;
},
{
// Don't log errors when there aren't any!
skipWhen: (/** @type {State} */ state) => state.errors.length === 0,
},
);
export const AutoConfirm = (context) =>
new Scenario(
"AutoConfirm",
[
promptForStackName,
promptForStackRegion,
getStackOutputs,
greeting,
logPopulatingUsers,
populateUsers,
logPopulatingUsersComplete,
logSetupSignUpTrigger,
setupSignUpTrigger,
logSetupSignUpTriggerComplete,
selectUser,
checkIfUserAlreadyExists,
createPassword,
logSignUpExistingUser,
signUpExistingUser,
logSignUpExistingUserComplete,
logLambdaLogs,
logSignInUser,
signInUser,
logSignInUserComplete,
confirmDeleteSignedInUser,
deleteSignedInUser,
logCleanUpReminder,
logErrors,
],
context,
);
These are steps that are shared with other Scenarios.
import {
ScenarioAction,
ScenarioInput,
ScenarioOutput,
} from "@aws-doc-sdk-examples/lib/scenario/scenario.js";
import { getCfnOutputs } from "@aws-doc-sdk-examples/lib/sdk/cfn-outputs.js";
export const skipWhenErrors = (state) => state.errors.length > 0;
export const getStackOutputs = new ScenarioAction(
"getStackOutputs",
async (state) => {
if (!state.stackName || !state.stackRegion) {
state.errors.push(
new Error(
"No stack name or region provided. The stack name and \
region are required to fetch CFN outputs relevant to this example.",
),
);
return;
}
const outputs = await getCfnOutputs(state.stackName, state.stackRegion);
Object.assign(state, outputs);
},
);
export const promptForStackName = new ScenarioInput(
"stackName",
"Enter the name of the stack you deployed earlier.",
{ type: "input", default: "PoolsAndTriggersStack" },
);
export const promptForStackRegion = new ScenarioInput(
"stackRegion",
"Enter the region of the stack you deployed earlier.",
{ type: "input", default: "us-east-1" },
);
export const logCleanUpReminder = new ScenarioOutput(
"logCleanUpReminder",
"All done. Remember to run 'cdk destroy' to teardown the stack.",
{ skipWhen: skipWhenErrors },
);
A handler for the PreSignUp
trigger with a Lambda function.
import type { PreSignUpTriggerEvent, Handler } from "aws-lambda";
import type { UserRepository } from "./user-repository";
import { DynamoDBUserRepository } from "./user-repository";
export class PreSignUpHandler {
private userRepository: UserRepository;
constructor(userRepository: UserRepository) {
this.userRepository = userRepository;
}
private isPreSignUpTriggerSource(event: PreSignUpTriggerEvent): boolean {
return event.triggerSource === "PreSignUp_SignUp";
}
private getEventUserEmail(event: PreSignUpTriggerEvent): string {
return event.request.userAttributes.email;
}
async handlePreSignUpTriggerEvent(
event: PreSignUpTriggerEvent,
): Promise<PreSignUpTriggerEvent> {
console.log(
`Received presignup from <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mrow><mi>e</mi><mi>v</mi><mi>e</mi><mi>n</mi><mi>t</mi><mi mathvariant="normal">.</mi><mi>t</mi><mi>r</mi><mi>i</mi><mi>g</mi><mi>g</mi><mi>e</mi><mi>r</mi><mi>S</mi><mi>o</mi><mi>u</mi><mi>r</mi><mi>c</mi><mi>e</mi></mrow><mi>f</mi><mi>o</mi><mi>r</mi><mi>u</mi><mi>s</mi><mi>e</mi><msup><mi>r</mi><mo mathvariant="normal" lspace="0em" rspace="0em">′</mo></msup></mrow><annotation encoding="application/x-tex">{event.triggerSource} for user '</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9463em;vertical-align:-0.1944em;"></span><span class="mord"><span class="mord mathnormal">e</span><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="mord mathnormal">e</span><span class="mord mathnormal">n</span><span class="mord mathnormal">t</span><span class="mord">.</span><span class="mord mathnormal">t</span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="mord mathnormal">i</span><span class="mord mathnormal" style="margin-right:0.03588em;">gg</span><span class="mord mathnormal" style="margin-right:0.02778em;">er</span><span class="mord mathnormal" style="margin-right:0.05764em;">S</span><span class="mord mathnormal">o</span><span class="mord mathnormal">u</span><span class="mord mathnormal">rce</span></span><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="mord mathnormal" style="margin-right:0.02778em;">or</span><span class="mord mathnormal">u</span><span class="mord mathnormal">se</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7519em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">′</span></span></span></span></span></span></span></span></span></span></span></span>{event.userName}'`,
);
if (!this.isPreSignUpTriggerSource(event)) {
return event;
}
const eventEmail = this.getEventUserEmail(event);
console.log(`Looking up email ${eventEmail}.`);
const storedUserInfo =
await this.userRepository.getUserInfoByEmail(eventEmail);
if (!storedUserInfo) {
console.log(
`Email ${eventEmail} not found. Email verification is required.`,
);
return event;
}
if (storedUserInfo.UserName !== event.userName) {
console.log(
`UserEmail <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mrow><mi>e</mi><mi>v</mi><mi>e</mi><mi>n</mi><mi>t</mi><mi>E</mi><mi>m</mi><mi>a</mi><mi>i</mi><mi>l</mi></mrow><mi>f</mi><mi>o</mi><mi>u</mi><mi>n</mi><mi>d</mi><mo separator="true">,</mo><mi>b</mi><mi>u</mi><mi>t</mi><mi>s</mi><mi>t</mi><mi>o</mi><mi>r</mi><mi>e</mi><mi>d</mi><mi>U</mi><mi>s</mi><mi>e</mi><mi>r</mi><mi>N</mi><mi>a</mi><mi>m</mi><msup><mi>e</mi><mo mathvariant="normal" lspace="0em" rspace="0em">′</mo></msup></mrow><annotation encoding="application/x-tex">{eventEmail} found, but stored UserName '</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9463em;vertical-align:-0.1944em;"></span><span class="mord"><span class="mord mathnormal">e</span><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="mord mathnormal">e</span><span class="mord mathnormal">n</span><span class="mord mathnormal" style="margin-right:0.05764em;">tE</span><span class="mord mathnormal">mai</span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span></span><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="mord mathnormal">o</span><span class="mord mathnormal">u</span><span class="mord mathnormal">n</span><span class="mord mathnormal">d</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">b</span><span class="mord mathnormal">u</span><span class="mord mathnormal">t</span><span class="mord mathnormal">s</span><span class="mord mathnormal">t</span><span class="mord mathnormal">ore</span><span class="mord mathnormal">d</span><span class="mord mathnormal" style="margin-right:0.10903em;">U</span><span class="mord mathnormal" style="margin-right:0.02778em;">ser</span><span class="mord mathnormal" style="margin-right:0.10903em;">N</span><span class="mord mathnormal">am</span><span class="mord"><span class="mord mathnormal">e</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7519em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">′</span></span></span></span></span></span></span></span></span></span></span></span>{storedUserInfo.UserName}' does not match supplied UserName '${event.userName}'. Verification is required.`,
);
} else {
console.log(
`UserEmail <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mrow><mi>e</mi><mi>v</mi><mi>e</mi><mi>n</mi><mi>t</mi><mi>E</mi><mi>m</mi><mi>a</mi><mi>i</mi><mi>l</mi></mrow><mi>f</mi><mi>o</mi><mi>u</mi><mi>n</mi><mi>d</mi><mi>w</mi><mi>i</mi><mi>t</mi><mi>h</mi><mi>m</mi><mi>a</mi><mi>t</mi><mi>c</mi><mi>h</mi><mi>i</mi><mi>n</mi><mi>g</mi><mi>U</mi><mi>s</mi><mi>e</mi><mi>r</mi><mi>N</mi><mi>a</mi><mi>m</mi><mi>e</mi></mrow><annotation encoding="application/x-tex">{eventEmail} found with matching UserName </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord"><span class="mord mathnormal">e</span><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="mord mathnormal">e</span><span class="mord mathnormal">n</span><span class="mord mathnormal" style="margin-right:0.05764em;">tE</span><span class="mord mathnormal">mai</span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span></span><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="mord mathnormal">o</span><span class="mord mathnormal">u</span><span class="mord mathnormal">n</span><span class="mord mathnormal">d</span><span class="mord mathnormal" style="margin-right:0.02691em;">w</span><span class="mord mathnormal">i</span><span class="mord mathnormal">t</span><span class="mord mathnormal">hma</span><span class="mord mathnormal">t</span><span class="mord mathnormal">c</span><span class="mord mathnormal">hin</span><span class="mord mathnormal" style="margin-right:0.10903em;">gU</span><span class="mord mathnormal" style="margin-right:0.02778em;">ser</span><span class="mord mathnormal" style="margin-right:0.10903em;">N</span><span class="mord mathnormal">am</span><span class="mord mathnormal">e</span></span></span></span>{storedUserInfo.UserName}. User is confirmed.`,
);
event.response.autoConfirmUser = true;
event.response.autoVerifyEmail = true;
}
return event;
}
}
const createPreSignUpHandler = (): PreSignUpHandler => {
const tableName = process.env.TABLE_NAME;
if (!tableName) {
throw new Error("TABLE_NAME environment variable is not set");
}
const userRepository = new DynamoDBUserRepository(tableName);
return new PreSignUpHandler(userRepository);
};
export const handler: Handler = async (event: PreSignUpTriggerEvent) => {
const preSignUpHandler = createPreSignUpHandler();
return preSignUpHandler.handlePreSignUpTriggerEvent(event);
};
Module of CloudWatch Logs actions.
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];
}
};
Module of Amazon Cognito actions.
import {
AdminGetUserCommand,
CognitoIdentityProviderClient,
DeleteUserCommand,
InitiateAuthCommand,
SignUpCommand,
UpdateUserPoolCommand,
} from "@aws-sdk/client-cognito-identity-provider";
/**
* Connect a Lambda function to the PreSignUp trigger for a Cognito user pool
* @param {{ region: string, userPoolId: string, handlerArn: string }} config
* @returns {Promise<[import("@aws-sdk/client-cognito-identity-provider").UpdateUserPoolCommandOutput | null, unknown]>}
*/
export const addPreSignUpHandler = async ({
region,
userPoolId,
handlerArn,
}) => {
try {
const cognitoClient = new CognitoIdentityProviderClient({
region,
});
const command = new UpdateUserPoolCommand({
UserPoolId: userPoolId,
LambdaConfig: {
PreSignUp: handlerArn,
},
});
const response = await cognitoClient.send(command);
return [response, null];
} catch (err) {
return [null, err];
}
};
/**
* Attempt to register a user to a user pool with a given username and password.
* @param {{
* region: string,
* userPoolClientId: string,
* username: string,
* email: string,
* password: string
* }} config
* @returns {Promise<[import("@aws-sdk/client-cognito-identity-provider").SignUpCommandOutput | null, unknown]>}
*/
export const signUpUser = async ({
region,
userPoolClientId,
username,
email,
password,
}) => {
try {
const cognitoClient = new CognitoIdentityProviderClient({
region,
});
const response = await cognitoClient.send(
new SignUpCommand({
ClientId: userPoolClientId,
Username: username,
Password: password,
UserAttributes: [{ Name: "email", Value: email }],
}),
);
return [response, null];
} catch (err) {
return [null, err];
}
};
/**
* Sign in a user to Amazon Cognito using a username and password authentication flow.
* @param {{ region: string, clientId: string, username: string, password: string }} config
* @returns {Promise<[import("@aws-sdk/client-cognito-identity-provider").InitiateAuthCommandOutput | null, unknown]>}
*/
export const signIn = async ({ region, clientId, username, password }) => {
try {
const cognitoClient = new CognitoIdentityProviderClient({ region });
const response = await cognitoClient.send(
new InitiateAuthCommand({
AuthFlow: "USER_PASSWORD_AUTH",
ClientId: clientId,
AuthParameters: { USERNAME: username, PASSWORD: password },
}),
);
return [response, null];
} catch (err) {
return [null, err];
}
};
/**
* Retrieve an existing user from a user pool.
* @param {{ region: string, userPoolId: string, username: string }} config
* @returns {Promise<[import("@aws-sdk/client-cognito-identity-provider").AdminGetUserCommandOutput | null, unknown]>}
*/
export const getUser = async ({ region, userPoolId, username }) => {
try {
const cognitoClient = new CognitoIdentityProviderClient({ region });
const response = await cognitoClient.send(
new AdminGetUserCommand({
UserPoolId: userPoolId,
Username: username,
}),
);
return [response, null];
} catch (err) {
return [null, err];
}
};
/**
* Delete the signed-in user. Useful for allowing a user to delete their
* own profile.
* @param {{ region: string, accessToken: string }} config
* @returns {Promise<[import("@aws-sdk/client-cognito-identity-provider").DeleteUserCommandOutput | null, unknown]>}
*/
export const deleteUser = async ({ region, accessToken }) => {
try {
const client = new CognitoIdentityProviderClient({ region });
const response = await client.send(
new DeleteUserCommand({ AccessToken: accessToken }),
);
return [response, null];
} catch (err) {
return [null, err];
}
};
Module of DynamoDB actions.
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import {
BatchWriteCommand,
DynamoDBDocumentClient,
} from "@aws-sdk/lib-dynamodb";
/**
* Populate a DynamoDB table with provide items.
* @param {{ region: string, tableName: string, items: Record<string, unknown>[] }} config
* @returns {Promise<[import("@aws-sdk/lib-dynamodb").BatchWriteCommandOutput | null, unknown]>}
*/
export const populateTable = async ({ region, tableName, items }) => {
try {
const ddbClient = new DynamoDBClient({ region });
const docClient = DynamoDBDocumentClient.from(ddbClient);
const response = await docClient.send(
new BatchWriteCommand({
RequestItems: {
[tableName]: items.map((item) => ({
PutRequest: {
Item: item,
},
})),
},
}),
);
return [response, null];
} catch (err) {
return [null, err];
}
};
- For API details, see the following topics in AWS SDK for JavaScript API Reference.