diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-cognito/test/integ.user-pool-link-custom-placeholder.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-cognito/test/integ.user-pool-link-custom-placeholder.js.snapshot/cdk.out new file mode 100644 index 0000000000000..1f0068d32659a --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-cognito/test/integ.user-pool-link-custom-placeholder.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"36.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-cognito/test/integ.user-pool-link-custom-placeholder.js.snapshot/integ-user-pool-link-custom-placeholder.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-cognito/test/integ.user-pool-link-custom-placeholder.js.snapshot/integ-user-pool-link-custom-placeholder.assets.json new file mode 100644 index 0000000000000..cb5c759a25aec --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-cognito/test/integ.user-pool-link-custom-placeholder.js.snapshot/integ-user-pool-link-custom-placeholder.assets.json @@ -0,0 +1,19 @@ +{ + "version": "36.0.0", + "files": { + "8933ce2d15790f339b208cf26b074a443813cb433115af260ab927c97e241c47": { + "source": { + "path": "integ-user-pool-link-custom-placeholder.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "8933ce2d15790f339b208cf26b074a443813cb433115af260ab927c97e241c47.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-cognito/test/integ.user-pool-link-custom-placeholder.js.snapshot/integ-user-pool-link-custom-placeholder.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-cognito/test/integ.user-pool-link-custom-placeholder.js.snapshot/integ-user-pool-link-custom-placeholder.template.json new file mode 100644 index 0000000000000..7d982cb5fbff6 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-cognito/test/integ.user-pool-link-custom-placeholder.js.snapshot/integ-user-pool-link-custom-placeholder.template.json @@ -0,0 +1,76 @@ +{ + "Resources": { + "myuserpool01998219": { + "Type": "AWS::Cognito::UserPool", + "Properties": { + "AccountRecoverySetting": { + "RecoveryMechanisms": [ + { + "Name": "verified_phone_number", + "Priority": 1 + }, + { + "Name": "verified_email", + "Priority": 2 + } + ] + }, + "AdminCreateUserConfig": { + "AllowAdminCreateUserOnly": true + }, + "DeletionProtection": "INACTIVE", + "SmsVerificationMessage": "The verification code to your new account is {####}", + "UserPoolName": "MyUserPool", + "VerificationMessageTemplate": { + "DefaultEmailOption": "CONFIRM_WITH_LINK", + "EmailMessageByLink": "You have been invited to join our awesome app! {##Click here to verify your email##}", + "EmailSubjectByLink": "Invite to join our awesome app!", + "SmsMessage": "The verification code to your new account is {####}" + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + } + }, + "Outputs": { + "userpoolid": { + "Value": { + "Ref": "myuserpool01998219" + } + } + }, + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-cognito/test/integ.user-pool-link-custom-placeholder.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-cognito/test/integ.user-pool-link-custom-placeholder.js.snapshot/integ.json new file mode 100644 index 0000000000000..837060dde243f --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-cognito/test/integ.user-pool-link-custom-placeholder.js.snapshot/integ.json @@ -0,0 +1,19 @@ +{ + "version": "36.0.0", + "testCases": { + "user-pool-link-custom-placeholder-integ-test/DefaultTest": { + "stacks": [ + "integ-user-pool-link-custom-placeholder" + ], + "cdkCommandOptions": { + "deploy": { + "args": { + "rollback": true + } + } + }, + "assertionStack": "user-pool-link-custom-placeholder-integ-test/DefaultTest/DeployAssert", + "assertionStackName": "userpoollinkcustomplaceholderintegtestDefaultTestDeployAssert5C199314" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-cognito/test/integ.user-pool-link-custom-placeholder.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-cognito/test/integ.user-pool-link-custom-placeholder.js.snapshot/manifest.json new file mode 100644 index 0000000000000..e3a71d145f54d --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-cognito/test/integ.user-pool-link-custom-placeholder.js.snapshot/manifest.json @@ -0,0 +1,119 @@ +{ + "version": "36.0.0", + "artifacts": { + "integ-user-pool-link-custom-placeholder.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "integ-user-pool-link-custom-placeholder.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "integ-user-pool-link-custom-placeholder": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "integ-user-pool-link-custom-placeholder.template.json", + "terminationProtection": false, + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/8933ce2d15790f339b208cf26b074a443813cb433115af260ab927c97e241c47.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "integ-user-pool-link-custom-placeholder.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "integ-user-pool-link-custom-placeholder.assets" + ], + "metadata": { + "/integ-user-pool-link-custom-placeholder/myuserpool/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "myuserpool01998219" + } + ], + "/integ-user-pool-link-custom-placeholder/user-pool-id": [ + { + "type": "aws:cdk:logicalId", + "data": "userpoolid" + } + ], + "/integ-user-pool-link-custom-placeholder/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/integ-user-pool-link-custom-placeholder/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "integ-user-pool-link-custom-placeholder" + }, + "userpoollinkcustomplaceholderintegtestDefaultTestDeployAssert5C199314.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "userpoollinkcustomplaceholderintegtestDefaultTestDeployAssert5C199314.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "userpoollinkcustomplaceholderintegtestDefaultTestDeployAssert5C199314": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "userpoollinkcustomplaceholderintegtestDefaultTestDeployAssert5C199314.template.json", + "terminationProtection": false, + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "userpoollinkcustomplaceholderintegtestDefaultTestDeployAssert5C199314.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "userpoollinkcustomplaceholderintegtestDefaultTestDeployAssert5C199314.assets" + ], + "metadata": { + "/user-pool-link-custom-placeholder-integ-test/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/user-pool-link-custom-placeholder-integ-test/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "user-pool-link-custom-placeholder-integ-test/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-cognito/test/integ.user-pool-link-custom-placeholder.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-cognito/test/integ.user-pool-link-custom-placeholder.js.snapshot/tree.json new file mode 100644 index 0000000000000..d66f0e544396f --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-cognito/test/integ.user-pool-link-custom-placeholder.js.snapshot/tree.json @@ -0,0 +1,156 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "integ-user-pool-link-custom-placeholder": { + "id": "integ-user-pool-link-custom-placeholder", + "path": "integ-user-pool-link-custom-placeholder", + "children": { + "myuserpool": { + "id": "myuserpool", + "path": "integ-user-pool-link-custom-placeholder/myuserpool", + "children": { + "Resource": { + "id": "Resource", + "path": "integ-user-pool-link-custom-placeholder/myuserpool/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Cognito::UserPool", + "aws:cdk:cloudformation:props": { + "accountRecoverySetting": { + "recoveryMechanisms": [ + { + "name": "verified_phone_number", + "priority": 1 + }, + { + "name": "verified_email", + "priority": 2 + } + ] + }, + "adminCreateUserConfig": { + "allowAdminCreateUserOnly": true + }, + "deletionProtection": "INACTIVE", + "smsVerificationMessage": "The verification code to your new account is {####}", + "userPoolName": "MyUserPool", + "verificationMessageTemplate": { + "defaultEmailOption": "CONFIRM_WITH_LINK", + "emailMessageByLink": "You have been invited to join our awesome app! {##Click here to verify your email##}", + "emailSubjectByLink": "Invite to join our awesome app!", + "smsMessage": "The verification code to your new account is {####}" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_cognito.CfnUserPool", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_cognito.UserPool", + "version": "0.0.0" + } + }, + "user-pool-id": { + "id": "user-pool-id", + "path": "integ-user-pool-link-custom-placeholder/user-pool-id", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnOutput", + "version": "0.0.0" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "integ-user-pool-link-custom-placeholder/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "integ-user-pool-link-custom-placeholder/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "0.0.0" + } + }, + "user-pool-link-custom-placeholder-integ-test": { + "id": "user-pool-link-custom-placeholder-integ-test", + "path": "user-pool-link-custom-placeholder-integ-test", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "user-pool-link-custom-placeholder-integ-test/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "user-pool-link-custom-placeholder-integ-test/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "user-pool-link-custom-placeholder-integ-test/DefaultTest/DeployAssert", + "children": { + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "user-pool-link-custom-placeholder-integ-test/DefaultTest/DeployAssert/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "user-pool-link-custom-placeholder-integ-test/DefaultTest/DeployAssert/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.IntegTestCase", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.IntegTest", + "version": "0.0.0" + } + }, + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.App", + "version": "0.0.0" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-cognito/test/integ.user-pool-link-custom-placeholder.js.snapshot/userpoollinkcustomplaceholderintegtestDefaultTestDeployAssert5C199314.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-cognito/test/integ.user-pool-link-custom-placeholder.js.snapshot/userpoollinkcustomplaceholderintegtestDefaultTestDeployAssert5C199314.assets.json new file mode 100644 index 0000000000000..819351d69a81e --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-cognito/test/integ.user-pool-link-custom-placeholder.js.snapshot/userpoollinkcustomplaceholderintegtestDefaultTestDeployAssert5C199314.assets.json @@ -0,0 +1,19 @@ +{ + "version": "36.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "source": { + "path": "userpoollinkcustomplaceholderintegtestDefaultTestDeployAssert5C199314.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-cognito/test/integ.user-pool-link-custom-placeholder.js.snapshot/userpoollinkcustomplaceholderintegtestDefaultTestDeployAssert5C199314.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-cognito/test/integ.user-pool-link-custom-placeholder.js.snapshot/userpoollinkcustomplaceholderintegtestDefaultTestDeployAssert5C199314.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-cognito/test/integ.user-pool-link-custom-placeholder.js.snapshot/userpoollinkcustomplaceholderintegtestDefaultTestDeployAssert5C199314.template.json @@ -0,0 +1,36 @@ +{ + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-cognito/test/integ.user-pool-link-custom-placeholder.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-cognito/test/integ.user-pool-link-custom-placeholder.ts new file mode 100644 index 0000000000000..65e04962e0437 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-cognito/test/integ.user-pool-link-custom-placeholder.ts @@ -0,0 +1,32 @@ +import { App, CfnOutput, RemovalPolicy, Stack } from 'aws-cdk-lib'; +import { UserPool, VerificationEmailStyle } from 'aws-cdk-lib/aws-cognito'; +import { IntegTest } from '@aws-cdk/integ-tests-alpha'; + +const app = new App(); +const stack = new Stack(app, 'integ-user-pool-link-custom-placeholder'); + +const userpool = new UserPool(stack, 'myuserpool', { + userPoolName: 'MyUserPool', + removalPolicy: RemovalPolicy.DESTROY, + deletionProtection: false, + userVerification: { + emailStyle: VerificationEmailStyle.LINK, + emailSubject: 'Invite to join our awesome app!', + emailBody: 'You have been invited to join our awesome app! {##Click here to verify your email##}', + }, +}); + +new CfnOutput(stack, 'user-pool-id', { + value: userpool.userPoolId, +}); + +new IntegTest(app, 'user-pool-link-custom-placeholder-integ-test', { + testCases: [stack], + cdkCommandOptions: { + deploy: { + args: { + rollback: true, + }, + }, + }, +}); diff --git a/packages/aws-cdk-lib/aws-cognito/README.md b/packages/aws-cdk-lib/aws-cognito/README.md index 8616cb0b929ab..ae7b91ecc4f5a 100644 --- a/packages/aws-cdk-lib/aws-cognito/README.md +++ b/packages/aws-cdk-lib/aws-cognito/README.md @@ -79,6 +79,11 @@ Users can either be signed up by the app's administrators or can sign themselves account needs to be confirmed. Cognito provides several ways to sign users up and confirm their accounts. Learn more about [user sign up here](https://docs.aws.amazon.com/cognito/latest/developerguide/signing-up-users-in-your-app.html). +To verify the email address of a user in your user pool with Amazon Cognito, you can send the user an email message +with a link that they can select, or you can send them a code that they can enter. + +#### Code Verification + When a user signs up, email and SMS messages are used to verify their account and contact methods. The following code snippet configures a user pool with properties relevant to these verification messages - @@ -113,6 +118,20 @@ new cognito.UserPool(this, 'myuserpool', { }); ``` +#### Link Verification +Alternatively, users can use link as a verification method. The following code snippet configures a user pool with +properties relevant to these verification messages and link verification method. + +```ts +new cognito.UserPool(this, 'myuserpool', { + userVerification: { + emailStyle: cognito.VerificationEmailStyle.LINK, + emailSubject: 'Invite to join our awesome app!', + emailBody: 'You have been invited to join our awesome app! {##Verify Your Email##}', + }, +}); +``` + All email subjects, bodies and SMS messages for both invitation and verification support Cognito's message templating. Learn more about [message templates here](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pool-settings-message-templates.html). diff --git a/packages/aws-cdk-lib/aws-cognito/lib/user-pool.ts b/packages/aws-cdk-lib/aws-cognito/lib/user-pool.ts index aca961028a79a..8da548198eb32 100644 --- a/packages/aws-cdk-lib/aws-cognito/lib/user-pool.ts +++ b/packages/aws-cdk-lib/aws-cognito/lib/user-pool.ts @@ -1047,6 +1047,11 @@ export class UserPool extends UserPoolBase { private verificationMessageConfiguration(props: UserPoolProps): CfnUserPool.VerificationMessageTemplateProperty { const CODE_TEMPLATE = '{####}'; const VERIFY_EMAIL_TEMPLATE = '{##Verify Email##}'; + /** + * Email message placeholder regex + * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cognito-userpool-verificationmessagetemplate.html#cfn-cognito-userpool-verificationmessagetemplate-emailmessagebylink + */ + const VERIFY_EMAIL_REGEX = /\{##[\p{L}\p{M}\p{S}\p{N}\p{P}\s*]*##\}/u; const emailStyle = props.userVerification?.emailStyle ?? VerificationEmailStyle.CODE; const emailSubject = props.userVerification?.emailSubject ?? 'Verify your new account'; @@ -1069,7 +1074,7 @@ export class UserPool extends UserPoolBase { } else { const emailMessage = props.userVerification?.emailBody ?? `Verify your account by clicking on ${VERIFY_EMAIL_TEMPLATE}`; - if (!Token.isUnresolved(emailMessage) && emailMessage.indexOf(VERIFY_EMAIL_TEMPLATE) < 0) { + if (!Token.isUnresolved(emailMessage) && !VERIFY_EMAIL_REGEX.test(emailMessage)) { throw new Error(`Verification email body must contain the template string '${VERIFY_EMAIL_TEMPLATE}'`); } return { diff --git a/packages/aws-cdk-lib/aws-cognito/test/user-pool.test.ts b/packages/aws-cdk-lib/aws-cognito/test/user-pool.test.ts index af482b5abf1ab..b80c669e205d7 100644 --- a/packages/aws-cdk-lib/aws-cognito/test/user-pool.test.ts +++ b/packages/aws-cdk-lib/aws-cognito/test/user-pool.test.ts @@ -159,14 +159,35 @@ describe('User Pool', () => { expect(() => new UserPool(stack, 'Pool5', { userVerification: { emailStyle: VerificationEmailStyle.LINK, - emailBody: 'invalid email body {####}', + emailBody: 'valid email body {####}', }, - })).toThrow(/Verification email body/); + })).not.toThrow(); expect(() => new UserPool(stack, 'Pool6', { userVerification: { emailStyle: VerificationEmailStyle.LINK, - emailBody: 'invalid email body {##Verify Email##}', + emailBody: 'valid email body {##Verify Email##}', + }, + })).not.toThrow(); + + expect(() => new UserPool(stack, 'Pool7', { + userVerification: { + emailStyle: VerificationEmailStyle.LINK, + emailBody: 'invalid email body ##Verify Email##', + }, + })).toThrow(/Verification email body/); + + expect(() => new UserPool(stack, 'Pool8', { + userVerification: { + emailStyle: VerificationEmailStyle.LINK, + emailBody: 'valid email body {##Verify !! Email##}', + }, + })).not.toThrow(); + + expect(() => new UserPool(stack, 'Pool9', { + userVerification: { + emailStyle: VerificationEmailStyle.LINK, + emailBody: 'valid email body {##Click here to verify##}', }, })).not.toThrow(); });