Open jaredready opened 2 years ago
I was looking to add exactly this to my Amplify application since I have a multi-tenant app that multiple organizations share. I'd like to see this added to the federatedSignIn
function as well.
The current workaround I'm envisioning for this is to create a mapping between the identifier (ex: company.com
) and the provider name in a DB.
Even though there is no official documentation for this feature, it is possible without major workarounds. I am currently implementing federated sign in using AzureAD as my third party provider using OpenID (It is also possible using SAML).
Notice that the provider
argument is the identity_provider
query parameter that you mentioned in the Authorize endpoint API, so there is no need to create new arguments.
const queryString = Object.entries({
redirect_uri: redirectSignIn,
response_type: responseType,
client_id: clientId,
identity_provider: provider, // This is already implemented in
Amplify
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);
First you need to amplify add auth
and select Apply default configuration with Social Provider (Federation)
. You will be asked for a domain name prefix. You should supply the following information:
When being prompted for the identity providers you want to configure for your user pool press enter without selecting any. This will create a user pool and create a Cognito domain that you will need in your third party auth provider.
amplify push
to see your changes in the cloud.
Head to the AWS Console and search for AWS Amplify. Select all apps and click the app you are using. There you can select the Authentication category you just created:
Once there, select the View in Cognito option:
That will open your Amazon Cognito console. Select Sign-in experience and click in Add identity provider:
You can select the third party identifier you are going to use. Be sure to use a provider name you will remember, this will be used as the provider
argument in your Auth.federatedSignIn
function:
Fill in the rest of the information and click in Add identity provider.
After that the identity provider you just created should show up. You should go into App integration and scroll down to the App client list. Select the app that ends in clientWeb (You can follow the same procedure for the _appclient app if needed): From there go to Hosted UI and tap the Edit button: Scroll down to Identity providers and select the one you just created and hit Save changes at the end of the page:
You should configure your third party provider using the following documentation for SAML and this documentation for OIDC. The redirect URI is key for the flow to work correctly.
You can use the following React code to test your newly created IdP. Notice that the provider is a string containing the name of the newly created IdP:
import { Auth } from "aws-amplify";
import { useEffect, useState } from "react";
export default function SignInPage() {
const [user, setUser] = useState(null);
const signIn = async () => {
try {
await Auth.federatedSignIn({ provider: "Azure" });
} catch (error) {
console.log("error signing in", error);
}
};
useEffect(() => {
getUser().then((userData) => setUser(userData));
}, []);
function getUser() {
return Auth.currentAuthenticatedUser()
.then((userData) => userData)
.catch(() => console.log("Not signed in"));
}
return (
<div>
<h1>
Welcome{" "}
{user
? JSON.stringify(user.attributes.email)
: "Ups! Not signed in"}
</h1>
{user ? (
<button onClick={() => Auth.signOut()}>Sign Out</button>
) : (
<button onClick={signIn}>Federated Sign In</button>
)}
</div>
);
}
Once you click the button you should be redirected to your IdP and a new user should be created in your Cognito user pool.
Edit: Just realized you were asking about another query parameter. I'll leave the comment as a tutorial for adding third party idps.
Just to add to this discussion, I faced exactly the same issue described by @ncarvajalc (thanks for the great walkthrough, BTW) and managed to do the UserPool IdP setup from within Amplify using overrides
:
auth
setup in the project) generate a overrides file for Auth:amplify override auth
This will create a file under amplify/backend/auth/override.ts
(details in the docs here).
AWS::Cognito::UserPoolIdentityProvider
(details here) with your IdP details:import { AmplifyAuthCognitoStackTemplate, AmplifyProjectInfo } from '@aws-amplify/cli-extensibility-helper';
export function override(resources: AmplifyAuthCognitoStackTemplate, amplifyProjectInfo: AmplifyProjectInfo) {
resources.addCfnResource(
{
type: "AWS::Cognito::UserPoolIdentityProvider",
properties: {
AttributeMapping: {
<your K:V attribute mappings>
},
ProviderDetails: {
client_id: "<your client id>",
client_secret: "<your client secret>",
authorize_scopes: "openid",
oidc_issuer: "<oidc issuer URL>",
attributes_url_add_attributes: false,
attributes_request_method: "GET"
},
ProviderName: "<your provider name>",
ProviderType: "OIDC",
UserPoolId: {
Ref: "UserPool",
},
},
},
"oidc-provider"
);
}
amplify push
After this point, it is possible to call Auth.federatedSignIn()
in your app to redirect the user to the OIDC provider. You do need to specify the provider name - the same used in the CfnResource above - like so:
Auth.federatedSignIn({ provider: "<your provider name>" } as any);
Hope this helps!
Is this related to a new or existing framework?
React
Is this related to a new or existing API?
Authentication
Is this related to another service?
No response
Describe the feature you'd like to request
Cognito User Pools federated identities supports using identifiers (typically a domain name) to correctly figure out what IdP a user should be authenticating with based on their email address. This is described in the Cognito documentation here.
Following the link, you can see that the
/oauth2/authorize
endpoint supports an optionalidp_identifier
query parameter for providing this information.I would like to be able to use the
Auth.federatedSignIn
function to be able to utilize this functionality.Currently Amplify applications utilizing multiple identify providers need to jump through some awkward hoops to get their authentication code working correctly, but Cognito already supports the required functionality.
Describe the solution you'd like
Currently the
Auth
package provides afederatedSignIn
function that has a requiredprovider
. I would like to see this function's input type enhanced to something like the following.Maybe something a little smarter to require either
provider
oridpIdentifier
; my TypeScript isn't that good.This would allow one to do something like,
and have the user be directed to their correct IdP to authenticate.
Describe alternatives you've considered
I've tried to see if it would be possible to abuse the current behavior to make this work, but you can see here that there's currently no way to provide additional query parameters to make this request work.
Additional context
The documentation here has a handy graphical overview of the workflow.
Is this something that you'd be interested in working on?