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(cognito): add analyticsConfiguration to UserPoolClient #32862

Open
wants to merge 38 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
d4ba257
feat: add `analyticsConfiguration` to UserPoolClient
ren-yamanashi Jan 12, 2025
2444316
feat: change property name
ren-yamanashi Jan 12, 2025
06842c4
feat: add unit test
ren-yamanashi Jan 12, 2025
012183d
docs: add documents
ren-yamanashi Jan 12, 2025
67b914f
feat: change method name
ren-yamanashi Jan 12, 2025
6531be3
feat: add integ test
ren-yamanashi Jan 12, 2025
73ca9d9
feat: update unit test
ren-yamanashi Jan 12, 2025
3c7a594
chore: add jsdoc comment
ren-yamanashi Jan 12, 2025
0dcb1e2
docs: update README.md
ren-yamanashi Jan 12, 2025
c31198e
feat: update integ test
ren-yamanashi Jan 12, 2025
114fa85
Merge branch 'main' of https://github.com/aws/aws-cdk into 32837-feat…
ren-yamanashi Jan 12, 2025
228177a
feat: update jsDoc
ren-yamanashi Jan 12, 2025
8319091
Merge branch 'main' of https://github.com/aws/aws-cdk into 32837-feat…
ren-yamanashi Jan 12, 2025
9d26e09
feat: update integ test
ren-yamanashi Jan 12, 2025
080d156
feat: update integ test
ren-yamanashi Jan 12, 2025
0bc7aac
Merge branch 'main' of https://github.com/aws/aws-cdk into 32837-feat…
ren-yamanashi Jan 12, 2025
415929d
feat: update integ test
ren-yamanashi Jan 12, 2025
407ee7e
feat: implementation modification at user-pool-client.ts
ren-yamanashi Jan 12, 2025
c12092d
test: fix test
ren-yamanashi Jan 12, 2025
47e8800
test: update unit test
ren-yamanashi Jan 12, 2025
73ddec4
docs: update README.md
ren-yamanashi Jan 12, 2025
bed1061
docs: update README.md
ren-yamanashi Jan 12, 2025
91569e3
test: update integ test
ren-yamanashi Jan 12, 2025
73b368c
Merge branch 'main' of https://github.com/aws/aws-cdk into 32837-feat…
ren-yamanashi Jan 12, 2025
b1098de
docs: update README.md
ren-yamanashi Jan 12, 2025
436a666
docs: update README.md
ren-yamanashi Jan 12, 2025
af90b5c
feat: change property name
ren-yamanashi Jan 12, 2025
4c548c2
feat: change import order
ren-yamanashi Jan 12, 2025
0cf0934
feat: update property type
ren-yamanashi Jan 12, 2025
2804b8c
test: update integ test
ren-yamanashi Jan 13, 2025
5959b3e
docs: update README.md
ren-yamanashi Jan 13, 2025
2c82f2e
Merge branch 'main' of https://github.com/aws/aws-cdk into 32837-feat…
ren-yamanashi Jan 13, 2025
03948d8
test: update integ test
ren-yamanashi Jan 13, 2025
f16fa90
test: update integ test
ren-yamanashi Jan 13, 2025
0c03d77
test: update integ test
ren-yamanashi Jan 13, 2025
683ddf0
Merge branch 'main' of https://github.com/aws/aws-cdk into 32837-feat…
ren-yamanashi Jan 13, 2025
a3904fd
test: update integ test
ren-yamanashi Jan 13, 2025
5ca76ad
Merge branch 'main' of https://github.com/aws/aws-cdk into 32837-feat…
ren-yamanashi Jan 13, 2025
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
38 changes: 38 additions & 0 deletions packages/aws-cdk-lib/aws-cognito/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1085,3 +1085,41 @@ userPool.addGroup('AnotherUserPoolGroup', {
groupName: 'another-group-name'
});
```

### Analytics Configuration

User pool clients can be configured with Amazon Pinpoint analytics to collect user activity metrics. This integration enables you to track user engagement and campaign effectiveness.

📝 Note: Amazon Pinpoint isn't available in all AWS Regions. For a list of available Regions, see [Amazon Cognito and Amazon Pinpoint Region availability](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-pinpoint-integration.html#cognito-user-pools-find-region-mappings).

The following example shows how to configure analytics for a user pool client:

```ts
const pool = new cognito.UserPool(this, 'Pool');

new cognito.UserPoolClient(this, 'Client', {
userPool: pool,
analytics: {
// The ARN of your Pinpoint project
applicationArn: 'arn:aws:pinpoint:us-east-1:123456789012:app/abc123',

// Your Pinpoint project ID
applicationId: '123456789012',

// External ID for the IAM role
externalId: 'my-external-id',

// IAM role that Cognito can assume to publish to Pinpoint
roleArn: 'arn:aws:iam::123456789012:role/CognitoPinpointRole',

// Whether to include user data in analytics events
userDataShared: true,
},
});
```

When configuring analytics:

- `applicationArn` must be a valid ARN of a Pinpoint project
- `roleArn` must be a valid IAM role ARN with permissions to publish to Pinpoint
- Setting `userDataShared` to `true` allows Cognito to include user data in the analytics events
53 changes: 53 additions & 0 deletions packages/aws-cdk-lib/aws-cognito/lib/user-pool-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,45 @@ export interface UserPoolClientProps extends UserPoolClientOptions {
* The UserPool resource this client will have access to
*/
readonly userPool: IUserPool;

/**
* The analytics configuration for this client.
*/
readonly analytics?: AnalyticsConfiguration;
}

/**
* The settings for Amazon Pinpoint analytics configuration.
*
* With an analytics configuration, your application can collect user-activity metrics for user notifications with a Amazon Pinpoint campaign.
*
* Amazon Pinpoint isn't available in all AWS Regions. For a list of available Regions, see [Amazon Cognito and Amazon Pinpoint Region availability](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-pinpoint-integration.html#cognito-user-pools-find-region-mappings).
*/
export interface AnalyticsConfiguration {
/**
* The Amazon Resource Name (ARN) of an Amazon Pinpoint project that you want to connect to your user pool app client.
*/
readonly applicationArn?: string;

/**
* Your Amazon Pinpoint project ID.
*/
readonly applicationId?: string;

/**
* The [external ID](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-user_externalid.html) of the role that Amazon Cognito assumes to send analytics data to Amazon Pinpoint.
*/
readonly externalId?: string;

/**
* The ARN of an AWS Identity and Access Management role that has the permissions required for Amazon Cognito to publish events to Amazon Pinpoint analytics.
*/
readonly roleArn?: string;

/**
* If `UserDataShared` is `true` , Amazon Cognito includes user data in the events that it publishes to Amazon Pinpoint analytics.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* If `UserDataShared` is `true` , Amazon Cognito includes user data in the events that it publishes to Amazon Pinpoint analytics.
* If `true`, Amazon Cognito includes user data in the events that it publishes to Amazon Pinpoint analytics.

Formatting.

*/
readonly userDataShared?: boolean;
}

/**
Expand Down Expand Up @@ -447,6 +486,10 @@ export class UserPoolClient extends Resource implements IUserPoolClient {
throw new Error('Cannot activate enablePropagateAdditionalUserContextData in an app client without a client secret.');
}

if (props.analytics) {
this.validateAnalytics(props.analytics);
}

this._generateSecret = props.generateSecret;
this.userPool = props.userPool;

Expand All @@ -467,6 +510,7 @@ export class UserPoolClient extends Resource implements IUserPoolClient {
writeAttributes: props.writeAttributes?.attributes(),
enableTokenRevocation: props.enableTokenRevocation,
enablePropagateAdditionalUserContextData: props.enablePropagateAdditionalUserContextData,
analyticsConfiguration: props.analytics,
});
this.configureAuthSessionValidity(resource, props);
this.configureTokenValidity(resource, props);
Expand Down Expand Up @@ -618,4 +662,13 @@ export class UserPoolClient extends Resource implements IUserPoolClient {
throw new Error(`${name}: Must be a duration between ${min.toHumanString()} and ${max.toHumanString()} (inclusive); received ${value.toHumanString()}.`);
}
}

private validateAnalytics(analytics: AnalyticsConfiguration) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the CloudFormation expects either ApplicationArn or all of ApplicationId, ExternalId and RoleArn to be provided. Could you please adjust the validation for this?

if (analytics.applicationArn && !Token.isUnresolved(analytics.applicationArn) && !analytics.applicationArn.startsWith('arn:')) {
throw new Error(`applicationArn must be start with "arn:"; received ${analytics.applicationArn}`);
}
if (analytics.roleArn && !Token.isUnresolved(analytics.roleArn) && !analytics.roleArn.startsWith('arn:')) {
throw new Error(`roleArn must be start with "arn:"; received ${analytics.roleArn}`);
}
}
}
66 changes: 66 additions & 0 deletions packages/aws-cdk-lib/aws-cognito/test/user-pool-client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1342,4 +1342,70 @@ describe('User Pool Client', () => {
).toThrow(`defaultRedirectUri must match the \`^(?=.{1,1024}$)[\p{L}\p{M}\p{S}\p{N}\p{P}]+$\` pattern, got ${invalidUrl}`);
});

test('should add analytics configuration to userPoolClients ', () => {
// GIVEN
const stack = new Stack();
const pool = new UserPool(stack, 'Pool');

// WHEN
new UserPoolClient(stack, 'Client', {
userPool: pool,
analytics: {
applicationArn: 'arn:aws:pinpoint:us-east-1:123456789012:application/abc123',
applicationId: '123456789012',
externalId: '123456789012',
roleArn: 'arn:aws:iam::123456789012:role/TestRole',
userDataShared: true,
},
});

// THEN
Template.fromStack(stack).hasResourceProperties('AWS::Cognito::UserPoolClient', {
AnalyticsConfiguration: {
ApplicationArn: 'arn:aws:pinpoint:us-east-1:123456789012:application/abc123',
ApplicationId: '123456789012',
ExternalId: '123456789012',
RoleArn: 'arn:aws:iam::123456789012:role/TestRole',
UserDataShared: true,
},
});
});

test('throws an error when applicationArn is not an ARN', () => {
// GIVEN
const stack = new Stack();
const pool = new UserPool(stack, 'Pool');

// WHEN
// THEN
expect(() => new UserPoolClient(stack, 'Client', {
userPool: pool,
analytics: {
applicationArn: 'invalid-arn',
applicationId: '123456789012',
externalId: '123456789012',
roleArn: 'arn:aws:iam::123456789012:role/TestRole',
userDataShared: true,
},
})).toThrow('applicationArn must be start with "arn:"; received invalid-arn');
});

test('throws an error when roleArn is not an ARN', () => {
// GIVEN
const stack = new Stack();
const pool = new UserPool(stack, 'Pool');

// WHEN
// THEN
expect(() => new UserPoolClient(stack, 'Client', {
userPool: pool,
analytics: {
applicationArn: 'arn:aws:pinpoint:us-east-1:123456789012:application/abc123',
applicationId: '123456789012',
externalId: '123456789012',
roleArn: 'invalid-arn',
userDataShared: true,
},
})).toThrow('roleArn must be start with "arn:"; received invalid-arn');
});
});
Loading