Complete Guide to Build Authentication system with Amplify and Next.js

Sumit Sapkota
readytowork, Inc.
Published in
10 min readSep 26, 2023

An efficient authentication system is essential to the security and usability of online applications in today’s networked digital environment. This post will show you how to utilize AWS Amplify and Next.js to easily develop a strong authentication system, giving you the power to design a frictionless registration and login process that improves both security and developer experience.

Are you sick of battling web app authentication? Would you like to integrate Amplify into your Next.js projects? You’re in the proper location! This thorough guide explains how to use AWS Amplify to implement an authentication mechanism into your Next.js applications. You can quickly create an authentication flow with the help of these step-by-step instructions!

Table of Contents:

  1. Setting up AWS Amplify CLI
  2. Build Amplify Authentication Service
  3. Creating a Next.js Project
  4. Implementing Amplify Default User Sign-In and Sign-Up
  5. Implementing Custom User Sign-In and Sign-Up
  6. Retrieving User Information

Make sure you have the following prerequisites in place before we start the implementation:

  • Basic Understanding of React.js and Next.js
  • An AWS account
  • Nodejs and NPM in your local machine

Setting up AWS Amplify CLI

First, you need to have an AWS account. Now you need to install amplify CLI on your local machine, to do that runnpm install -g @aws-amplify/cli Next, run amplify configure This will automatically open up the AWS console to make sure you have an account and are signed in. After that, you can switch back to your code editor, press enter, and select your region.

And you will be redirected to complete the user creation in the AWS console.

In the next step, you will see the permission level. Select attach policies directly, For our Amplify app, we will go with AdministratorAccess-Amplify (set by default). Select Next to continue:

Finally, review the changes the confirm the IAM user Creation by clicking in Create User.

In the next page, you will see the IAM users and you can find recently created user in this page called auth-root

Now we need to generate Access Key and Secret Key in order to authenticate Amplify CLI.

Click on your IAM user and select Security Credential tab and scroll down till you see Access Keys.

Now create a new Access Key and Select the use case Command Line Interface (CLI) . It will generate an Access Key and Access Secret Key for your IAM user.

Now use these keys in your CLI to authenticate.

That’s it for the Amplify CLI configuration in your Terminal.

Now we can move on to the next step.

Build Amplify Authentication Service

Now, login to the AWS console and Search for Amplify service.

Now click on Get Started and start creating your new Amplify App.

Let's get started with building our App.

Now Give your app a name and confirm the deployment

After deployment is successful you will see the below screen now you need to launch Amplify studio

Launching Studio will bring you to the Amplify Studio page. Amplify studio has many other functions like Data, Functions, Storage etc but for now we will go into authentication.

Now Enable Authentication and It will redirect you to the Auth setup page.

Next, you need to configure your authentication system. In the first step, you can configure the Login mechanism and you can add as many mechanisms as you want like login with email, google, apple, facebook etc. In the Second part, you need to configure user signup attributes, these are the fields that the user is required to fill during signup. It provides many more config settings like password requirements and verification message settings. So, feel free to express the dashboard.

Here I have enabled email and Google login, For Google login you need to provide Client ID and Client Secret. And I have added two attributes Phone Number and Name for Signup.

Next, Deploy the authentication service.

After your Authentication service has been deployed to the AWS server. Now you can pull this service in your next.js app and use the service.

Creating and Configuring Next.js Project

Let’s create a next.js project by using the command npx create-next-app@v12 . After successfully creating a Next.js project let’s install the amplify dependencies.

npm install aws-amplify @aws-amplify/ui-react

@aws-amplify/ui-react Is the UI component library provided by the AWS which makes building UI seamless for us.

Now, it’s time to pull the auth configuration we created in the previous app to our app. Using the below command, this command was given to us when the auth service was deployed successfully. Look at the most recent image above.

amplify pull - appId d3u3ibrthnx3za - envName staging

This code will pull all the auth configurations to your next.js app but before pulling it will ask some question

This will add amplify directory in your project root and also a file called aws-exports.js which contains the credentials for AWS auth app.

Now, let’s get started with the Coding part.

First, we need to add some configuration to your pages/_app.tsx file. This will add amplify to your Project and we have also imported aws-amplify css which will help us build beautiful UI easily.

import '../styles/globals.css'
import type { AppProps } from 'next/app'
import { Amplify } from 'aws-amplify'
import awsconfig from "../aws-exports"
import "@aws-amplify/ui-react/styles.css";


Amplify.configure({ ...awsconfig, ssr: true });

function MyApp({ Component, pageProps }: AppProps) {
return <Component {...pageProps} />
}

export default MyApp

Let’s create a page called auth/index.tsx in pages directory and add the following code.

import React from "react";
import styled from "styled-components";
import { Authenticator } from "@aws-amplify/ui-react";

const Container = styled.div`
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
`;

const Authentication = () => {
return (
<Container>
<Authenticator>
{({ signOut, user }) => (
<main>
<h1>Hello, {user?.username}!</h1>
<button onClick={signOut}>Sign out</button>
</main>
)}
</Authenticator>
</Container>
);
};

export default Authentication;

We created an Authenticator component for the homepage so that the user is required to create an account or log in to see the content. Run npm run dev to start the developer server again and open http://localhost:3000:

Now, create an account using the attributes you provided in your auth service and try to sign in. You will be presented with the greeting indicating that you have successfully authenticated:

Tada, You have successfully implemented an Authentication service using Amplify and Next.js.

However, we will not stop here. If you have a pre-built login and signup page. You can implement login and signup in your own components. We will see how!

Implementing Custom User Sign-In and Sign-Up

For this, I have created custom-signup , confirm-email, custom-login pages in my project.

For Custom Signup Page:

import { Button, Input, Link } from "@aws-amplify/ui-react";
import { notification } from "antd";
import { Auth } from "aws-amplify";
import { useRouter } from "next/router";
import React, { useState } from "react";
import styled from "styled-components";

const Container = styled.div`
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
background-color: white;
color: black;
form {
width: 50%;
}
input {
margin-top: 20px;
margin-bottom: 20px;
}
`;

const Signup = () => {
const [email, setemail] = useState("");
const [password, setPassword] = useState("");
const [name, setname] = useState("");
const [phone, setPhone] = useState("");
const router = useRouter()
const handleSubmit = async (e: any) => {
e.preventDefault();
try {
await Auth.signUp({
username: email,
password: password,
attributes: {
email: email,
name: name,
phone_number: phone,
},
});
notification.success({
message: "User created successfully",
});
router.push(`/confirm-email?user=${email}`)
} catch (error) {
notification.error({
message: `Failed to create user ${error}`,
});
}
};
return (
<Container>
<div>AWS custom signup</div>
<form onSubmit={handleSubmit}>
<Input
name="Name"
placeholder="Enter Name"
required={true}
type="text"
onChange={(e) => setname(e.target.value)}
/>
<Input
name="Email"
placeholder="Enter Email"
required={true}
type="email"
onChange={(e) => setemail(e.target.value)}
/>
<Input
name="Password"
placeholder="Enter Password"
required={true}
type="password"
onChange={(e) => setPassword(e.target.value)}
/>
<Input
name="Phone"
placeholder="Enter Phone number"
required={true}
type="text"
onChange={(e) => setPhone(e.target.value)}
/>
<Button type="submit">Create Account</Button>
</form>
<Link href={"/custom-login"}>Go to Login page</Link>
</Container>
);
};

export default Signup;

We will make user of Auth method that is imported from amplify library to the Signup user.

After signup is complete, we will redirect the user to the email verification page, Verification code will be sent to the registered email.

import { Button, Input } from "@aws-amplify/ui-react";
import { notification } from "antd";
import { Auth } from "aws-amplify";
import { useRouter } from "next/router";
import React, { useState } from "react";
import styled from "styled-components";

const Container = styled.div`
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
background-color: white;
color: black;
form {
width: 50%;
}
input {
margin-top: 20px;
margin-bottom: 20px;
}
`;

const Login = () => {
const [code, setCode] = useState("");
const router = useRouter()
const {query} = router
const user = query.user
const handleSubmit = async (e: any) => {
e.preventDefault();
try {
await Auth.confirmSignUp(user, code);
notification.success({
message: `User verified successfully, now you can login`,
});
router.push("/custom-login")
} catch (error) {
notification.error({
message: `Failed to verify user ${error}`,
});
}
};
return (
<Container>
<div>Confirm Email</div>
<form onSubmit={handleSubmit}>
<Input
name="Verification COde"
placeholder="Enter Verification Cdde"
required={true}
type="text"
onChange={(e) => setCode(e.target.value)}
/>
<Button type="submit">Verify My Account</Button>
</form>
</Container>
);
};

export default Login;

Similarly, custom-login page

import { Button, Input } from "@aws-amplify/ui-react";
import { notification } from "antd";
import { Auth } from "aws-amplify";
import Link from "next/link";
import React, { useEffect, useState } from "react";
import styled from "styled-components";

const Container = styled.div`
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
background-color: white;
color: black;
form {
width: 50%;
}
input {
margin-top: 20px;
margin-bottom: 20px;
}
`;

const Login = () => {
const [email, setemail] = useState("");
const [password, setPassword] = useState("");
const [isLoggedIn, setisLoggedIn] = useState(false);
const [user, setUser] = useState<{name:string} | null>(null)
const handleSubmit = async (e: any) => {
e.preventDefault();
try {
await Auth.signIn(email, password);
notification.success({
message: "Logged in successfully",
});
setisLoggedIn(true);
} catch (error) {
notification.error({
message: `Failed to login ${error}`,
});
}
};
useEffect(() => {
const fetchUsers = async () => {
const {attributes} = await Auth.currentUserInfo();
setUser(attributes)
};
fetchUsers();
}, [isLoggedIn]);

if (isLoggedIn) {
return <Container>Hello, {user?.name}!!!!</Container>;
}

return (
<Container>
<div>AWS custom Login</div>
<form onSubmit={handleSubmit}>
<Input
name="Email"
placeholder="Enter Email"
type="email"
onChange={(e) => setemail(e.target.value)}
/>
<Input
name="Password"
placeholder="Enter Password"
type="password"
onChange={(e) => setPassword(e.target.value)}
/>
<Button type="submit">Login</Button>
</form>
<Link href={"/custom-signup"}>Go to Signup page</Link>
</Container>
);
};

export default Login;

Let’s see the above code output in UI.

--

--

Sumit Sapkota
readytowork, Inc.

Full Stack Developer. Golang, React.js, Next.js, Flutter, GCP