React + AWS Cognito: Email Authentication Setup Guide (Second Part)

In the last post, we handled everything on the AWS side; now let’s dive into React to set up our code.

AWS provides the npm package @aws-sdk/client-cognito-identity-provider, which includes functions for:

  • Creating an account using an email and password
  • Verifying the email via a code sent by AWS
  • Logging in with the email and password

React + AWS Cognito: Email Authentication Setup Guide (Second Part)

Check out the demo page to try it yourself, and feel free to look at the code in the GitHub repository.

Sign up

The first step is signing up

import { SignUpCommand } from "@aws-sdk/client-cognito-identity-provider";

const AWS_CLIENT_ID = "REPLACE_WITH_YOUR_AWS_CLIENT_ID";
const AWS_REGION = "REPLACE_WITH_YOUR_AWS_REGION";

const cognitoClient = new CognitoIdentityProviderClient({
  region: AWS_REGION,
});

export const signUp = async (email: string, password: string) => {
  const params = {
    ClientId: AWS_CLIENT_ID,
    Username: email,
    Password: password,
    UserAttributes: [
      {
        Name: "email",
        Value: email,
      },
    ],
  };

  const command = new SignUpCommand(params);

  try {
    await cognitoClient.send(command);
  } catch (error) {
    throw error;
  }
};

Note how AWS_CLIENT_ID is required, and this helper function takes in email and password. In the demo, both values are input by the user in a form, and the UI then calls this method, passing those values.

If there’s an error, an exception is thrown, and the UI handles it accordingly.

Confirmation

Note: During testing, any email used in the form must first be verified. This won’t be necessary in production.

When SignUpCommand runs, AWS registers the account and sends a verification code by email, so the next step is to check the inbox and copy the code.

import { ConfirmSignUpCommand } from "@aws-sdk/client-cognito-identity-provider";

const AWS_CLIENT_ID = "REPLACE_WITH_YOUR_AWS_CLIENT_ID";
const AWS_REGION = "REPLACE_WITH_YOUR_AWS_REGION";

const cognitoClient = new CognitoIdentityProviderClient({
  region: AWS_REGION,
});

export const confirmSignUp = async (username: string, code: string) => {
  const params = {
    ClientId: AWS_CLIENT_ID,
    Username: username,
    ConfirmationCode: code,
  };

  const command = new ConfirmSignUpCommand(params);
  try {
    await cognitoClient.send(command);
  } catch (error) {
    throw error;
  }
};

Notice that ConfirmSignUpCommand requires your AWS ClientId, username (email), and the confirmation code that was sent to the email.

Sign In

If ConfirmSignUpCommand completes successfully, the account should be all set for logging in.

import {
  AuthFlowType,
  SignUpCommand,
} from "@aws-sdk/client-cognito-identity-provider";

const AWS_CLIENT_ID = "REPLACE_WITH_YOUR_AWS_CLIENT_ID";
const AWS_REGION = "REPLACE_WITH_YOUR_AWS_REGION";

const cognitoClient = new CognitoIdentityProviderClient({
  region: AWS_REGION,
});

export const signIn = async (username: string, password: string) => {
  const params = {
    AuthFlow: AuthFlowType.USER_PASSWORD_AUTH,
    ClientId: AWS_CLIENT_ID,
    AuthParameters: {
      USERNAME: username,
      PASSWORD: password,
    },
  };
  const command = new InitiateAuthCommand(params);

  let AuthenticationResult;
  try {
    const response = await cognitoClient.send(command);
    AuthenticationResult = response.AuthenticationResult;
  } catch (error) {
    throw error;
  }

  if (!AuthenticationResult) {
    return;
  }

  sessionStorage.setItem("idToken", AuthenticationResult.IdToken || "");
  sessionStorage.setItem("accessToken", AuthenticationResult.AccessToken || "");
  sessionStorage.setItem(
    "refreshToken",
    AuthenticationResult.RefreshToken || ""
  );

  return AuthenticationResult;
};

In the InitiateAuthCommand, AWS requires the ClientId, username (email), and password provided by the user through the form. If the email has already been verified, the login will succeed.

Additionally, some values are stored in sessionStorage for potential future use.

Conclusion

Check out the demo and explore the code base.

Cognito is relatively easy to set up yet powerful. It handles essentials like creating, verifying, and authenticating accounts. While building your own service for this is possible, it demands significant effort for proper implementation and maintenance.

When starting a project, cloud services offer the advantage of offloading these responsibilities so you can focus on your core business logic, even if it introduces some dependency.