Skip to content
This repository has been archived by the owner on Feb 24, 2018. It is now read-only.

How to authenticate user using identity providers in User Pool #508

Open
ildar-icoosoft opened this issue Aug 25, 2017 · 63 comments
Open

How to authenticate user using identity providers in User Pool #508

ildar-icoosoft opened this issue Aug 25, 2017 · 63 comments

Comments

@ildar-icoosoft
Copy link

ildar-icoosoft commented Aug 25, 2017

I need to authenticate users using federated identity providers in User Pool (docs). I can get access token from google or facebook but I don't know what should I do with this token to authenticate user in User Pool. Can you please give me an example how to do it using js sdk or link to API Reference method?

AWS Console User Pool screenshot

@danilotorrisi
Copy link

danilotorrisi commented Aug 25, 2017

I have a similar use case, I haven't found any sample code or docs. Is there anyone that can help us?

EDIT: Are you looking for Federated Identities on Identity Pools or Federation on User Pool? These are two different scenarios.

I want to provide the ability to authenticate via Facebook or Google and then authenticate the user on my User Pool to obtain a Token ( so in my case would be Federation on User Pool ). What about you?

@rafalwrzeszcz
Copy link

I have a very similar problem. However I think in such case the approach should be oposite (as previously I used Auth0 and that was very similar):

  1. Define custom attribute in user pool to store FB access token.
  2. Define attribute mapping for Facebook integration to map access_token to that custom attribute.
  3. Authenticate user with User Pool by specifying Facebook as authorizer (https://<yourdomain>.auth.<region>.amazoncognito.com/oauth2/authorize?identity_provider=Facebook&redirect_uri=https://<yourpage>&response_type=token&client_id=<your_user_pool_app_id>&scope=openid%20email%20profile%20aws.cognito.signin.user.admin&state=<verify_string>) - unfortunately I did not find equivalent method in Cognito Identity JS - only authroizeUser() variant uses username+password athentication
  4. Then you can obtain FB access token with AWS SDK from User Pool attributes.

Would be great to have this flow covered with the lib API (this feature was added not that long ago to User Pools - federated authenticators, so I guess libs are not yet updated).

@ildar-icoosoft
Copy link
Author

ildar-icoosoft commented Aug 25, 2017

@danilotorrisi I'm looking for Federation on User Pool too

@dianasotirova
Copy link

+1

2 similar comments
@ajaxon
Copy link

ajaxon commented Aug 26, 2017

+1

@jeetatl
Copy link

jeetatl commented Aug 26, 2017

+1

@itrestian
Copy link
Contributor

I've explained the process here:

#500

You would have to use the Auth sdk to interact with the authorize/token endpoints. https://github.com/aws/amazon-cognito-auth-js/

That would have you login with Facebook if Facebook is an identity provider for your user pool. A corresponding user is created in your user pool and the auth SDK saves that username and tokens in a local storage location (same location where this SDK retrieves it from). By using use case 16 in this SDK you can retrieve that user and the session containing the tokens.

@ildar-icoosoft
Copy link
Author

@itrestian Thank you for the answer. Is it posible NOT to use built-in AWS UI for signing up and signing in users? I want to use my own UI. Is it possible to authenticate user in User Pool by Facebook access token?

@rafalwrzeszcz
Copy link

@itrestian This is not the answer, as stated above we want to authenticate just with FB access token, not to trigger the external UI flow.

@ildar-icoosoft Please see my answer - by specifying identity_provider URL argument you automatically trigger the social flow. You can then also create a simple <iframe> to run it in the background and use postMessage() to send acquired tokens to parent.

@hblanken
Copy link

hblanken commented Aug 30, 2017

Would also like to see fed integrated in user pools. Any update on how this might be achieved / when the libs are being updated? Where might I find aws docs and examples?

@rachitdhall
Copy link

@rafalwrzeszcz, we do not accept Facebook token directly as of now. But if you hit /authorize endpoint with identity_provider=Facebook and the end user is already logged in, it will not show the Facebook UI to the end user (except the first time, when they need to grant the permissions to the Facebook App). Isn't this simpler as you do not have to deal with Facebook tokens? Any feedback is welcome on this.

@rafalwrzeszcz
Copy link

rafalwrzeszcz commented Aug 30, 2017

@rachitdhall: Totally, this is even the flow I proposed in my first post here. The only issue is that the lib doesn't provide possibility to do that. By specifying provider option I don't mean to add handling of Facebook token, but just URL identity_provider in the lib config so it could redirect to /authorize?...&identity_provider=Facebook. This way we could get a Cognito access/ID token automatically from hosted page configured with Facebook federation.

@davideickhoff
Copy link

davideickhoff commented Aug 31, 2017

@rachitdhall I use the cognito authentication within a native application and it makes things easier to just take the facebook sdk to get the Access Token and use this to register / authenticate on cognito (which can validate the access token at facebook in the background) . because on native applications, redirections don't work so well..

@ildar-icoosoft
Copy link
Author

ildar-icoosoft commented Sep 6, 2017

@rafalwrzeszcz Thank you! It works for me.

I have a function googleLogin, that opens https://<yourdomain>.auth.<region>.amazoncognito.com/oauth2/authorize?identity_provider=Google&redirect_uri=https://<redirect_page>&response_type=token&client_id=<your_user_pool_app_id>&scope=openid%20email%20profile%20aws.cognito.signin.user.admin&state=<verify_string> in popup window. <redirect_page> uses postMessage to send acquired tokens to parent script. Parent script gets tokens, saves tokens to cache and gets Cognito credentials.

Here is my code:

googleLogin() function. Pay attention to lines:

cognitoUser.signInUserSession = cognitoUser.getCognitoUserSession(tokensData);
cognitoUser.cacheTokens();

without them the session disappears after the page is refreshed

public googleLogin(): Observable<any> {
  return new Observable(observer => {
    let authHost = 'https://<some_name>.auth.us-east-1.amazoncognito.com';
    let identityProvider = 'Google';
    let redirectUri = 'https://localhost:8080/assets/oauth/receiver.html';
    let responseType = 'TOKEN';
    let clientId = '<app_client_id>';
    let state = 'some_state';
    let scope = 'profile email openid';

    let authUrl = `${authHost}/oauth2/authorize?identity_provider=${identityProvider}&redirect_uri=${redirectUri}&response_type=${responseType}&client_id=${clientId}&state=${state}&scope=${scope}`

    window.open(
      authUrl,
      "awsGoogleAuth",
      "location,toolbar,resizable,scrollbars,status,width=600,height=600"
    );

    window.addEventListener("message", res => {
      let tokensData = res.data;
      let token = tokensData.IdToken;
      let payload = token.split('.')[1];
      payload = JSON.parse(atob(payload));
      let username = payload['cognito:username'];

      let userPoolId = <user pool id>;
      let clientId = <client id>;

      AWS.config.credentials.params.Logins['cognito-idp.' + awsConfig.region + '.amazonaws.com/' + userPoolId] = token;
      AWS.config.credentials.refresh(err => {
        if (err) {
          return observer.error(err);
        }

        let poolData = {
          UserPoolId : userPoolId, // Your user pool id here
          ClientId : clientId // Your client id here
        };
        let userPool = new AWS.CognitoIdentityServiceProvider.CognitoUserPool(poolData);
        let userData = {
          Username : username,
          Pool : userPool
        };

        var cognitoUser = new AWS.CognitoIdentityServiceProvider.CognitoUser(userData);

        cognitoUser.signInUserSession = cognitoUser.getCognitoUserSession(tokensData);
        cognitoUser.cacheTokens();

        console.log("Amazon Cognito Identity", AWS.config.credentials.identityId);
        observer.next(AWS.config.credentials.identityId);
      });
    }, false);
  });
}

<redirect_page> - Page in popup window:

<script>
  function getHashValue(key) {
    var matches = location.hash.match(new RegExp(key+'=([^&]*)'));
    return matches ? matches[1] : null;
  }

  window.opener.postMessage({
    AccessToken: getHashValue('access_token'),
    ExpiresIn: getHashValue('expires_in'),
    IdToken: getHashValue('id_token'),
    TokenType: getHashValue('token_type')
  }, '*');
  window.close();
</script>

@ildar-icoosoft
Copy link
Author

ildar-icoosoft commented Sep 7, 2017

@davideickhoff you can try cordova in-app-browser plugin for Facebook. But it will not work with Google. Google denied access from web view

@ajaxon
Copy link

ajaxon commented Sep 15, 2017

I get an error on - CognitoUser does not exist on CognitoIdentityServiceProvider. If I get CognitoUser from amazon-cognito-identity-js it gives an error about no method cacheTokens() on cognitoUser .

   var cognitoUser = new AWS.CognitoIdentityServiceProvider.CognitoUser(userData);

    cognitoUser.signInUserSession = cognitoUser.getCognitoUserSession(tokensData);
    cognitoUser.cacheTokens();

@ildar-icoosoft
Copy link
Author

@ajaxon it looks like you didn't included amazon-cognito-identity.js script.
This should fix this error:

import "amazon-cognito-identity-js/dist/amazon-cognito-identity.js";
import "aws-sdk";

@ajaxon
Copy link

ajaxon commented Sep 15, 2017

Hmm yeah my imports are:

import {CognitoUserPool, CognitoUserAttribute, CognitoUser, AuthenticationDetails} from 'amazon-cognito-identity-js'; import * as AWS from 'aws-sdk'; import {CognitoIdentityCredentials} from "aws-sdk";

@ajaxon
Copy link

ajaxon commented Sep 15, 2017

So this is related to the typescript types file. I'll take a look at fixing that.

@ildar-icoosoft
Copy link
Author

@ajaxon try to replace import "amazon-cognito-identity-js"; to import "amazon-cognito-identity-js/dist/amazon-cognito-identity.js"; It should help

@ajaxon
Copy link

ajaxon commented Sep 15, 2017

I just edited the index.d.ts file to include the methods I needed. Everything is working now , however when I make a social login request I only get back the idToken and accessToken without the refreshToken. How are you keeping the social user token refreshed?

@flieks
Copy link

flieks commented Oct 10, 2017

@ildar-icoosoft thanks for the code but is there a way not to use aws-sdk ?

@cl2205
Copy link

cl2205 commented Oct 12, 2017

@ajaxon I was wondering the same and after some digging, I learned that in order to get a refreshToken along with idToken and accessToken, we have to opt for the authorization code grant flow. We do this by setting response_type=code as a request parameter to the /oauth2/authorize endpoint as mentioned in their docs.

When response_type=token, that uses the implicit flow which does not return a refreshToken for security reasons I think.

With the authorization code grant flow, we get an authorization code sent back as a query string parameter in the redirect url, which we'd then pass with a request to their /oauth2/token endpoint and get a json response back with the refreshToken included.

I got up to this point but get a 405 Method Not Allowed response from the /oauth2/token endpoint and not sure why. 😕

@juhamust
Copy link

I also struggled with this and managed to make it work for me, at least in minimal level. Finally, I created a simple app with setup instructions (see repo link below). Hope it is helpful for someone.

https://github.com/juhamust/serverless-aws-cognito-login

@frangeris
Copy link

I just made it using firebase in ~30 mins 😕

For now it's required using the hosted UI in AWS, but what about those that want to have their own UI? not using redirects on external services, seriously why? hope you adapt this in futures release....

About the jwt token from cognito for authenticate to AWS API Gateway? I just made my own authorizer for jwt using the firebase implementation and gets all working in my way...

@djar
Copy link

djar commented Oct 20, 2017

Can someone from AWS confirm whether it is possible or not to use the new "Federation" approach without the need to use the hosted UI?

@sam-jg
Copy link

sam-jg commented Nov 4, 2017

@djar I have figured out that if an app client only has a single identity provider then it will default to that provider and skip the hosted UI. So what I have done is made a Facebook client and a Google Client. Then the Facebook and Google login buttons on my site run use case 1 with the respective client ids. It seems like a work around, but gets the job done.

@ed-zm
Copy link

ed-zm commented Nov 7, 2017

Hi sam @sam-jg, I tried the same you say, however it still shows the hosted UI but only showing facebook in my case, did you do something else to avoid the hosted UI and get logged in? Thanks in advance

@djar
Copy link

djar commented Nov 7, 2017

It would be good of AWS to provide a response or information on this rather than letting the community guess and flounder.

@flieks
Copy link

flieks commented Nov 20, 2017

@sebelga are you using hosted-UI ?

@sebelga
Copy link

sebelga commented Nov 20, 2017

No, I am opening my own modal with a url like:

let authUrl = `${authHost}/oauth2/authorize?identity_provider=${identityProvider}&redirect_uri=${redirectUri}&response_type=${responseType}&client_id=${clientId}&state=${state}&scope=${scope}`

@flieks
Copy link

flieks commented Nov 21, 2017

@sebelga you mean using ....amazoncognito.com url ?
@sam-jg so when arriving on hosted-UI it will immediately redirect to the 1 availabile social provider ?

@richardzcode
Copy link

AWS Amplify is trying to help solving the problem. Please take a look here, help us improve.

AWS Amplify is a library, leverages Amazon Cognito service in authentication. So limitation to Cognito also applies, for example no OAuth only OpenID.

import { withFederated } from 'aws-amplify-react';

const Buttons = (props) => (
    <div>
        <img
            onClick={props.googleSignIn}
            src={google_icon}
        />
        <img
            onClick={props.facebookSignIn}
            src={facebook_icon}
        />
    </div>
)

const Federated = withFederated(Buttons);

...

    const federated = {
        google_client_id: '',
        facebook_app_id: ''
    };

    <Federated federated={federated} onStateChange={this.handleAuthStateChange} />

@flieks
Copy link

flieks commented Dec 4, 2017

@richardzcode thanks but it also uses the hosted UI ?

@richardzcode
Copy link

@flieks you can build your own UI. Just use with... to hook it up.

Google button:

const btn = (props) => (
    <div onclick={props.googleSignIn}>Google Sign In</div>
)

export const GoogleSignIn = withGoogle(btn)

Facebook button:

const btn = (props) => (
    <div onclick={props.facebookSignIn}>Facebook Sign In</div>
)

export const FacebookSignIn = withFacebook(btn)

Both:

const btns = (props) => (
    <div>
        <div onclick={props.googleSignIn}>Google Sign In</div>
        <div onclick={props.facebookSignIn}>Facebook Sign In</div>
    </div>
)

export const GoogleFacebookSignIn = withFederated(btns)

@flieks
Copy link

flieks commented Dec 10, 2017

Thanks @richardzcode so this uses the federation approach which doesn't need the redirect to the hosted UI ?
It's all a bit confusing: Federation vs OAuth 2 approach.
Does it have any disadvantages ?

@yuntuowang yuntuowang reopened this Dec 11, 2017
@hilkeheremans
Copy link

hilkeheremans commented Dec 15, 2017

For logging in users through Cognito and other Identity Providers with Federated User Pools, the code posted by @ildar-icoosoft is a valid starting point.

Using that snippet, with minor adjustments, you should be able to log in users without having to use the hosted UI at all, and without depending on amazon-cognito-auth-js.

Contrary to what @cl2205 mentions you can keep using the regular implicit flow, but you do need to add aws.cognito.signin.user.admin to the requested scope, or you will not receive the necessary tokens from Cognito.

@joe455
Copy link

joe455 commented Dec 19, 2017

@yuntuowang @hilkeheremans Is there sample app/ documentation to save the facebook user into userpool with custom UI?

@yuntuowang
Copy link
Contributor

@joe455 Currently, we don't have doc/sample for this specific use case. But I will bring this up in our meeting and discuss with team. Thanks.

@joe455
Copy link

joe455 commented Dec 26, 2017

Hi @yuntuowang , I am able to save the facebook user into userpool.Now how can retrive the current user logged in? getCurrentUser() returning me null always.

@icbdbmtbqinoot
Copy link

getCurrentUser() returns null when it is not authenticated. I was able to check the result of getCurrentUser() after using authenticateUser! not sure how cognito works... especially tokens.. Does refresh token help users not to log in again?? for like.. if I set the expiry time 10years? I saw the maximum is 3650days...

@yuntuowang
Copy link
Contributor

Hi @joe455 and @Kmiso, since we pushed the bug fix last week, now the SDK works well.
getCurrentUser() returns null when it is not authenticated. However, it is not null or empty after authenticating the user.

Refresh token is used for refreshing id token and access token when they are expiring, therefore you don't need to log in again. @Kmiso is correct, the upper limit of refresh token is 3650 days.
The details here: https://docs.aws.amazon.com/cognito/latest/developerguide/token-endpoint.html

About tokens:
https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-with-identity-providers.html

@louisfoster
Copy link

@yuntuowang If I call the token endpoint and retrieve the tokens (access, id & refresh) for the user, is there a way to store this information as I would if I had used the SDK to handle everything? At the moment I seem to have to manage the information in the tokens, and refreshing them, manually however I want to be able to call cognito user pool and get the user from that.

@yuntuowang
Copy link
Contributor

Hi @louisfoster, actually the auth SDK will cache tokens(store these info) after you sign in. When the current user's id token and access token are expiring, the SDK will check if refresh token is valid and refresh session as needed(when refresh token is valid).

To get the user, do you mean get the current signed in user?
Then you just need to call getCurrentUser() method which is in the CognitoAuth.js file(line 151) as I mentioned before.

@hetalmadhani
Copy link

hetalmadhani commented Feb 2, 2018

I have more than 1 SAML identity providers in my user pool. When the user enters the username is there a way to know based on the username which identity provider i should send the authorize request to?

@yuntuowang
Copy link
Contributor

Basically, when you sign up from a Identity Provider, e.g. Google, then the username saved on Cognito User Pool is like "Google_100338449557987692243". You can see this username under Cognito User Pool console "Users and groups" tab.

@hetalmadhani
Copy link

hetalmadhani commented Feb 3, 2018

thank you for your response, so when user with account "myAccount@IDP123" signed in using his identity provider "IDP123" on the hosted UI, that user got added to my UserPool and shows up as "IDP123_1000121342133211134" as you mentioned above. But i dont want to display all the identity providers under my user pool on the login screen, I need the user to be able to just enter "myAccount@IDP123" in the username textbox of my login screen and want to be able to determine behind the scenes his identity provider to get his access token. When I enter "myAccount@IDP123" in the username text box of the hosted UI I get the error "User does not exist"

@yuntuowang
Copy link
Contributor

Hi @hetalmadhani, I understand your situation. Currently, we don't support that you can sign in directly using "myAccount@IDP123" in the username text box of the hosted UI. You need to click the identity provider button to sign in. So basically, you need to display all the identity providers under your user pool on the login screen.
However, I will discuss your use case with my teammates and create a feature request. Thanks!

@timricker
Copy link

Hello @yuntuowang and others in my same situation...

I'm attempting to implement my own authentication flow and UI/UX in an iOS mobile app, using a Cognito User Pool (not Federated Identities), and I use the Facebook SDK to allow the user to authenticate, meaning they don't have to provide a password.

Upon the user successfully authenticating via the Facebook SDK, I receive back from Facebook an accessToken. As I understand from the documentation specified here:
https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-social.html I configure the OAuth redirect url of: https://your-user-pool-domain/oauth2/idpresponse within Facebook. What is not clear is:
(1) Does this then automatically create a user within my User Pool?
(1)(a) If YES, how can I access this newly created user? (I only have an access token and a facebook user id within my app at this stage)
(1)(b) if NO, how can I then create a user using only the access token without a username/password?

Thanks for your help.

@yuntuowang
Copy link
Contributor

Hi @timricker, I cannot open this link: https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-social.html

But I think I understand your situation. So if you authenticate using Facebook, then the answer is YES. It will automatically create a user with your Cognito User Pool.

What do you mean by accessing the newly created user? You can check this user on Cognito User Pool console under "Users and groups" tab. The username should be similar with "Facebook_100338449557987692243".

@daole
Copy link

daole commented Feb 11, 2018

@timricker I share your situation in Android. Unfortunately doing so won't get your user info saved into user pool, it has to go through the hosted UI which I don't want to use as it breaks my application UI/UX. I still desperately wait for AWS to support a native way. You can reference to the issue I posted here

@timricker
Copy link

@yuntuowang, I'm not sure why you can't access that url (it works fine for me) but thank you for clarifying that a user is automatically created in the user pool after configuring the OAuth redirect url within my Facebook app settings.

What I meant by asking how to access the newly created user is:
After I authenticate a user directly via the Facebook SDK in my app (not via the cognito hosted UI) and now have a facebook access token, with a user now created in my Cognito User Pool, how do I either:

  1. login the user using only the facebook access token, or
  2. retrieve/access a user's account using only the facebook access token?

The user will not have specified a password (nor should they have to as this is the benefit of using facebook connect).

It seems that @daole has raised the exact same issue above here and cognito does not support this functionality at this time. If this is indeed the case I would strongly suggest prioritizing this feature request as it makes cognito completely unusable for any serious mobile app that wants full control over its experience and not have to use the hosted UI.

@Nitansh44
Copy link

I have implemented 'Login with Google' in android hybrid app with the federated identities which is working fine and I am receiving accessKeyId, secretAccessKey, sessionToken.
But what I want is, when the user logged in with google, the new user id should also get created in 'User Pool' which is not happening right now.

AWS.config.region = region;
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: IdentityPoolId, // identity pool id here
Logins: {
// Change the key below according to the specific region your user pool is in.
// 'cognito-idp.us-east-1.amazonaws.com/us-east-1_x7DyN3tQH':idToken,
'accounts.google.com': idToken // idToken received from google
}
});

I haven't seen any document which clearly states the process.
I have set up the Identity providers under the Federation tab in User Pool with the correct Google app Id,
App secret and Authorize scope.

@johndpope
Copy link

johndpope commented Feb 22, 2018

@yuntuowang - we need a cheat sheet. a google doc slide
it seems like this flow will only work when using a 'hosted UI'

said another way - I get the app from mobile hub -
it's configured to allow signing up with facebook / google fine. this sign in flow works.
screen shot 2018-02-22 at 12 36 21 pm

when I go to user pool > users + groups -
Autogenerated group for users who sign in using Facebook
there's no congnito users created....
screen shot 2018-02-22 at 12 37 35 pm

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests