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

feat(auth): Resend MFA code #3409

Closed
wants to merge 16 commits into from
7 changes: 7 additions & 0 deletions infra/lib/auth/common.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

import type { AdminSetUserMFAPreferenceCommandInput } from "@aws-sdk/client-cognito-identity-provider";

/**
* Custom headers used in API Gateways.
*
Expand All @@ -13,3 +15,8 @@ export const CUSTOM_HEADERS = [
"x-query-test-key",
"x-query-special-key",
];

export type UserMfaPreference = Pick<
AdminSetUserMFAPreferenceCommandInput,
"SMSMfaSettings" | "SoftwareTokenMfaSettings"
>;
2 changes: 1 addition & 1 deletion infra/lib/auth/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ type Subscription {

input CreateUserInput {
username: String!
password: String
password: String!
autoConfirm: Boolean
enableMFA: Boolean
verifyAttributes: Boolean
Expand Down
202 changes: 103 additions & 99 deletions infra/lib/auth/stack.create-user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import type * as lambda from "aws-lambda";
interface CreateUserInput {
input: {
username: string;
password?: string;
password: string;
autoConfirm?: boolean;
enableMFA?: boolean;
verifyAttributes?: boolean;
Expand All @@ -24,7 +24,7 @@ interface CreateUserResponse {
error?: string;
}

const USER_POOL_ID = process.env.USER_POOL_ID;
const { USER_POOL_ID } = process.env;
const CLIENT = new cognito.CognitoIdentityProviderClient({
region: process.env.REGION,
});
Expand All @@ -35,123 +35,127 @@ export const handler: lambda.AppSyncResolverHandler<
> = async (
event: lambda.AppSyncResolverEvent<CreateUserInput>
): Promise<CreateUserResponse> => {
console.log(`Got event: ${JSON.stringify(event, null, 2)}`);
console.log(`Got event: ${JSON.stringify(event, null, 2)}`);

const { input } = event.arguments;
const { username } = input;
const { input } = event.arguments;
const { username, password, autoConfirm, enableMFA, verifyAttributes } = input;

const baseParams = {
UserPoolId: USER_POOL_ID,
Username: username,
};

console.log(`Creating user ${username}...`);
let cognitoUsername: string;
try {
const UserAttributes: cognito.AttributeType[] = [];
if (input.email) {
UserAttributes.push({ Name: "email", Value: input.email });
}
if (input.phoneNumber) {
UserAttributes.push({ Name: "phone_number", Value: input.phoneNumber });
}
if (input.name) {
UserAttributes.push({ Name: "name", Value: input.name });
}
if (input.givenName) {
UserAttributes.push({ Name: "given_name", Value: input.givenName });
}
const createUserParams: cognito.AdminCreateUserCommandInput = {
...baseParams,
TemporaryPassword: input.password,
UserAttributes,
};
const resp = await CLIENT.send(
new cognito.AdminCreateUserCommand(createUserParams)
);
console.log(`Successfully created user: ${username}`, resp);
cognitoUsername = resp.User!.Username!;
} catch (err: any) {
console.error(`Could not create user ${username}`, err);
return {
success: false,
error: err.toString(),
const baseParams = {
UserPoolId: USER_POOL_ID,
Username: username,
};
}

if (input.autoConfirm) {
console.log(`Updating password for ${username}...`);
console.log(`Creating user ${username}...`);
let cognitoUsername: string;
try {
const setPasswordParams: cognito.AdminSetUserPasswordCommandInput = {
const UserAttributes: cognito.AttributeType[] = [];
if (input.email) {
UserAttributes.push({ Name: "email", Value: input.email });
}
if (input.phoneNumber) {
UserAttributes.push({ Name: "phone_number", Value: input.phoneNumber });
}
if (input.name) {
UserAttributes.push({ Name: "name", Value: input.name });
}
if (input.givenName) {
UserAttributes.push({ Name: "given_name", Value: input.givenName });
}
const createUserParams: cognito.AdminCreateUserCommandInput = {
...baseParams,
Password: input.password,
Permanent: true,
TemporaryPassword: input.password,
UserAttributes,
};
const resp = await CLIENT.send(
new cognito.AdminSetUserPasswordCommand(setPasswordParams)
);
console.log(
`Updated password for ${username} to ${input.password}`,
resp
new cognito.AdminCreateUserCommand(createUserParams)
);
console.log(`Successfully created user: ${username}`, resp);
cognitoUsername = resp.User!.Username!;
} catch (err: any) {
console.log(`Could not update password for ${username}`, err);
console.error(`Could not create user ${username}`, err);
return {
success: false,
error: err.toString(),
};
}
}

if (input.enableMFA) {
console.log(`Enabling MFA for ${username}...`);
try {
const mfaParams: cognito.AdminSetUserMFAPreferenceCommandInput = {
...baseParams,
SMSMfaSettings: {
Enabled: true,
PreferredMfa: true,
},
};
const resp = await CLIENT.send(
new cognito.AdminSetUserMFAPreferenceCommand(mfaParams)
);
console.log(`Successfully enabled MFA for ${username}`, resp);
} catch (err: any) {
console.log(`Could not enable MFA for ${username}`, err);
return {
success: false,
error: err.toString(),
};
if (autoConfirm) {
console.log(`Updating password for ${username}...`);
try {
const setPasswordParams: cognito.AdminSetUserPasswordCommandInput = {
...baseParams,
Password: input.password,
Permanent: true,
};
const resp = await CLIENT.send(
new cognito.AdminSetUserPasswordCommand(setPasswordParams)
);
console.log(
`Updated password for ${username} to ${input.password}`,
resp
);
} catch (err: any) {
console.log(`Could not update password for ${username}`, err);
return {
success: false,
error: err.toString(),
};
}
}
}

if (input.verifyAttributes) {
console.log(`Verifying attributes for ${username}...`);
try {
const userAttributesParams: cognito.AdminUpdateUserAttributesCommandInput =
if (enableMFA) {
console.log(`Enabling MFA for ${username}...`);
try {
const mfaParams: cognito.AdminSetUserMFAPreferenceCommandInput = {
...baseParams,
SMSMfaSettings: {
Enabled: true,
PreferredMfa: true,
},
};
const resp = await CLIENT.send(
new cognito.AdminSetUserMFAPreferenceCommand(mfaParams),
);
console.log(`Successfully enabled MFA for ${username}`, resp);
} catch (err: any) {
console.log(`Could not enable MFA for ${username}`, err);
return {
success: false,
error: err.toString(),
};
}
}

if (verifyAttributes) {
console.log(`Verifying attributes for ${username}...`);
try {
const userAttributes: cognito.AttributeType[] = [];
if (input.email) {
userAttributes.push({ Name: "email_verified", Value: "true" });
}
if (input.phoneNumber) {
userAttributes.push({ Name: "phone_number_verified", Value: "true" });
}
const userAttributesParams: cognito.AdminUpdateUserAttributesCommandInput =
{
...baseParams,
UserAttributes: [
{ Name: "phone_number_verified", Value: "true" },
{ Name: "email_verified", Value: "true" },
],
UserAttributes: userAttributes,
};
const resp = await CLIENT.send(
new cognito.AdminUpdateUserAttributesCommand(userAttributesParams)
);
console.log(`Successfully verified attributes for ${username}`, resp);
} catch (err: any) {
console.log(`Could not verify attributes for ${username}`, err);
return {
success: false,
error: err.toString(),
};
const resp = await CLIENT.send(
new cognito.AdminUpdateUserAttributesCommand(userAttributesParams)
);
console.log(`Successfully verified attributes for ${username}`, resp);
} catch (err: any) {
console.log(`Could not verify attributes for ${username}`, err);
return {
success: false,
error: err.toString(),
};
}
}
}

return {
success: true,
cognitoUsername,
};
};
return {
success: true,
cognitoUsername,
};
};
Loading