Skip to content
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

Identity providers authentication against User Pools WITHOUT hosted UI #1316

Closed
martimarkov opened this issue Jul 26, 2018 · 75 comments
Closed
Labels
Cognito Related to cognito issues feature-request Request a new feature

Comments

@martimarkov
Copy link

Allow for custom UI (self-hosted, not the poorly customizable hosted UI) when using User Pools.

Currently, I have to redirect my customers to a page I have 10% control over how it looks. I can't change the font or the layout. I'm using react and have already built my desired flow. I only want to be able to get a JWT from Cognito for a person who decides to signup with Facebook or Google.

If I use Federated Identities I get a Facebook token. If there is a way to then "exchange" that for a JWT issued by Cognito I'll be happy as well.

@manueliglesias manueliglesias added the Cognito Related to cognito issues label Jul 26, 2018
@manueliglesias
Copy link
Contributor

Hi @martimarkov

Currently it is not possible, but the good news is that this is currently in the roadmap. Please stay tuned!

@manueliglesias manueliglesias added the feature-request Request a new feature label Jul 26, 2018
@martimarkov
Copy link
Author

martimarkov commented Jul 26, 2018 via email

@powerful23
Copy link
Contributor

powerful23 commented Jul 26, 2018

@martimarkov we find a solution for you to use the customized button to do that. You can construct a url like https://the-app-domain/oauth2/authorize?redirect_uri=callback_url&response_type=token&client_id=the_web_client_id&identity_provider=Facebook. This url will directly take you to the facebook login page and after login successfully, the browser will redirect to the callback_url. Then you can parse the callback url to get the access_token and id_token. We will also bring this into Amplify library in the future.

@akash87
Copy link

akash87 commented Jul 27, 2018

@powerful23 does it work for other providers too ? (google, amazon )

@powerful23
Copy link
Contributor

@akash87 It works for google but not sure for Amazon because I didn't add it as one of the providers in my Cognito User Pool settings.

@akash87
Copy link

akash87 commented Jul 27, 2018

This is great, thanks!!

@peetss
Copy link

peetss commented Jul 28, 2018

@powerful23 What do I do with the response from https://the-app-domain/oauth2/authorize?redirect_uri=callback_url&response_type=token&client_id=the_web_client_id&identity_provider=Facebook ?

Do I call federatedSignIn ? Do I pass the access_token or the id_token?

@bajzat
Copy link

bajzat commented Jul 29, 2018

Hi! Thanks for the great work around it works well. @peetss yes you need call the federatedSignIn first and after navigate to the custom url and you will get the JWT tokens.

I've only one question. How do you refresh the token after you get that, because It does not contain any refresh token? @powerful23 Could you give me a hint please?

Thanks again!

@powerful23
Copy link
Contributor

@peetss for now it's not completely integrated into the library but you can use a work around like:

import { CognitoAuth } from 'amazon-cognito-auth-js';

const params = {
                    ClientId,
                    UserPoolId,
                    AppWebDomain,
                    TokenScopesArray,
                    RedirectUriSignIn,
                    RedirectUriSignOut,
                    ResponseType,
                    Storage
}
const cognitoAuthClient = new CognitoAuth(params);
cognitoAuthClient.userhandler = {
                // user signed in
                onSuccess: (result) => {
                    Auth.currentSession().then(async (session) => {
                         // ...
                    });
                },
                onFailure: (err) => {
                    logger.debug("Error in cognito hosted auth response", err);
                }
};

const curUrl = window.location.href;
cognitoAuthClient.parseCognitoWebResponse(curUrl);

The params are basically the same with https://aws-amplify.github.io/amplify-js/media/authentication_guide#configuring-the-hosted-ui
What it does is to parse the callback url when loaded, store those tokens in the storage and fire the callback. Then Auth.currentSession() will return the session info to you.

@bajzat if there is no refresh token, then you will need to log the user out when the token is expired.

@xscottx
Copy link

xscottx commented Aug 19, 2018

Would someone (@bajzat @peetss) mind sharing out the snippet before the storage of the cognito token workaround? I'm unclear on how you're invoking the oauth url after the Auth.federatedSignIn call. I'm using the Facebook federated identity approach and it looks like from my react app I need to call the Cognito Oauth2 url, that then calls Facebook Oauth (https://your-cognito-domain/oauth2/idpresponse), which redirects back to Cognito and then my app.

@itaied246
Copy link

@powerful23 hello again :)
I'm trying to integrate this call you posted but I get cors from facebook.
Do you know how can I solve it?

@ardsouza
Copy link

@powerful23 are there any updates on how to get a refresh token via this method?

@powerful23
Copy link
Contributor

@ardsouza if you mean how to get the refresh token via Cognito Hosted UI, you need to set the responseType to code: https://aws-amplify.github.io/docs/js/authentication#configuring-the-hosted-ui

@BKB503
Copy link

BKB503 commented Dec 4, 2018

@powerful23 so it's not possible to get refresh token with response type :token

  1. will it work with custom IDP(SAML or OIDC) in cognito user pool registered identity?
  2. with response type:code how to get access token to authorize some .net web api endpoints

@powerful23
Copy link
Contributor

@BKB503

  1. Yes.
  2. When you get redirected back from the login page and Auth.configure() is called, Amplify library will try to parse the current url and get the tokens from Cognito. You need to use the Hub module in the Amplify to wait for the signIn event emitted: https://aws-amplify.github.io/docs/js/hub#listening-authentication-events
  3. Now you are logged in and you can call Auth.currentSession().then(session => console.log(session.getAccessToken()); to get the access token.

@BKB503
Copy link

BKB503 commented Dec 5, 2018

@powerful23 Thanks for your reply.

  1. If I use custom hosted UI based on domain in the textbox either SAML or OIDC it will redirect to relevant IDP login page with resonsetype: code it will get AUTHORIZATION_CODE,to get accesstoken Auth.currentSession().then(session => console.log(session.getAccessToken()); and send to WEB API endpoints, to achieve this I can use this library or is there any angular version to use it ?
  2. If not with Custom hosted UI what are options to implement with angular 6 and angular js including refresh token and custom IDP

@ngrosso
Copy link

ngrosso commented Dec 5, 2018

Hello! i used this workaround for now:

@peetss for now it's not completely integrated into the library but you can use a work around like:

import { CognitoAuth } from 'amazon-cognito-auth-js';

const params = {
                    ClientId,
                    UserPoolId,
                    AppWebDomain,
                    TokenScopesArray,
                    RedirectUriSignIn,
                    RedirectUriSignOut,
                    ResponseType,
                    Storage
}
const cognitoAuthClient = new CognitoAuth(params);
cognitoAuthClient.userhandler = {
                // user signed in
                onSuccess: (result) => {
                    Auth.currentSession().then(async (session) => {
                         // ...
                    });
                },
                onFailure: (err) => {
                    logger.debug("Error in cognito hosted auth response", err);
                }
};

const curUrl = window.location.href;
cognitoAuthClient.parseCognitoWebResponse(curUrl);

The params are basically the same with https://aws-amplify.github.io/amplify-js/media/authentication_guide#configuring-the-hosted-ui
What it does is to parse the callback url when loaded, store those tokens in the storage and fire the callback. Then Auth.currentSession() will return the session info to you.

@bajzat if there is no refresh token, then you will need to log the user out when the token is expired.

and it worked! at least until the feature is live. you can get the expiration time decoding the JWT access token.
My problem here is the lack of features for Angular2+ projects since all the docs examples for social authentication in userpools (in my case using identity provider) goes for a react approach, while trying to adapt it to Angular is not that clean as i wish... so yeah.. again, this worked for now but i'm waiting for a feature

@BKB503
Copy link

BKB503 commented Dec 5, 2018

@ngrosso is it working with above approach for custom idp ? if yes can you please provide me full example and which library is it amplify angular or amazon-cognito-auth-js

@powerful23
Copy link
Contributor

@BKB503

  1. As I said you can use the library to get the access token if you follow the right process. Then it depends on you to use that access token.
  2. The Cognito Hosted UI is the only way to federated with the Cognito User Pool.

@BKB503
Copy link

BKB503 commented Dec 5, 2018

@powerful23 Ok thanks

@cliffordh
Copy link

cliffordh commented Jan 13, 2019

When I call: https://DOMAIN.amazoncognito.com/oauth2/authorize?redirect_uri=https%3A%2F%2Flocalhost%3A8080%2F&response_type=token&client_id=CLIENTID&identity_provider=Facebook

I'm getting this response: https://localhost:8080/#error_description=unauthorized_client&error=invalid_request

Any ideas?

I'm able to bring up the hosted UI directly so I'm pretty sure my DOMAIN and CLIENTID are correct.

Wish this was easier!

@timgivois
Copy link

This seems fair, and its another workaround. The only problem is that it doesn't integrate with auth directives in the schema. I believe it's one of the coolest things that AppSync has, and also it's the reason we've chosen it instead of other Graphql servers like Apollo server. Plus, we'll need to add additional logic to add the user info to a Dynamo Table/User Pool.
For the moment, we'll handle authentication on our side: we'll switch to Api Keys for AppSync and create users directly in a Dynamo Table adding its info from facebook/google token we receive in the request. The authorization we'll be made by a Lambda that will check that the user has a valid token. We already have some automation tools that add transpiles a schema, adds a Lambda for authorization. (I wanted to use the aws implementation though)
I'm looking forward to see this feature (federatedLogin) implemented to consider the tool for future projects. thanks a lot for your reply, AWS team seemed really supportive and I really appreciate that.

@timgivois This should actually be able to use the @auth directive in the GraphQL Transformer. That directive uses the OIDC JWT token from User Pools to perform conditional logic in the AppSync resolvers (I was on the design team for this feature). You do need to define the authorization metadata somewhere which represents what users/groups have rights to a specific resource, and the way we do this with the Transformer is storing it on the DynamoDB record rather than hardcoding it in the resolver itself [1]. Essentially the AppSync resolver looks at $context.identity.username or $context.identity.claims.get("cognito:groups") and compares the current user context from the JWT token to what access has been granted on that GraphQL field.

[1] This is actually a fundamental requirement of any access control system as defined by Butler Lampson: https://en.wikipedia.org/wiki/Access_Control_Matrix
More info specific to AppSync which is what the GraphQL Transform does for you: https://docs.aws.amazon.com/appsync/latest/devguide/security-authorization-use-cases.html

Well, this is a cleaner way to user pools with AppSync. I'm not sure if we can find this in the docs.

@undefobj
Copy link
Contributor

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: #2716

Your feedback in the RFC will help us ensure that we are delivering the best experience possible. Thank you.

@donaldev
Copy link

donaldev commented Mar 14, 2019

@uclaeagit would you mind sharing what's involved in your postLogin() ?
I have the following

  const { access_token } = hashParams;
async function socialLogin() {
    console.log('Configure Settings');
    const cognitoAuthClient = new CognitoAuth(socialParams);

    cognitoAuthClient.userhandler = {
      onSuccess: async function(result) {
        console.log(result);
    // if I set {isAuthenticated} to true here, it navigates me to my authenticated route but it does this too quickly - it hasn't authenticated the user yet.
      },
      onFailure: async function(err) {
        console.log(err);
      },
    };
    await cognitoAuthClient.parseCognitoWebResponse(window.location.href);
  }

useEffect(() => {
    console.log('useEffect()');
    console.log('access_token', access_token);
    if (access_token) {
      socialLogin();
    }
  }, []);

See comment above. When I navigate to the authenticated app(and call getCurrentAuthenticatedUser()) it seems as though my logged in user is gone again, any help on this would be greatly appreciated.

@uclaeagit
Copy link

uclaeagit commented Mar 15, 2019

Sure, here's doPostLogin with some comments:

import { Auth } from 'aws-amplify'

export const doPostLogin = async () => {
  const userInfo = await getUser(Auth); // this goes to our back end
  const user = await Auth.currentAuthenticatedUser(); // make sure we have authenticated user
  
  if (userInfo.Success) component.props.history.push({pathname: '/dashboard'});
  else  component.props.history.push({pathname: '/promopage'});
};

We do some other stuff with user that won't matter to you. But I think awaiting the Auth.currentAuthenticatedUser() call is the key for you.

I just tested with our our getUser() call and it still works, so it's not because that is delaying it or anything.

@donaldev
Copy link

@uclaeagit Thank you for your response.
I tried what you have working in a similar manner -

export const doPostLogin = async () => {
  // const userInfo = await getUser(Auth);
  const user = await Auth.currentAuthenticatedUser();

  if (!user) {
    console.log('no user');
  } else {
    console.log('Here it comes');
    console.log(user);
    ///NAVIGATE TO SPACES
    ///setIsAuthenticated(true); here ends up pushing to /dashboard too early
  }
};

The console.log(user) does log a cognito user though which is great so thank you.
Are you managing your user sign in sessions yourself or relying on amplify?

@uclaeagit
Copy link

Using amplify for everything so far.

@peetss
Copy link

peetss commented Mar 26, 2019

I used the instructions provided here (https://serverless-stack.com/chapters/facebook-login-with-cognito-using-aws-amplify.html) to integrate federated login with aws-amplify.

Then I use amazon-cognito-js to save user-specific information for users logged in with federated identities.

@0x6C38
Copy link

0x6C38 commented Apr 9, 2019

@peetss those instructions are valid for federated identities with an identity pool not federated login with user pools.

@timgivois
Copy link

I believe there is a lot of confusion between identity pool and federated login with user pools. I don't think this is a problem with Amplify, it's Cognito's documentation.

@peetss
Copy link

peetss commented Apr 9, 2019

@0x6C38 Ahhh yes it is.

What is the use case for using federated identities with user pools?

AFAIK you will save a lot if you leverage identity pool vs saving all federated identities to user pool.

@0x6C38
Copy link

0x6C38 commented Apr 10, 2019

@peetss using a cognito user pool with groups allows for easy, granular authorization that is a lot more difficult with identity pools. Other than that I have no use for an identity pool if I can do federated login through the user pool.

@peetss
Copy link

peetss commented Apr 10, 2019

@0x6C38 Ah, what do you find to be more difficult in using identity pools for authorization?

@dementiev
Copy link

@peetss my use-case: I store users in user pool. Each user belongs to a group, depending on which he has access to different appsync urls. userId (sub) is also part of rows in dynamodb, where it is clear which data belongs to user. Let's say I have a row like this in Dynamo:
user-subid | entityBelongingtoUser-uuid | entity info.
user-subid | entityBelongingtoUser2-uuid | entity2 info.

How can achieve similar logic using identity pool?
Do you propose to store all users only in identity pool? Is there any good tutorial on this approach?
Thank you.

@Adr1ann
Copy link

Adr1ann commented May 7, 2019

I've tried all the possibilites but no chance to save facebook/google users into user pools. I'm using Auth.federatedSignIn, can display email,name but still don't save in user pools. What should I do after Auth.federatedSignIn?

Thank you!

@michelem09
Copy link

Is this #1316 (comment) in Amplify now?

@kylegwalsh
Copy link

I'm dealing with the same issue as @AdrianRealDevs. I've got the federatedSignIn working fine with Auth.federatedSignIn('facebook', { token: accessToken, expires_at }, user), but it does not create a user for them in the user pool.

I was previously using the Hosted UI (and it did create users in the user pool), but I found that the user experience is more customize-able by doing it manually.

It would be nice if there was some option in federated sign in to store the user in the user pool as well. For now, I'll probably trigger a Lambda that uses admin rights to create the social user during the sign up process.

@michelem09
Copy link

@kylegwalsh It seems you have to redirect to Hosted-UI to let create the user in the user pool, they suggest to use withOauth HOC from your custom UI, so you can still use your custom UI just using the hosted-UI endpoints to sign in social identity. #3875 (comment), but I still have to verify this.

Furthermore, I also was thinking to use a lambda but I didn't find any lambda triggered by Auth.federatedSignIn, did you do?

@kylegwalsh
Copy link

@michelem09

I ended up reverting to Hosted-UI due to the issue I cited above. When I was doing it manually, I did like the fact that I could trigger a popup window rather than temporarily redirecting the user away from my site, but I determined it was not worth the headache of trying to manually manage everything.

In addition I configured Hosted-UI to use a subdomain of my site (auth.mysite.com) so that I didn't have to rely on the random URL they generated.

@lhong375
Copy link

@manueliglesias is this supported now ?
even with all the customization, when we click any sso button to login (google/facebook/etc), the pop up won't be able to say exactly "use google/facebook/... to login", the nicest thing we can do is configured Hosted-UI to use a subdomain , so it will say "use some-subdomain-of-us to login", this is a sketchy experience to end user tbh

@Jun711
Copy link

Jun711 commented Apr 22, 2020

I used the instructions provided here (https://serverless-stack.com/chapters/facebook-login-with-cognito-using-aws-amplify.html) to integrate federated login with aws-amplify.

Then I use amazon-cognito-js to save user-specific information for users logged in with federated identities.

@peetss
What did you mean by using amazon-cognito-js to save user-specific information for users logged in with federated identities?

Did you use it to create a User Pool user for FB / Google / other IdP logged in users?

@peetss
Copy link

peetss commented Apr 23, 2020

@Jun711

Mainly I used this var client = new AWS.CognitoSyncManager(); for saving user-specific data.

@yonimor
Copy link

yonimor commented Jul 2, 2020

Any updates?

@ianmartorell
Copy link

As of the implementation of #2716 you can call Auth.federatedSignIn({ provider: 'Facebook' }) and it will sign in using User Pool Federation provided you have Amplify configured that way.

@github-actions
Copy link

This issue has been automatically locked since there hasn't been any recent activity after it was closed. Please open a new issue for related bugs.

Looking for a help forum? We recommend joining the Amplify Community Discord server *-help channels or Discussions for those types of questions.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jul 24, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Cognito Related to cognito issues feature-request Request a new feature
Projects
None yet
Development

No branches or pull requests