Skip to content

Commit 8c371b1

Browse files
authored
fix: Expose name prop to allow controlling resource naming (#967)
* allow customizing name for resources * chore: add changeset * chore: update api * chore: cleanup
1 parent b73d76a commit 8c371b1

File tree

5 files changed

+176
-79
lines changed

5 files changed

+176
-79
lines changed

.changeset/many-lobsters-move.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@aws-amplify/auth-construct-alpha': patch
3+
---
4+
5+
Allow users to customize the resource names for auth.

packages/auth-construct/API.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export type AppleProviderProps = Omit<aws_cognito.UserPoolIdentityProviderAppleP
3131

3232
// @public
3333
export type AuthProps = {
34+
name?: string;
3435
loginWith: {
3536
email?: EmailLogin;
3637
phone?: PhoneNumberLogin;

packages/auth-construct/src/construct.test.ts

Lines changed: 110 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1734,15 +1734,113 @@ void describe('Auth construct', () => {
17341734
},
17351735
});
17361736
});
1737+
1738+
void it('does not automatically map email attributes if phone is also enabled', () => {
1739+
const app = new App();
1740+
const stack = new Stack(app);
1741+
new AmplifyAuth(stack, 'test', {
1742+
loginWith: {
1743+
email: true,
1744+
phone: true, // this makes phone_number a required attribute
1745+
externalProviders: {
1746+
google: {
1747+
clientId: googleClientId,
1748+
clientSecret: SecretValue.unsafePlainText(googleClientSecret),
1749+
},
1750+
facebook: {
1751+
clientId: facebookClientId,
1752+
clientSecret: facebookClientSecret,
1753+
},
1754+
signInWithApple: {
1755+
clientId: appleClientId,
1756+
keyId: appleKeyId,
1757+
privateKey: applePrivateKey,
1758+
teamId: appleTeamId,
1759+
},
1760+
loginWithAmazon: {
1761+
clientId: amazonClientId,
1762+
clientSecret: amazonClientSecret,
1763+
},
1764+
oidc: {
1765+
clientId: oidcClientId,
1766+
clientSecret: oidcClientSecret,
1767+
issuerUrl: oidcIssuerUrl,
1768+
name: oidcProviderName,
1769+
},
1770+
callbackUrls: ['https://redirect.com'],
1771+
logoutUrls: ['https://logout.com'],
1772+
},
1773+
},
1774+
});
1775+
const template = Template.fromStack(stack);
1776+
template.hasResourceProperties('AWS::Cognito::UserPool', {
1777+
UsernameAttributes: ['email', 'phone_number'],
1778+
AutoVerifiedAttributes: ['email', 'phone_number'],
1779+
});
1780+
const mappingThatShouldNotExist = {
1781+
AttributeMapping: {
1782+
email: 'email',
1783+
},
1784+
};
1785+
assert.throws(() => {
1786+
template.hasResourceProperties(
1787+
'AWS::Cognito::UserPoolIdentityProvider',
1788+
{
1789+
...ExpectedAmazonIDPProperties,
1790+
...mappingThatShouldNotExist,
1791+
}
1792+
);
1793+
});
1794+
assert.throws(() => {
1795+
template.hasResourceProperties(
1796+
'AWS::Cognito::UserPoolIdentityProvider',
1797+
{
1798+
...ExpectedAppleIDPProperties,
1799+
...mappingThatShouldNotExist,
1800+
}
1801+
);
1802+
});
1803+
assert.throws(() => {
1804+
template.hasResourceProperties(
1805+
'AWS::Cognito::UserPoolIdentityProvider',
1806+
{
1807+
...ExpectedFacebookIDPProperties,
1808+
...mappingThatShouldNotExist,
1809+
}
1810+
);
1811+
});
1812+
assert.throws(() => {
1813+
template.hasResourceProperties(
1814+
'AWS::Cognito::UserPoolIdentityProvider',
1815+
{
1816+
...ExpectedGoogleIDPProperties,
1817+
...mappingThatShouldNotExist,
1818+
}
1819+
);
1820+
});
1821+
assert.throws(() => {
1822+
template.hasResourceProperties(
1823+
'AWS::Cognito::UserPoolIdentityProvider',
1824+
{
1825+
...ExpectedOidcIDPProperties,
1826+
...mappingThatShouldNotExist,
1827+
}
1828+
);
1829+
});
1830+
});
17371831
});
17381832

1739-
void it('does not automatically map email attributes if phone is also enabled', () => {
1833+
void it('sets resource names based on id and name property', () => {
17401834
const app = new App();
17411835
const stack = new Stack(app);
1836+
const stackId = 'test';
1837+
const name = 'name';
1838+
const expectedPrefix = stackId + name;
17421839
new AmplifyAuth(stack, 'test', {
1840+
name: name,
17431841
loginWith: {
17441842
email: true,
1745-
phone: true, // this makes phone_number a required attribute
1843+
phone: true,
17461844
externalProviders: {
17471845
google: {
17481846
clientId: googleClientId,
@@ -1768,50 +1866,22 @@ void describe('Auth construct', () => {
17681866
issuerUrl: oidcIssuerUrl,
17691867
name: oidcProviderName,
17701868
},
1869+
saml: {
1870+
name: samlProviderName,
1871+
metadata: {
1872+
metadataContent: samlMetadataContent,
1873+
metadataType: 'FILE',
1874+
},
1875+
},
17711876
callbackUrls: ['https://redirect.com'],
17721877
logoutUrls: ['https://logout.com'],
17731878
},
17741879
},
17751880
});
17761881
const template = Template.fromStack(stack);
1777-
template.hasResourceProperties('AWS::Cognito::UserPool', {
1778-
UsernameAttributes: ['email', 'phone_number'],
1779-
AutoVerifiedAttributes: ['email', 'phone_number'],
1780-
});
1781-
const mappingThatShouldNotExist = {
1782-
AttributeMapping: {
1783-
email: 'email',
1784-
},
1785-
};
1786-
assert.throws(() => {
1787-
template.hasResourceProperties('AWS::Cognito::UserPoolIdentityProvider', {
1788-
...ExpectedAmazonIDPProperties,
1789-
...mappingThatShouldNotExist,
1790-
});
1791-
});
1792-
assert.throws(() => {
1793-
template.hasResourceProperties('AWS::Cognito::UserPoolIdentityProvider', {
1794-
...ExpectedAppleIDPProperties,
1795-
...mappingThatShouldNotExist,
1796-
});
1797-
});
1798-
assert.throws(() => {
1799-
template.hasResourceProperties('AWS::Cognito::UserPoolIdentityProvider', {
1800-
...ExpectedFacebookIDPProperties,
1801-
...mappingThatShouldNotExist,
1802-
});
1803-
});
1804-
assert.throws(() => {
1805-
template.hasResourceProperties('AWS::Cognito::UserPoolIdentityProvider', {
1806-
...ExpectedGoogleIDPProperties,
1807-
...mappingThatShouldNotExist,
1808-
});
1809-
});
1810-
assert.throws(() => {
1811-
template.hasResourceProperties('AWS::Cognito::UserPoolIdentityProvider', {
1812-
...ExpectedOidcIDPProperties,
1813-
...mappingThatShouldNotExist,
1814-
});
1882+
const resourceNames = Object.keys(template['template']['Resources']);
1883+
resourceNames.map((name) => {
1884+
assert.equal(name.startsWith(expectedPrefix), true);
18151885
});
18161886
});
18171887

packages/auth-construct/src/construct.ts

Lines changed: 56 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@ export class AmplifyAuth
103103

104104
private readonly oAuthSettings: cognito.OAuthSettings | undefined;
105105

106+
private readonly name: string;
107+
106108
/**
107109
* Create a new Auth construct with AuthProps.
108110
* If no props are provided, email login and defaults will be used.
@@ -114,11 +116,13 @@ export class AmplifyAuth
114116
) {
115117
super(scope, id);
116118

119+
this.name = props.name ?? '';
120+
117121
// UserPool
118122
this.computedUserPoolProps = this.getUserPoolProps(props);
119123
this.userPool = new cognito.UserPool(
120124
this,
121-
'UserPool',
125+
`${this.name}UserPool`,
122126
this.computedUserPoolProps
123127
);
124128

@@ -133,7 +137,7 @@ export class AmplifyAuth
133137
this.domainPrefix &&
134138
this.providerSetupResult.providersList.length > 0
135139
) {
136-
this.userPool.addDomain('UserPoolDomain', {
140+
this.userPool.addDomain(`${this.name}UserPoolDomain`, {
137141
cognitoDomain: { domainPrefix: this.domainPrefix },
138142
});
139143
} else if (
@@ -174,7 +178,7 @@ export class AmplifyAuth
174178
// UserPool Client
175179
const userPoolClient = new cognito.UserPoolClient(
176180
this,
177-
'UserPoolAppClient',
181+
`${this.name}UserPoolAppClient`,
178182
{
179183
userPool: this.userPool,
180184
authFlows: DEFAULTS.AUTH_FLOWS,
@@ -244,7 +248,7 @@ export class AmplifyAuth
244248
*/
245249
private setupAuthAndUnAuthRoles = (identityPoolId: string): DefaultRoles => {
246250
const result: DefaultRoles = {
247-
auth: new Role(this, 'authenticatedUserRole', {
251+
auth: new Role(this, `${this.name}authenticatedUserRole`, {
248252
assumedBy: new FederatedPrincipal(
249253
'cognito-identity.amazonaws.com',
250254
{
@@ -258,7 +262,7 @@ export class AmplifyAuth
258262
'sts:AssumeRoleWithWebIdentity'
259263
),
260264
}),
261-
unAuth: new Role(this, 'unauthenticatedUserRole', {
265+
unAuth: new Role(this, `${this.name}unauthenticatedUserRole`, {
262266
assumedBy: new FederatedPrincipal(
263267
'cognito-identity.amazonaws.com',
264268
{
@@ -286,14 +290,19 @@ export class AmplifyAuth
286290
) => {
287291
// setup identity pool
288292
const region = Stack.of(this).region;
289-
const identityPool = new cognito.CfnIdentityPool(this, 'IdentityPool', {
290-
allowUnauthenticatedIdentities: DEFAULTS.ALLOW_UNAUTHENTICATED_IDENTITIES,
291-
});
293+
const identityPool = new cognito.CfnIdentityPool(
294+
this,
295+
`${this.name}IdentityPool`,
296+
{
297+
allowUnauthenticatedIdentities:
298+
DEFAULTS.ALLOW_UNAUTHENTICATED_IDENTITIES,
299+
}
300+
);
292301
const roles = this.setupAuthAndUnAuthRoles(identityPool.ref);
293302
const identityPoolRoleAttachment =
294303
new cognito.CfnIdentityPoolRoleAttachment(
295304
this,
296-
'IdentityPoolRoleAttachment',
305+
`${this.name}IdentityPoolRoleAttachment`,
297306
{
298307
identityPoolId: identityPool.ref,
299308
roles: {
@@ -602,7 +611,7 @@ export class AmplifyAuth
602611
const googleProps = external.google;
603612
result.google = new cognito.UserPoolIdentityProviderGoogle(
604613
this,
605-
'GoogleIdP',
614+
`${this.name}GoogleIdP`,
606615
{
607616
userPool,
608617
clientId: googleProps.clientId,
@@ -624,7 +633,7 @@ export class AmplifyAuth
624633
if (external.facebook) {
625634
result.facebook = new cognito.UserPoolIdentityProviderFacebook(
626635
this,
627-
'FacebookIDP',
636+
`${this.name}FacebookIDP`,
628637
{
629638
userPool,
630639
...external.facebook,
@@ -645,7 +654,7 @@ export class AmplifyAuth
645654
if (external.loginWithAmazon) {
646655
result.amazon = new cognito.UserPoolIdentityProviderAmazon(
647656
this,
648-
'AmazonIDP',
657+
`${this.name}AmazonIDP`,
649658
{
650659
userPool,
651660
...external.loginWithAmazon,
@@ -667,7 +676,7 @@ export class AmplifyAuth
667676
if (external.signInWithApple) {
668677
result.apple = new cognito.UserPoolIdentityProviderApple(
669678
this,
670-
'AppleIDP',
679+
`${this.name}AppleIDP`,
671680
{
672681
userPool,
673682
...external.signInWithApple,
@@ -687,36 +696,44 @@ export class AmplifyAuth
687696
result.providersList.push('APPLE');
688697
}
689698
if (external.oidc) {
690-
result.oidc = new cognito.UserPoolIdentityProviderOidc(this, 'OidcIDP', {
691-
userPool,
692-
...external.oidc,
693-
attributeMapping:
694-
external.oidc.attributeMapping ?? shouldMapEmailAttributes
695-
? {
696-
email: {
697-
attributeName: 'email',
698-
},
699-
}
700-
: undefined,
701-
});
699+
result.oidc = new cognito.UserPoolIdentityProviderOidc(
700+
this,
701+
`${this.name}OidcIDP`,
702+
{
703+
userPool,
704+
...external.oidc,
705+
attributeMapping:
706+
external.oidc.attributeMapping ?? shouldMapEmailAttributes
707+
? {
708+
email: {
709+
attributeName: 'email',
710+
},
711+
}
712+
: undefined,
713+
}
714+
);
702715
result.providersList.push('OIDC');
703716
}
704717
if (external.saml) {
705718
const saml = external.saml;
706-
result.saml = new cognito.UserPoolIdentityProviderSaml(this, 'SamlIDP', {
707-
userPool,
708-
attributeMapping: saml.attributeMapping,
709-
identifiers: saml.identifiers,
710-
idpSignout: saml.idpSignout,
711-
metadata: {
712-
metadataContent: saml.metadata.metadataContent,
713-
metadataType:
714-
saml.metadata.metadataType === 'FILE'
715-
? UserPoolIdentityProviderSamlMetadataType.FILE
716-
: UserPoolIdentityProviderSamlMetadataType.URL,
717-
},
718-
name: saml.name,
719-
});
719+
result.saml = new cognito.UserPoolIdentityProviderSaml(
720+
this,
721+
`${this.name}SamlIDP`,
722+
{
723+
userPool,
724+
attributeMapping: saml.attributeMapping,
725+
identifiers: saml.identifiers,
726+
idpSignout: saml.idpSignout,
727+
metadata: {
728+
metadataContent: saml.metadata.metadataContent,
729+
metadataType:
730+
saml.metadata.metadataType === 'FILE'
731+
? UserPoolIdentityProviderSamlMetadataType.FILE
732+
: UserPoolIdentityProviderSamlMetadataType.URL,
733+
},
734+
name: saml.name,
735+
}
736+
);
720737
result.providersList.push('SAML');
721738
}
722739
return result;

packages/auth-construct/src/types.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,10 @@ export type TriggerEvent = (typeof triggerEvents)[number];
242242
* Input props for the AmplifyAuth construct
243243
*/
244244
export type AuthProps = {
245+
/**
246+
* Specify a name which will aid in generating resource names.
247+
*/
248+
name?: string;
245249
/**
246250
* Specify how you would like users to log in. You can choose from email, phone, and even external providers such as LoginWithAmazon.
247251
*/

0 commit comments

Comments
 (0)