* Which Category is your question related to? *
Amplify - Authentication via Cognito Hosted UI
* What AWS Services are you utilizing? *
Cognito
Background
So I am currently integrating login with Facebook on an application that uses Amplify and I have a question around it's behaviour that I can't find anywhere in the documentation.
I am not using any of the React HOCs to log the users in, I'm doing so by sending them directly to the Facebook url as documented by the url_to_facebook
const here
I've configured Amplify Auth manually with the oauth
settings:
Auth: {
identityPoolId: REACT_APP_IDENTITY_POOL_ID,
region: REACT_APP_AWS_REGION,
userPoolId: REACT_APP_USER_POOL_ID,
userPoolWebClientId: REACT_APP_USER_POOL_CLIENT,
authenticationFlowType: 'USER_PASSWORD_AUTH',
mandatorySignIn: true,
oauth: {
domain: REACT_APP_USER_POOL_DOMAIN,
scope: ['phone', 'email', 'profile', 'openid', 'aws.cognito.signin.user.admin'],
redirectSignIn: `${protocol}//${REACT_APP_USER_POOL_REDIRECT_HOST}/u/social-auth-redirect`,
redirectSignOut: `${protocol}//${REACT_APP_USER_POOL_REDIRECT_HOST}/u/sign-out`,
responseType: 'code',
options: {
AdvancedSecurityDataCollectionFlag: false,
},
},
},
The redirectSignOut url is compulsory here and I'm trying to figure out it's purpose.
Question
If the @aws-amplify/auth
package deletes the tokens out of localstorage, and the CognitoAuth client then subsequently deletes the scopes from localstorage...
Why does it have to redirect to the logout page at all?
Why was Amplify happy just calling Auth.signOut
before without redirecting, and since adding oauth
config does it now need to redirect?
(https://github.com/aws/amazon-cognito-auth-js/blob/master/src/CognitoAuth.js#L730)
Thanks
_NOTE_
I've found the documentation for integrating facebook login incredibly difficult when not using the bootstrapped components provided by the Amplify React package (I'd like to integrate this login functionality within my current experience). I just want to control the login flow with some simple HTTP calls and JS functions, which at the moment is very difficult when it should be simple.
I get you're trying to help with the Cognito Hosted UI, especially for bootstrapping, but I would rather control that page and experience and it's unfortunate that it's very difficult at the moment, I'd be happy to help try and improve this.
@christemple Hey the redirection is to sign the user out from the Cognito side. For example, if you have already logged in through the Hosted UI and you went to the login page again, you will have the option to sign in as the same user because the Cognito service still "remember" you. So to log the user out completely, you would need to do that redirection.
As for now the Auth.signOut
function will call the signOut
method from amazon-cognito-auth-js
sdk if the user configured oauth
in the Auth module. I agree that we need to improve that part a bit.
About the difficulty of using the Cognito Hosted UI, can you provide more details? Do you mean it's difficult to launch the Hosted UI or to understand how to process when redirected back from the Hosted UI?
@powerful23 thanks for getting back to me, I've created a diagram to help explain how I'm integrating Facebook login with Cognito on my app
As you can see my users never actually see any Cognito Hosted UI, but I do use the Cognito Domain to handle adding the user to my User Pool.
When you say it's to sign the user out from Cognito's side, what do you mean?
Because without the oauth config, logging the user out is a matter of deleting the tokens in local storage calling Auth.signOut
(no redirection), however since adding the oauth config, the local storage tokens continue to get deleted on my client app, plus the scopes key in local storage... then it redirects to the Cognito Domain logout URL of which I can't understand what further work needs completed to log the user out?
I'm struggling to understand why I could log the user out, without the oauth config, by calling Auth.signOut
and have it only delete the local storage entries.
Yet now, with the oauth conifg, it continues deleting the same entries, plus the scopes one, but that doesn't suffice in the user being logged out so they have to be redirected to the Cognito domain logout page?
Even when my users will never use the Cognito Hosted UI?
What additional things needs taken care of on that page to log the user out?
_Edit_
For example, if you have already logged in through the Hosted UI and you went to the login page again, you will have the option to sign in as the same user because the Cognito service still "remember" you.
But if my user never logs in via the Cognito Hosted UI, surely they don't need to be redirected there to logout right?
I feel like the boundaries between the features of the Cognito domain and Cognito Hosted UI are being crossed here, I want the Cognito domain feature and non of the Hosted UI but I feel like the Amplify package's logic assumes if you're using one you're using both?
@christemple thanks for all those details. For the first question:
When you say it's to sign the user out from Cognito's side, what do you mean?
If you have previously logged in with Facebook through the Hosted UI and you didn't get redirected to that logout URL when logging out, the next time when you sign in again, you would have something like this:
The second thing you brought up is what we need to improve.
But if my user never logs in via the Cognito Hosted UI, surely they don't need to be redirected there to logout right?
Yes, for users not logged through Hosted UI, they should not be directed. Because for now Amplify would always try to redirect to that logout URL if you configured oauth
.
I have the same issue. My work around is as follows
const url = `https://${oauth.domain}/logout?redirect_uri=${oauth.redirectSignOut}&response_type=${oauth.responseType}&client_id=${Auth.configure().userPoolWebClientId}`;
Auth.signOut()
.then(() => { window.location.url = url; }) // eslint-disable-line no-undef
.catch(err => console.error(err));
It would be great if Auth.signOut()
did that last bit for me.
Happy to do a PR if that approach makes sense.
Hello everyone, we have created an RFC for feature work that should make the challenges found in this issue easier in the future. If you have a moment please read through the details and add any comments: https://github.com/aws-amplify/amplify-js/issues/2716
Your feedback in the RFC will help us ensure that we are delivering the best experience possible. Thank you.
This issue is fixed in the latest version of Amplify. Please let us know if you have further concern.
Hey @powerful23 can you explain a bit on how this is fixed? I am using OAuth
with Google federation. Everything works ok except the signOut
part which launches/redirects the user to the browser again, which from a user experience is confusing especially for a mobile app.
I use withOAuth
at the root
export default withOAuth(App);
Auth.signOut()
The above always redirects the user to the browser.
Config is like this-
const urlOpener = async (url, redirectUrl) => {
const { type, url: newUrl } = await WebBrowser.openAuthSessionAsync(url, redirectUrl);
if (type === 'success') {
await WebBrowser.dismissBrowser();
if (Platform.OS === 'ios') {
return Linking.openURL(newUrl);
}
}
};
const amplifyconfig = {
region: "ap-south-1",
identityPoolId: "ap-south-1:XXXXXXXXXXX",
userPoolId: "ap-south-XXXXXXXXX",
userPoolWebClientId: "XXXXXXXXXXXXXXXXXX",
oauth: {
domain : "domain.auth.ap-south-1.amazoncognito.com",
scope : ["email", "profile", "openid","aws.cognito.signin.user.admin"],
redirectSignIn : Linking.makeUrl(),
redirectSignOut : Linking.makeUrl(),
responseType: "code",
options: {
AdvancedSecurityDataCollectionFlag : true
},
urlOpener: urlOpener
}
}
I'm not using expo, but the same problem happens. So, based on your fix, I'm doing this:
// fix urlOpener; otherwise signOut will lead back to the browser
const urlOpener = async (url: string, redirectUrl: string) => {
if (redirectUrl === 'myapp://signin/') {
return await Linking.openURL(url);
}
};
@cpmech
Where did you put this code to avoid opening the browser on signOut on mobile app?
@ponchautf this code is placed in the urlOpener example function provided by the Amplify js docs: https://docs.amplify.aws/lib/auth/social/q/platform/js#hosted-ui-with-expo
I'm not using expo, but the same problem happens. So, based on your fix, I'm doing this:
// fix urlOpener; otherwise signOut will lead back to the browser const urlOpener = async (url: string, redirectUrl: string) => { if (redirectUrl === 'myapp://signin/') { return await Linking.openURL(url); } };
@cpmech In my case (expo) the Redirect URL is undefined
at sign out. The app's URL is included in the &logout_uri
query parameter of the url
, so I don't believe your code would work for me. The URL is of the pattern https://xxxxxxxxx.auth.us-east-1.amazoncognito.com/logout?client_id=xxxxxxxxxxxxxxx&logout_uri=exp%3A%2F%2Fbz-6qb.app.myapp.exp.direct%3A80
and to me it looks like there isn't a way to avoid the redirect to browser.
Hey guys... struggled all day with a similar issue. The fix what seems to work for me is below:
const signOut = async () => {
try {
AppStorage.setItem('amplify-signin-with-hostedUI', 'false');
await Auth.signOut({ global: true });
} catch (error) {
console.warn(error);
}
};
I am setting in storage the 'amplify-signin-with-hostedUI' key to false before calling Auth.signOut(); this seems to get rid of the redirect when not using the hostedUI
Hey guys... struggled all day with a similar issue. The fix what seems to work for me is below:
const signOut = async () => { try { AppStorage.setItem('amplify-signin-with-hostedUI', 'false'); await Auth.signOut({ global: true }); } catch (error) { console.warn(error); } };
I am setting in storage the 'amplify-signin-with-hostedUI' key to false before calling Auth.signOut(); this seems to get rid of the redirect when not using the hostedUI
What package is AppStorage coming from? Do you have a full code snippet you could share?
Hey everyone, any updates here? I am experiencing the same thing, login works but when I click logout I get the prompt to open the browser, then this:
event: oAuthSignOut
Possible Unhandled Promise Rejection (id: 0):
"Signout timeout fail"
This makes the hosted ui almost unusable
Most helpful comment
Hey @powerful23 can you explain a bit on how this is fixed? I am using
OAuth
with Google federation. Everything works ok except thesignOut
part which launches/redirects the user to the browser again, which from a user experience is confusing especially for a mobile app.I use
withOAuth
at the rootThe above always redirects the user to the browser.
Config is like this-