amazon-cognito-identity-js icon indicating copy to clipboard operation
amazon-cognito-identity-js copied to clipboard

How to authenticate user using identity providers in User Pool

Open ildar-icoosoft opened this issue 8 years ago • 63 comments

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

ildar-icoosoft avatar Aug 25 '17 06:08 ildar-icoosoft

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?

danilotorrisi avatar Aug 25 '17 07:08 danilotorrisi

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).

rafalwrzeszcz avatar Aug 25 '17 07:08 rafalwrzeszcz

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

ildar-icoosoft avatar Aug 25 '17 09:08 ildar-icoosoft

+1

dianasotirova avatar Aug 25 '17 13:08 dianasotirova

+1

ajaxon avatar Aug 26 '17 20:08 ajaxon

+1

jeetatl avatar Aug 26 '17 21:08 jeetatl

I've explained the process here:

https://github.com/aws/amazon-cognito-identity-js/issues/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.

itrestian avatar Aug 28 '17 17:08 itrestian

@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?

ildar-icoosoft avatar Aug 28 '17 20:08 ildar-icoosoft

@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.

rafalwrzeszcz avatar Aug 28 '17 21:08 rafalwrzeszcz

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?

hblanken avatar Aug 30 '17 07:08 hblanken

@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.

rachitdhall avatar Aug 30 '17 17:08 rachitdhall

@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.

rafalwrzeszcz avatar Aug 30 '17 18:08 rafalwrzeszcz

@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..

davideickhoff avatar Aug 31 '17 11:08 davideickhoff

@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 avatar Sep 06 '17 20:09 ildar-icoosoft

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

ildar-icoosoft avatar Sep 07 '17 10:09 ildar-icoosoft

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();

ajaxon avatar Sep 15 '17 19:09 ajaxon

@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";

ildar-icoosoft avatar Sep 15 '17 19:09 ildar-icoosoft

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 avatar Sep 15 '17 19:09 ajaxon

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

ajaxon avatar Sep 15 '17 19:09 ajaxon

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

ildar-icoosoft avatar Sep 15 '17 19:09 ildar-icoosoft

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?

ajaxon avatar Sep 15 '17 21:09 ajaxon

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

flieks avatar Oct 10 '17 08:10 flieks

@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. 😕

cl2205 avatar Oct 12 '17 21:10 cl2205

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

juhamust avatar Oct 14 '17 17:10 juhamust

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...

frangeris avatar Oct 14 '17 18:10 frangeris

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?

djar avatar Oct 20 '17 05:10 djar

@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.

sam-jg avatar Nov 04 '17 01:11 sam-jg

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

ed-zm avatar Nov 07 '17 19:11 ed-zm

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

djar avatar Nov 07 '17 22:11 djar

@ed-zm what 'Allowed OAuth Flows' are you using? I only have 'Implicit grant' selected.

sam-jg avatar Nov 07 '17 22:11 sam-jg