Signing a user up to your Cognito Pool using the AWS NodeJS SDK

Next-Auth is wonderful, and I've been using it a lot lately. But it only handles the OAuth flow (ie the login / logout functionality) of Cognito. However you need to roll your own Sign Up functionality as that sits outside the OAuth flow.

Digging through the documentation around implimenting SignUp using AWS's Node SDK was a little more involved than I'd hoped. The information is sparce and the examples obscure key components of the process, so I thought it would be worth posting a solution here.

To get started, you need two things:

  1. An IAM role with Access Key ID and Secret Access Token
  2. A Cognito Client ID that does not require a Client Secret.

They're both beyond the scope of this post, but there's plenty of resources online to help.

You shouldn't need a client secret because a) you've got the IAM Access Key and Secret; and b) this should be implimented server-side so your secrets are nicely tucked away in environment variables.

Then you just need some code that looks a bit like this:

async function createCognitoUser(email: string, password: string, nickname: string) {
  const client = new CognitoIdentityProviderClient({
    region: process.env.AWS_REGION,
    credentials: {
      accessKeyId: process.env.AWS_ACCEESS_ID, // IAM access ID
      secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY, // IAM Secret
    }
  });
  
  const input = {
    ClientId: process.env.AWS_CLIENT_ID, // cognito client
    Username: email, // email submitted by user
    Password: password, // password submitted by user
    UserAttributes: [{ Name: "email", Value: email }, { Name: "nickname", Value: 'hello' }], // user attributes
  }
  const command = new SignUpCommand(input);
  return client.send(command);
}

The function will return a Promise which you will probably need to await.

It's all pretty self explanatory really. You create the Client, defining the region and IAM user credentials. The CognitoIdentityProviderClient argument requires (at a minimum) the region and credentials fields. The credentials attribute needs to implement the AwsCredentialIdentity interface .

Then it's as simple as calling SignUpCommand with the necessary arguments. The SignUp command's signature impliments the SignUpCommandInput interface but ClientId, Password, and Username are the only three required fields.

There you have it!