Securing your NextJS Web Application with AWS Amplify and Cognito
Tags: react, nextjs, aws, security
Published: 2022-12-13 02:44:33

## 1. Introduction
NextJS is an open-source framework for developing React applications, while Cognito is a user identity service that lets you secure your applications. Cognito also supports the OAuth form of authentication.

AWS Amplify is an open-source library for managing AWS services like Cognito. It exposes an Authenticator library that can secure an application and provides a ready-made, customizable sign in and signup component.

## 2. Requirements
You will need the following to run this project.

Google Console Project
NodeJS installed on your local machine

## 3. The code

For this exercise, I use the new Authenticator component that Amplify UI library provides: https://ui.docs.amplify.aws/components/authenticator, specifically the withAuthenticator HOC.

And since I wanted to customize this HOC and make it reusable, I wrapped it in another HOC.

```
import React from 'react';
import Link from 'next/link';
import {
  AmplifyProvider,
  Authenticator,
  Button,
  CheckboxField,
  Divider,
  Flex,
  Heading,
  Image,
  Text,
  useAuthenticator,
  useTheme,
  View,
  withAuthenticator
} from "@aws-amplify/ui-react";
import '@aws-amplify/ui-react/styles.css';
import {I18n} from "aws-amplify";
 
I18n.putVocabulariesForLanguage('en', {
  Email: 'Enter your email', // Username label
  Password: 'Enter your password', // Password label
});
 
const withSecurity = (Component) => {
 
  const WithAmplifyProviderComponent = ({...rest}) => {
    return (
        <AmplifyProvider>
          <Component {...rest}></Component>
        </AmplifyProvider>
    )
  }
 
  return withAuthenticator(WithAmplifyProviderComponent, {
    loginMechanisms: ['email'],
    socialProviders: ['facebook', 'google'],
    signUpAttributes: ['family_name', 'given_name'],
    components: {
      Header() {
        const {tokens} = useTheme();
 
        return (
             View textAlign="center" padding={tokens.space.large}>
               Image
                  alt="Czetsuya Tech"
                  src="https://4.bp.blogspot.com/-mjqhWWOAQ4k/YHGCZ8vh16I/AAAAAAAAMk4/ciGAb0cebQkuXMS_2y_r_BIa20aaXgoYgCK4BGAYYCw/s1600/Artboard%2B1.png"
              />
             /View>
        );
      },
      // Customize `Authenticator.SignUp.FormFields`
      SignUp: {
        FormFields() {
          const {validationErrors} = useAuthenticator();
 
          return (
               >
                {/* Re-use default `Authenticator.SignUp.FormFields` */}
                 Authenticator.SignUp.FormFields/>
 
                {/*Append & require Terms & Conditions field to sign up*/}
                 CheckboxField
                    errorMessage={validationErrors.acknowledgement}
                    hasError={!!validationErrors.acknowledgement}
                    name="acknowledgement"
                    value="yes"
                    label="I agree with the Terms & Conditions"
                >
                 /CheckboxField>
               />
          );
        }
      },
      SignIn: {
        Header() {
          const {tokens} = useTheme();
 
          return (
               Heading
                  padding={`${tokens.space.xl} 0 0 ${tokens.space.xl}`}
                  level={3}
              >
                Sign in to your account
               /Heading>
          );
        },
        Footer() {
          const {toResetPassword} = useAuthenticator();
 
          return (
               View textAlign="center">
                 Button
                    fontWeight="normal"
                    onClick={toResetPassword}
                    size="small"
                    variation="link"
                >
                  Reset Password
                 /Button>
               /View>
          );
        },
      },
      Footer() {
        const {tokens} = useTheme();
 
        return (
             React.Fragment>
               View textAlign="center" padding={tokens.space.large}>
                 Text color={`${tokens.colors.neutral['80']}`}>
                  © 2021 Czetsuya Tech ® All Rights Reserved
                 /Text>
               /View>
               Divider/>
               View textAlign="center" padding={tokens.space.large}>
                 Flex direction="column">
                   Link href="/resources/terms-and-conditions">
                     a>Terms and Conditions /a>
                   /Link>
                   Link href="/resources/privacy-policy">
                     a>Privacy Policy /a>
                   /Link>
                 /Flex>
               /View>
             /React.Fragment>
        );
      },
    },
    services: {
      async validateCustomSignUp(formData) {
        if (!formData.acknowledgement) {
          return {
            acknowledgement: 'You must agree to the Terms & Conditions',
          };
        }
      },
    }
  })
}
 
export default withSecurity;
```

You can download the complete source code at https://github.com/czetsuya/lab-nextjs, check out the branch feature/aws-amplify.