Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SSO with AWS Cognito and Sub Domains

Can I easily pass identity information to multiple subdomain with AWS Cognito? If I have three applications (app1.example.com, app2.example.com, app3.example.com), how can I sign into app1, then pass the identity information to app2 and app3? I've read docs and seen methods such as getIdToken().getJwtToken, but I havn't seen how to pass such data to so I can use the identity.

//Login.ts
let cognitoUser = new CognitoUser(userData);
cognitoUser.authenticateUser(authenticationDetails, function(){
    onSuccess: function(result){
        let jwt = result.getIdToken().getJwtToken();
        //Is it possible to pass this jwt token (or something else)
        //to app2 and app3 so I can later fetch the user from the identity pool from those apps?
    }
});

2 Answers

You can achieve SSO across all your subdomains by using the CookieStorage class from the JS SDK while creating the CognitoUserPool objects. When the authentication tokens received from Cognito are stored in cookies (instead of LocalStorage), they are available on all the sub-domains also. So calls to CognitoUserPool.getCurrentUser() and CognitoUserPool.getSession() will return the tokens from all sub-domains.

TypeScript Code snippets below

Full implementation can be found here. A running application can be viewed here.

To authenticate the User (on the main domain, say, example.com) -

signIn(email: string, password: string): Observable<any> {
    let userPool = new CognitoUserPool({
       UserPoolId: environment._USER_POOL_ID,
       ClientId: environment._CLIENT_ID,
       Storage: new CookieStorage({secure: false, domain: "example.com"}),
    });
    let authenticationDetails = new AuthenticationDetails({
      Username: email,
      Password: password,
    });

    let userData = {
        Username: email,
        Pool: userPool,
        Storage: new CookieStorage({secure: false, domain: "example.com"}),
    };
    let cognitoUser = new CognitoUser(userData);
    return Observable.create((observer: Observer<any>) => {
      cognitoUser.authenticateUser(authenticationDetails, {
        onSuccess: result => {
          observer.next(result);
          observer.complete();
        },
        onFailure: error => observer.error(error),
      });
    });
}

To check if user is authenticated (on a subdomain, say, sub.example.com)

isAuthenticated(): Observable<boolean> {
    let userPool = new CognitoUserPool({
       UserPoolId: environment._USER_POOL_ID,
       ClientId: environment._CLIENT_ID,
       Storage: new CookieStorage({secure: false, domain: "example.com"}),
    });
    let cognitoUser = userPool.getCurrentUser();
    if (cognitoUser != null) {
      return Observable.create((observer: Observer<boolean>) => {
        cognitoUser.getSession((error, session) => {
          if (error) {
            console.error(error);
            observer.next(false);
            observer.complete();
          }
          console.log(session, session.isValid(), session.isAuthenticated);
          observer.next(session.isValid());
          observer.complete();
        });
      })
}
like image 108
Sarthak Jain Avatar answered Sep 06 '25 01:09

Sarthak Jain


First of all, application subdomain, doesn't have a direct connection with AWS Cognito.

If you have subdomains and need to authenticate users using a single Cognito Userpool while also checking the link of the identity with the subdomain (Assuming upon user registration, they get registered from a particular subdomain app), you need to either store that information in a custom attribute in Cognito User or in your storage backend linking with the Cognito ID and subdomain, and verify it in code while user authenticates.

//Login.ts
let cognitoUser = new CognitoUser(userData);
cognitoUser.authenticateUser(authenticationDetails, function(){
    onSuccess: function(result){
        // Also check the user custom attribute comparing with the request subdomain.
        let jwt = result.getIdToken().getJwtToken();
        //You can pass this jwt token back to the client
        //Each app can later fetch user data from identity pool
    }
});

Note: If you use Hosted UI for the Login, the flow might be slightly different, since you need to create three client apps with different callback urls for each subdomain.

I'm trying to develop a solutions similar to Google's auth process. You sign in once to accounts.google.com, then that session is used for mail.google.com, news.google.com, etc. You don't need to login into each application manually. Once I log into accounts.myapp.com, I need to pass the user's auth to mail.myapp.com and news.myapp.com. I don't see in the AWS docs how I can create an instance of the Cognito client (from mail.myapp.com, or news.myapp.com) from the identity created in accounts.myapp.com

This is achievable using Cognito UserPools.

  • Create an API endpoint which will issue an JWT token after validating Users Credentials (e.g Username & Password). Check the Authenticate a User section in this example.
  • From your frontend apps invoke this API and store the JWT in browser storage (e.g LocalStorage, SessionStorage).
  • For future API invocations, include the JWT in the header and send to your API where API will validate the JWT token. For more details check the Using ID Tokens and Access Tokens in your Web APIs section in this documentation.
like image 37
Ashan Avatar answered Sep 06 '25 00:09

Ashan