Skip to content

Commit

Permalink
fix: Flatten OIDC props to eliminate importing OidcAttributeRequestMe…
Browse files Browse the repository at this point in the history
…thod (aws-amplify#974)

* fix: flatten oidc props to improve DX

* chore: add changeset

* chore: update tests

* chore: fix test

* chore: update api

* chore: add test to verify default behavior
  • Loading branch information
awsluja authored Feb 8, 2024
1 parent faaed0b commit 29fb32b
Show file tree
Hide file tree
Showing 6 changed files with 161 additions and 9 deletions.
5 changes: 5 additions & 0 deletions .changeset/proud-brooms-live.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@aws-amplify/auth-construct-alpha': patch
---

OIDC attributeRequestMethod no longer requires importing OidcAttributeRequestMethod.
1 change: 1 addition & 0 deletions .eslint_dictionary.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
"javascript",
"jsdoc",
"jsons",
"jwks",
"keyof",
"lang",
"linux",
Expand Down
4 changes: 3 additions & 1 deletion packages/auth-construct/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,9 @@ export type MFASettings = {
};

// @public
export type OidcProviderProps = Omit<aws_cognito.UserPoolIdentityProviderOidcProps, 'userPool'>;
export type OidcProviderProps = Omit<aws_cognito.UserPoolIdentityProviderOidcProps, 'userPool' | 'attributeRequestMethod'> & {
readonly attributeRequestMethod?: 'GET' | 'POST';
};

// @public
export type PhoneNumberLogin = true | {
Expand Down
125 changes: 121 additions & 4 deletions packages/auth-construct/src/construct.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1230,6 +1230,13 @@ void describe('Auth construct', () => {
void it('supports oidc and email', () => {
const app = new App();
const stack = new Stack(app);
const authorizationURL = 'http://localhost:3000/authorization';
const jwksURI = 'https://localhost:3000/jwksuri';
const tokensURL = 'http://localhost:3000/token';
const userInfoURL = 'http://localhost:3000/userinfo';
const mockIdentifiers = ['one', 'two'];
const mockScopes = ['scope1', 'scope2'];
const attributeRequestMethod = 'POST';
new AmplifyAuth(stack, 'test', {
loginWith: {
email: true,
Expand All @@ -1239,6 +1246,20 @@ void describe('Auth construct', () => {
clientSecret: oidcClientSecret,
issuerUrl: oidcIssuerUrl,
name: oidcProviderName,
attributeMapping: {
email: {
attributeName: 'email',
},
},
attributeRequestMethod: attributeRequestMethod,
endpoints: {
authorization: authorizationURL,
jwksUri: jwksURI,
token: tokensURL,
userInfo: userInfoURL,
},
identifiers: mockIdentifiers,
scopes: mockScopes,
},
callbackUrls: ['https://redirect.com'],
logoutUrls: ['https://logout.com'],
Expand All @@ -1250,10 +1271,106 @@ void describe('Auth construct', () => {
UsernameAttributes: ['email'],
AutoVerifiedAttributes: ['email'],
});
template.hasResourceProperties(
'AWS::Cognito::UserPoolIdentityProvider',
ExpectedOidcIDPProperties
);
template.hasResourceProperties('AWS::Cognito::UserPoolIdentityProvider', {
AttributeMapping: {
email: 'email',
},
IdpIdentifiers: mockIdentifiers,
ProviderDetails: {
attributes_request_method: attributeRequestMethod,
attributes_url: userInfoURL,
authorize_scopes: mockScopes.join(' '),
authorize_url: authorizationURL,
client_id: oidcClientId,
client_secret: oidcClientSecret,
jwks_uri: jwksURI,
oidc_issuer: oidcIssuerUrl,
token_url: tokensURL,
},
ProviderName: oidcProviderName,
ProviderType: 'OIDC',
});
template.hasResourceProperties('AWS::Cognito::IdentityPool', {
OpenIdConnectProviderARNs: [
Match.objectEquals({
'Fn::Join': [
'',
[
'arn:aws:iam:',
{ Ref: 'AWS::Region' },
':',
{ Ref: 'AWS::AccountId' },
':oidc-provider/cognito-idp.',
{ Ref: 'AWS::Region' },
'.amazonaws.com/',
{ Ref: 'testOidcIDP12B3582F' },
],
],
}),
],
});
});
void it('oidc defaults to GET for oidc method', () => {
const app = new App();
const stack = new Stack(app);
const authorizationURL = 'http://localhost:3000/authorization';
const jwksURI = 'https://localhost:3000/jwksuri';
const tokensURL = 'http://localhost:3000/token';
const userInfoURL = 'http://localhost:3000/userinfo';
const mockIdentifiers = ['one', 'two'];
const mockScopes = ['scope1', 'scope2'];
new AmplifyAuth(stack, 'test', {
loginWith: {
email: true,
externalProviders: {
oidc: {
clientId: oidcClientId,
clientSecret: oidcClientSecret,
issuerUrl: oidcIssuerUrl,
name: oidcProviderName,
attributeMapping: {
email: {
attributeName: 'email',
},
},
endpoints: {
authorization: authorizationURL,
jwksUri: jwksURI,
token: tokensURL,
userInfo: userInfoURL,
},
identifiers: mockIdentifiers,
scopes: mockScopes,
},
callbackUrls: ['https://redirect.com'],
logoutUrls: ['https://logout.com'],
},
},
});
const template = Template.fromStack(stack);
template.hasResourceProperties('AWS::Cognito::UserPool', {
UsernameAttributes: ['email'],
AutoVerifiedAttributes: ['email'],
});
template.hasResourceProperties('AWS::Cognito::UserPoolIdentityProvider', {
AttributeMapping: {
email: 'email',
},
IdpIdentifiers: mockIdentifiers,
ProviderDetails: {
attributes_request_method: 'GET',
attributes_url: userInfoURL,
authorize_scopes: mockScopes.join(' '),
authorize_url: authorizationURL,
client_id: oidcClientId,
client_secret: oidcClientSecret,
jwks_uri: jwksURI,
oidc_issuer: oidcIssuerUrl,
token_url: tokensURL,
},
ProviderName: oidcProviderName,
ProviderType: 'OIDC',
});
template.hasResourceProperties('AWS::Cognito::IdentityPool', {
OpenIdConnectProviderARNs: [
Match.objectEquals({
Expand Down
20 changes: 18 additions & 2 deletions packages/auth-construct/src/construct.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
CfnUserPoolClient,
Mfa,
OAuthScope,
OidcAttributeRequestMethod,
UserPool,
UserPoolClient,
UserPoolIdentityProviderAmazon,
Expand Down Expand Up @@ -696,14 +697,29 @@ export class AmplifyAuth
result.providersList.push('APPLE');
}
if (external.oidc) {
const oidc = external.oidc;
const requestMethod =
oidc.attributeRequestMethod === undefined
? 'GET' // default if not defined
: oidc.attributeRequestMethod;
result.oidc = new cognito.UserPoolIdentityProviderOidc(
this,
`${this.name}OidcIDP`,
{
userPool,
...external.oidc,
attributeRequestMethod:
requestMethod === 'GET'
? OidcAttributeRequestMethod.GET
: OidcAttributeRequestMethod.POST,
clientId: oidc.clientId,
clientSecret: oidc.clientSecret,
endpoints: oidc.endpoints,
identifiers: oidc.identifiers,
issuerUrl: oidc.issuerUrl,
name: oidc.name,
scopes: oidc.scopes,
attributeMapping:
external.oidc.attributeMapping ?? shouldMapEmailAttributes
oidc.attributeMapping ?? shouldMapEmailAttributes
? {
email: {
attributeName: 'email',
Expand Down
15 changes: 13 additions & 2 deletions packages/auth-construct/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,19 @@ export type FacebookProviderProps = Omit<
*/
export type OidcProviderProps = Omit<
cognito.UserPoolIdentityProviderOidcProps,
'userPool'
>;
'userPool' | 'attributeRequestMethod'
> & {
/**
* The method to use to request attributes
* @default 'GET'
*
* For details about each option, see below.
*
* 'GET' - use GET
* 'POST' - use POST
*/
readonly attributeRequestMethod?: 'GET' | 'POST';
};

/**
* SAML provider.
Expand Down

0 comments on commit 29fb32b

Please sign in to comment.