How to implement authentication in NextJS using Amazon Cognito
Tags: authentication, cognito, nextjs
Published: 2022-12-26 01:52:49

Are you looking to implement authentication forms in your NextJS project using Amazon Cognito? Then this article is for you.

# 1. Introduction

1.1 Amazon Cognito
Amazon Cognito is an authentication and authorization service that lets you manage your applications' access control, whether a web or mobile app. Whether dealing with a small number of users or millions, Cognito already has the infrastructure set up for you. It also supports integration with popular identity providers such as Facebook, Google, and Apple. See their documentation.

Amazon Cognito provides a good amount of documentation for any level of developers to start with. They have complete user authentication forms, UI components that you can easily integrate into your application, and a set of APIs you can call in case you want to implement your own custom UI. All these are available from their website at https://docs.amplify.aws/lib/auth/getting-started/q/platform/js.

More than that, it can control access to Amazon resources such as Lambda, databases, and more. But that is a topic for another article.

1.2 NextJS
NextJS is just another open-source front-end web development framework for React. Its selling point is that it can render server-side and generate static websites, which is very good for SEO. What I love about NextJS is their easy-to-read documentation at https://nextjs.org/docs and examples officially available from their GitHub repository at https://github.com/vercel/next.js/tree/canary/examples. In a way, NextJS is like Angular Framework for React.

1.3 SSR Support for AWS Amplify
With SSR support, we can now access and verify a token from the request object using Amplify's library https://aws.amazon.com/blogs/mobile/ssr-support-for-aws-amplify-javascript-libraries.

# 2. Amazon Cognito Pool
If you haven't done so, register an account at AWS https://aws.amazon.com/console.

2.1 In the Service filter, enter Cognito. Click Manage User Pools.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/32kg244pdf25sudk6eug.png)

2.2 Click Create a user pool.

2.3 Enter a Pool name. Click Step through settings.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t8d0osudnq9ejv7qr9kn.png)

2.4 Select how you want your users to sign in. For this exercise, we will only allow the email address.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cavduyu804r4hfy5t0uj.png)

2.5 At the bottom of this screen, you can select which standard attributes you want to include in your users' profiles. We will use given_name and family_name. Note that we already have access to the email as a username. Click Next Step.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d9wwrhvmsdjzjz774u12.png)

2.6 On the next page, Configure the password strength. Click Next Step.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6ysevvsex8r9izddsvln.png)

2.7 For the following settings, leave everything to default and click Next Step.

- MFA and verifications
- Messages customizations
- Tags
- Devices

2.8 Under App clients, click Add an app client. Let's name the client Web Client.

- Uncheck Generate client secret.
- Check Enable username and password authentication.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xouneqfc1hvd2fdw7wlo.png)

Click Create Client.
# 3. Google Console Identity Provider
If you haven't done so, create a Google console account at https://console.cloud.google.com.

3.1 Create a new project. Click the arrow down button in the top left corner and New Project.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/94341q8ga24oc2zrt5ln.png)

3.2 Enter your project name.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sq24quxmzlco5q695ans.png)

Wait until the project is successfully created.

Before you continue, ensure the newly created project is selected in the screen's dropdown located at the top left corner.

*You can default create 25 projects under your Google console account.

3.3 Click the Navigation Menu / API & Services / Credentials.

3.4 Click Create Credentials / OAuth client ID.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x6vuag6e3jcpa8pus8e6.png)

3.5 Under Application type, select Web application.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5uib3ikl53pw4tb4s7l4.png)

3.6 Enter the name.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j418hn8temi0ufbi8o7y.png)

3.7 Enter the Authorized Javascript origins and Authorized redirect URIs.

You must get your Cognito domain name and replace the value accordingly: https://<cognitoDomainUrl>/oauth2/idresponse.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/spn0fjgh86uyidnz2679.png)

And hit save.

3.8 Once it saves, you must get and keep the Client ID and Secret on the right side of this page.

3.9 Once again, click the Navigation Menu / API & Services / and click the OAuth consent screen. This is where you will publish the app when it's ready for production. You should also add the email addresses of the users you will use for testing. Remember this as it's essential.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1r3agjr4k3ppl1wtu39o.png)

4. The NextJS App
The NextJS project is available at https://github.com/czetsuya/nextjs-auth-cognito, and the resources that we should look at are:

- useSession
- SessionContext
- WithLayout
- WithSession
- Secured
- secured

Part of the hook that authenticates a user:

```
const useSession = () => {
  const [stage, setStage] = useState(0)
  const [isLoading, setLoading] = useState(false)
  const [user, setUser] = useState(null) // cognito user
  const [isAuthenticated, setIsAuthenticated] = useState(!!user)
  const [error, setError] = useState(false)
 
  const refreshState = useCallback(() => {
 
    setStage(1)
    setLoading(true)
 
    Auth.currentAuthenticatedUser()
    .then(user => {
      setLoading(false)
      setStage(2)
      setUser(user)
      setIsAuthenticated(_isAuthenticated(user))
      setError(null)
    })
    .catch(err => {
      setLoading(false)
      setStage(3)
      logger.error("Error authenticating user", err)
      setIsAuthenticated(false)
      if (err === 'not authenticated') {
        setError(null)
 
      } else {
        setError(err)
      }
    })
 
    return () => {
      setStage(0)
      setLoading(false)
    }
  }, [])
  // ...
}
```