diff --git a/src/services/tokenGenerator.ts b/src/services/tokenGenerator.ts index a9527937..c6aebd73 100644 --- a/src/services/tokenGenerator.ts +++ b/src/services/tokenGenerator.ts @@ -160,7 +160,7 @@ export class JwtTokenGenerator implements TokenGenerator { auth_time: authTime, email: attributeValue("email", user.Attributes), email_verified: Boolean( - attributeValue("email_verified", user.Attributes) ?? false + "true" == attributeValue("email_verified", user.Attributes) ?? false ), event_id: eventId, iat: authTime, diff --git a/src/targets/signUp.test.ts b/src/targets/signUp.test.ts index 4d79cc5a..63215eea 100644 --- a/src/targets/signUp.test.ts +++ b/src/targets/signUp.test.ts @@ -57,7 +57,7 @@ describe("SignUp target", () => { ).rejects.toBeInstanceOf(UsernameExistsError); }); - it("saves a new user", async () => { + it("saves a new user with email", async () => { mockUserPoolService.getUserByUsername.mockResolvedValue(null); await signUp(TestContext, { @@ -74,6 +74,41 @@ describe("SignUp target", () => { Value: expect.stringMatching(UUID), }, { Name: "email", Value: "example@example.com" }, + { Name: "email_verified", Value: "false" }, + ], + Enabled: true, + Password: "pwd", + UserCreateDate: now, + UserLastModifiedDate: now, + UserStatus: "UNCONFIRMED", + Username: "user-supplied", + RefreshTokens: [], + }); + }); + + it("saves a new user with email and phone_number", async () => { + mockUserPoolService.getUserByUsername.mockResolvedValue(null); + + await signUp(TestContext, { + ClientId: "clientId", + Password: "pwd", + Username: "user-supplied", + UserAttributes: [ + { Name: "email", Value: "example@example.com" }, + { Name: "phone_number", Value: "0400000000" }, + ], + }); + + expect(mockUserPoolService.saveUser).toHaveBeenCalledWith(TestContext, { + Attributes: [ + { + Name: "sub", + Value: expect.stringMatching(UUID), + }, + { Name: "email", Value: "example@example.com" }, + { Name: "phone_number", Value: "0400000000" }, + { Name: "email_verified", Value: "false" }, + { Name: "phone_number_verified", Value: "false" }, ], Enabled: true, Password: "pwd", @@ -120,6 +155,7 @@ describe("SignUp target", () => { userAttributes: [ { Name: "sub", Value: expect.stringMatching(UUID) }, { Name: "email", Value: "example@example.com" }, + { Name: "email_verified", Value: "false" }, ], userPoolId: "test", username: "user-supplied", @@ -206,6 +242,7 @@ describe("SignUp target", () => { userAttributes: [ { Name: "sub", Value: expect.stringMatching(UUID) }, { Name: "email", Value: "example@example.com" }, + { Name: "email_verified", Value: "false" }, { Name: "cognito:user_status", Value: "CONFIRMED" }, ], userPoolId: "test", @@ -229,7 +266,10 @@ describe("SignUp target", () => { }, Password: "pwd", Username: "user-supplied", - UserAttributes: [{ Name: "email", Value: "example@example.com" }], + UserAttributes: [ + { Name: "email", Value: "example@example.com" }, + { Name: "email_verified", Value: "false" }, + ], ValidationData: [{ Name: "another", Value: "attribute" }], }) ).rejects.toBeInstanceOf(UserLambdaValidationError); @@ -466,6 +506,7 @@ describe("SignUp target", () => { Attributes: [ { Name: "sub", Value: expect.stringMatching(UUID) }, { Name: "email", Value: "example@example.com" }, + { Name: "email_verified", Value: "false" }, ], Enabled: true, Password: "pwd", @@ -535,6 +576,7 @@ describe("SignUp target", () => { Attributes: [ { Name: "sub", Value: expect.stringMatching(UUID) }, { Name: "phone_number", Value: "0400000000" }, + { Name: "phone_number_verified", Value: "false" }, ], Enabled: true, Password: "pwd", @@ -611,6 +653,8 @@ describe("SignUp target", () => { { Name: "sub", Value: expect.stringMatching(UUID) }, { Name: "email", Value: "example@example.com" }, { Name: "phone_number", Value: "0400000000" }, + { Name: "email_verified", Value: "false" }, + { Name: "phone_number_verified", Value: "false" }, ], Enabled: true, Password: "pwd", @@ -657,6 +701,7 @@ describe("SignUp target", () => { Attributes: [ { Name: "sub", Value: expect.stringMatching(UUID) }, { Name: "email", Value: "example@example.com" }, + { Name: "email_verified", Value: "false" }, ], Enabled: true, Password: "pwd", @@ -719,6 +764,7 @@ describe("SignUp target", () => { Attributes: [ { Name: "sub", Value: expect.stringMatching(UUID) }, { Name: "email", Value: "example@example.com" }, + { Name: "email_verified", Value: "false" }, ], ConfirmationCode: "123456", Enabled: true, diff --git a/src/targets/signUp.ts b/src/targets/signUp.ts index 4cb1c4f2..c1139f8a 100644 --- a/src/targets/signUp.ts +++ b/src/targets/signUp.ts @@ -87,6 +87,10 @@ export const SignUp = : [{ Name: "sub", Value: uuid.v4() }, ...(req.UserAttributes ?? [])]; let userStatus: UserStatusType = "UNCONFIRMED"; + const isEmailUsername = + config.UserPoolDefaults.UsernameAttributes?.includes("email"); + const hasEmailAttribute = attributesInclude("email", attributes); + if (triggers.enabled("PreSignUp")) { const { autoConfirmUser, autoVerifyEmail, autoVerifyPhone } = await triggers.preSignUp(ctx, { @@ -102,18 +106,30 @@ export const SignUp = if (autoConfirmUser) { userStatus = "CONFIRMED"; } - const isEmailUsername = - config.UserPoolDefaults.UsernameAttributes?.includes("email"); - const hasEmailAttribute = attributesInclude("email", attributes); if (isEmailUsername && !hasEmailAttribute) { attributes.push({ Name: "email", Value: req.Username }); } - if ((isEmailUsername || hasEmailAttribute) && autoVerifyEmail) { - attributes.push({ Name: "email_verified", Value: "true" }); + if (isEmailUsername || hasEmailAttribute) { + if (autoVerifyEmail) { + attributes.push({ Name: "email_verified", Value: "true" }); + } else { + attributes.push({ Name: "email_verified", Value: "false" }); + } + } + if (attributesInclude("phone_number", attributes)) { + if (autoVerifyPhone) { + attributes.push({ Name: "phone_number_verified", Value: "true" }); + } else { + attributes.push({ Name: "phone_number_verified", Value: "false" }); + } + } + } else { + if (isEmailUsername || hasEmailAttribute) { + attributes.push({ Name: "email_verified", Value: "false" }); } - if (attributesInclude("phone_number", attributes) && autoVerifyPhone) { - attributes.push({ Name: "phone_number_verified", Value: "true" }); + if (attributesInclude("phone_number", attributes)) { + attributes.push({ Name: "phone_number_verified", Value: "false" }); } }