DEV Community

Ed Legaspi
Ed Legaspi

Posted on • Originally published at czetsuyatech.com

Securing your NextJS Web Application with AWS Amplify and Cognito

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;
Enter fullscreen mode Exit fullscreen mode

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

Top comments (0)