'How to open the sign up page of an Amazon Cognito Hosted UI directly?

In an app I am trying to have separate buttons to link to the sign up and sign in pages respectively of an Amazon Cognito User Pools' Hosted UI but so far I can only link to the sign in page.

I am using the AWS Amplify Package from npm and my code may look somehow like the following:

import { Auth } from "aws-amplify";

//...
function openSignIn() {
  Auth.federatedSignIn();
}

function openSignUp() {
  // ???
}

I have found no federatedSignUp() or a function that would accept options regarding it.

The url of the sign up page is:

<domain>/signup?redirect_uri=<redirect_uri>&response_type=<response_typ>&client_id=<client_id>&identity_provider=<identity_provider>&scopes=<scopes>&state=<state>

and while I know all parameters' values I don't know the value of the state param which makes it difficult to use it immediately in an anchor tag even though I don't like this solution.

Is there a proper/elegant solution at all?



Solution 1:[1]

These values are ones you can generate yourself so long as they follow the proper patterns and you can make them available later in the OAuth process. The values required and their format depend on your specific Cognito implementation for that hosted UI / user pool and how you are using it.

Here is some code (pseudo nodejs) to get you started:

    var crypto = require('crypto');

    function getRandomString () {
          const randomItems = new Uint32Array(28);
          var bytes = crypto.randomBytes(28);
          randomItems.set(bytes);
          const binaryStringItems = randomItems.map(dec => `0${dec.toString(16).substr(-2)}`)
          return binaryStringItems.reduce((acc, item) => `${acc}${item}`, '');
    }
    
    var state = getRandomString();
    var code_verifier = getRandomString();
    var code_challenge = crypto.createHash('sha256').update(code_verifier).digest('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
    
    var redirect_url  = "https://"+domain+".auth."+region+".amazoncognito.com/oauth2/authorize?response_type=code&state="+state+"&client_id="+appClientId+"&redirect_uri="+redirectURI+"&scope=openid&code_challenge_method=S256&code_challenge="+code_challenge;

This assumes a number of things about the Cognito setup and how you are leveraging it (e.g. scope is openid, challenge is S256) but hopefully it can guide you a little. You will need to store some of these things locally before passing them on:

https://betterprogramming.pub/how-to-securely-implement-authentication-in-single-page-applications-670534da746f

Sorry this isn't more Amplify specific.

Solution 2:[2]

I'm not sure this counts as elegant, but here is a way:

  1. Override the Amplify Auth urlOpener configuration.
  2. Initiate Auth.federatedSignIn()
  3. Modify the captured URL of the form /oauth2/authorize? and replace with /signup?.
  4. Open the URL.
  5. This will initiate Cognito Hosted UI sign-up and then proceed as normal.

Notes:

  1. Details on Cognito Hosted UI URLs are here.
  2. Details on Amplify Auth config here and here.
  3. The default launchUri implementation just uses window.open() - see here.

More detail on implementation below.

Define your own urlOpener:

const urlOpener = async (url: string, redirectUrl: string): Promise<any> => {
  const signupUrl = url.replace(/\/oauth2\/authorize\?/, '/signup?');
  return launchUri(signupUrl);
};

Configure Amplify:

const config = {
    Auth: {
        ...
        oauth: {
            ...
            urlOpener,
        },
    },
};
Amplify.configure(config);

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 couchcode
Solution 2 Daniel