-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Added support for idp_identifier query parameter in cognito authorize... #10505
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
Added support for idp_identifier query parameter in cognito authorize... #10505
Conversation
Behavior for each permutation of idp_identifier + identity_provider
The way it was implemented is the following:
const queryString = provider ? Object.entries({ // Case a provider is given (with or without an idp_identifier) redirect_uri: redirectSignIn, response_type: responseType, client_id: clientId, identity_provider: provider, // Present instead of idp_identifier scope: scopesString, state, ...(responseType === 'code' ? { code_challenge } : {}), ...(responseType === 'code' ? { code_challenge_method } : {}), }) .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`) .join('&') : Object.entries({ // Case a provider is not given but there is an idp_identifier redirect_uri: redirectSignIn, response_type: responseType, idp_identifier: idpIdentifier, // Present instead of identity_provider client_id: clientId, scope: scopesString, state, ...(responseType === 'code' ? { code_challenge } : {}), ...(responseType === 'code' ? { code_challenge_method } : {}), }) .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`) .join('&'); const URL = `https://${domain}/oauth2/authorize?${queryString}`; logger.debug(`Redirecting to ${URL}`); this._urlOpener(URL, redirectSignIn);
Examples for different test cases
Case when no options are passed
const signIn = async () => { try { await Auth.federatedSignIn(); } catch (error) { console.log("error signing in", error); } };
In this case if signIn
is executed the user is redirected to the following:
Pasted image 20221110105606
Case empty options are passed
const signIn = async () => { try { await Auth.federatedSignIn({}); } catch (error) { console.log("error signing in", error); } };
The following error is raised:
Pasted image 20221110105927
Case only valid provider is present
const signIn = async () => { try { await Auth.federatedSignIn({ provider: "Azure" }); } catch (error) { console.log("error signing in", error); } };
The user is redirected to the given provider:
Pasted image 20221110110158
Case only invalid provider is present
const signIn = async () => { try { await Auth.federatedSignIn({ provider: "NonExistentProvider" }); } catch (error) { console.log("error signing in", error); } };
The user is redirected to:
Pasted image 20221110110345
Case only valid idp_identifier is present
const signIn = async () => { try { await Auth.federatedSignIn({ idpIdentifier: "hotmail.com" }); } catch (error) { console.log("error signing in", error); } };
User is redirected to the corresponding identity provider associated with the idp_identifier:
Pasted image 20221110110627
Case only invalid idp_identifier is present
const signIn = async () => { try { await Auth.federatedSignIn({ idpIdentifier: "invalid.com" }); } catch (error) { console.log("error signing in", error); } };
The user is redirected to the following:
Pasted image 20221110110834
Case valid provider and invalid or valid idp_identifier are used
const signIn = async () => { try { await Auth.federatedSignIn({ provider: "Azure", idpIdentifier: "hotmail.com", }); } catch (error) { console.log("error signing in", error); } };
Same case as when only a valid provider is passed as only that query parameter is inserted in the request.
Case invalid provider and invalid or valid idp_identifier are used
const signIn = async () => { try { await Auth.federatedSignIn({ provider: "NonExistentProvider", idpIdentifier: "hotmail.com", }); } catch (error) { console.log("error signing in", error); } };
Same case as when an invalid provider is used as only that query parameter is inserted in the request.
Are there any data/auth rule implications or differences between a user using other categories (ex. API, DataStore, etc) authenticated via identifier and provider?
No, as the redirect to the external provider and the registration in Cognito using idp_identifier is done the same way as using a custom provider (which is already implemented in Amplify).
Same as with custom providers – e.g { provider: "Azure" }
– developers have to be aware that Cognito assigns user names and creates groups automatically when using an external provider. Here are 3 users, 2 were registered using an idp_identifier ({ idpIdentifier: "hotmail.com" }
) and other using a custom provider ({ provider: "Azure" }
). All of them were redirected to the same AzureAD application and registered in Cognito as follows:
Pasted image 20221110113001
Also, a group was created automatically and all of the users are in it:
Pasted image 20221110113155
Pasted image 20221110113210
With this in mind, developers have to be aware about the group name generated to use auth rules for schemas and keep in mind the prefix usernames have with the corresponding identity provider name used when registering the Federated identity provider. This same behavior is expected both when using a provider or an idp_identifier.
I have submitted #14423 as an alternative PR to this one, as the auth library has changed significantly since this was authored.
... endpoint
Description of changes
Files changed
The following files had changes:
packages/auth/src/types/OAuth.ts
packages/auth/src/Auth.ts
packages/auth/src/OAuth/OAuth.ts
Changes
The
packages/auth/src/types/OAuth.ts
file had the following changes:An
idpIdentifier
filed was added as an optional field in theFederatedSignInOptions
andFederatedSignInOptionsCustom
types to enable the idp_identifier query parameter when sending the request URL to the Cognito authorize endpoint. Additionally, ahasIdpIdentifier
function was added to evaluate if the provider options have anidpIdentifier
key. Also, the provider field was made optional, as either anidp_identifier
or aprovider
is used when requesting for an IdP, as described in the Amazon Cognito documentation.The
packages/auth/src/Auth.ts
file had the following changes:The
hasIdpIdentifier
function was used to check for theidpIdentifier
key. In case it has it, the idpIdentifier value is extracted either from theFederatedSignInOptions
type or theFederatedSignInOptions
type. After that theidpIdentifier
is passed to thethis._oAuthHandler.oauthSignIn
function.Finally, the
packages/auth/src/OAuth/OAuth.ts
file had the following changes:The function
oauthSignIn
was modified to make theprovider
argument optional and added an optional argumentidpIdentifier
. In case there is aprovider
present the request URL generated will send theprovider
as theidentity_provider
query parameter and ignore anyidpIdentifier
present, as either anidp_identifier
or anidentity_provider
is used when requesting for an IdP. In case there is no provider, it will check for the idpIdentifier and send it as theidp_identifier
query parameter in the Cognito authorize endpoint.Issue #, if available
Closes #10226
Description of how you validated changes
I created a sample React app with the following component:
The federate sign in identity was set up as described in the comment in #10226 and adding an IdPidentifier as shown below:
image
The app successfully logged in the user and added it to the cognito user pool created.
Previous test cases when using default options or no arguments for the
federatedSignin
function where tested and they worked correctly.Checklist
yarn test
passes (It is not working for @aws-amplify/storage tests in the latest branch)yarn run test --scope @aws-amplify/auth
passesBy submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.