Implementing User Authentication in a Blog Application using AWS Amplify, NextJS, and Google Sign-In
Tags: aws, serverless, devops, nextjs
Published: 2023-05-25 03:47:43


In this tutorial, we will walk through the process of implementing user authentication in a blog application using **AWS Amplify**, **NextJS**, and **Google Sign-In**. Adding user authentication to your blog application allows users to authenticate themselves and edit their blogs securely. This feature enhances the user experience and adds an extra layer of security to your application.

---

## Prerequisites

Before getting started, make sure you have the following prerequisites:

- An [AWS account](https://docs.aws.amazon.com/accounts/latest/reference/manage-acct-creating.html)
- Basic knowledge of [NextJS and AWS Amplify](https://docs.amplify.aws/guides/hosting/nextjs/q/platform/js/)

If you haven't already done so, we recommend checking out our previous [**`blog post`**](https://dev.to/albac/managing-a-blog-with-aws-amplify-studio-1bgd) on adding a **`post data model with Amplify`**.

Additionally, we suggest following the [**`hosting blog`**](https://dev.to/albac/host-a-nextjs-blog-with-aws-amplify-and-setup-automated-deployments-6nl) before adding authentication, as it provides instructions that will be helpful in this blog.

---

## Step 1: Set up Google Console OAuth

Before adding social authentication to our app, we need to configure Google OAuth. Follow these steps:

**1.** Go to the [Google Cloud Console](https://console.cloud.google.com/) and create a new project.

**2.** Set up the OAuth consent screen by selecting **API & Services** in the left menu, then **Oauth Consent screen**. Choose **External** as the **User Type**, enter an **App Name**, and optionally upload a logo.

![Google Consent Screen](https://raw.githubusercontent.com/albac/albac.dev/v1.3/images/google_consent_screen.png)


![Google OAuth Consent](https://raw.githubusercontent.com/albac/albac.dev/v1.3/images//gc_oauth_consent_screen.png)


![Google Consent Summary](https://raw.githubusercontent.com/albac/albac.dev/v1.3/images/gc_summary.png)

**3.** After completing the consent screen, go to **credentials** under **API & Services** and create an OAuth Client ID. Choose **Web Application** as the application type and enter a name to identify your client. Leave the **Authorized JavaScript origins** and **Authorized redirect URIs** blank for now.

![Google Console Creds](https://raw.githubusercontent.com/albac/albac.dev/v1.3/images/google_console_creds.png)

**4.** Take note of the **`Google Web Client ID`** and **`Google Client Secret`** generated for your OAuth flow.

---

## Step 2: Set up AWS Amplify Authentication

Now, let's set up AWS Amplify Authentication and configure Google Sign-In as a social provider. Follow these steps:

**1.** Ensure you have Amplify set up and a GraphQL API created. You can check the status by running `amplify status` in your terminal. You can also follow our past tutorial where we initiate and [`host an amplify project`](https://albac.dev/blog/749a8e63-dc41-4dde-afac-0af2fe912287).

```bash
    Current Environment: dev

┌──────────┬──────────────────────┬───────────┬───────────────────┐
│ Category │ Resource name        │ Operation │ Provider plugin   │
├──────────┼──────────────────────┼───────────┼───────────────────┤
│ Hosting  │ amplifyhosting       │ Create    │                   │
├──────────┼──────────────────────┼───────────┼───────────────────┤
│ Api      │ albacdev             │ No Change │ awscloudformation │
└──────────┴──────────────────────┴───────────┴───────────────────┘
```

**2.** Add a new Amplify Authentication and **`Google Sign-In`** as a social provider by running the following command in your terminal:
   ```bash
   $ amplify add auth
   ```
   Choose **Default configuration with Social Provider (Federation)** when ask for the default authentication and security configuration. Select **Email** as the sign-in option and configure advanced settings as needed. Enter your chosen domain name prefix, redirect sign-in and sign-out URIs (e.g., `http://localhost:3000`), and choose Google as the social provider.

```bash

$ amplify add auth
Using service: Cognito, provided by: awscloudformation

  The current configured provider is Amazon Cognito

  Do you want to use the default authentication and security configuration? Default configuration with Social Provider (Federation)
  Warning: you will not be able to edit these selections.
  How do you want users to be able to sign in? Email
  Do you want to configure advanced settings? No, I am done
  What domain prefix do you want to use?
  Enter your redirect signin URI: http://localhost:3000/
 ? Do you want to add another redirect signin URI No
  Enter your redirect signout URI: http://localhost:3000/
 ? Do you want to add another redirect signout URI No
  Select the social providers you want to configure for your user pool: Google

  You've opted to allow users to authenticate via Google. If you haven't already, you will need to go to https://developers.google.com/identity and create an App ID.

  Enter your Google Web Client ID for your OAuth flow: XXXXXXXXXXXXXXX
  Enter your Google Web Client Secret for your OAuth flow: XXXXXXXXXXXXXXXXXXXXXXXXX
 
```


**3.** Provide your **`Google Web Client ID`** and **`Google Client Secret`** when prompted.

Once the setup is complete, Amplify will add the necessary auth resources locally.

![Amplify OAuth Success](https://raw.githubusercontent.com/albac/albac.dev/v1.3/images/amplify_success_oauth.png)

Take a note of the **Hosted UI Endpoint** and go back to Google Console OAuth Credentials, type it into your user pool domain into **Authorized Javascript** origins and with the /oauth2/idpresponse endpoint into **Authorized Redirect URIs**. 

## Step 2: Set Up Groups and Permissions

To control access to our application, we need to set up groups and permissions. This can be done using the **`AWS CLI or Amplify Studio`**. Here's an example of how to do it using the CLI:

**1.** Add groups using the following command:
   ```bash
   amplify auth add-group
   ```
**2.** Add permissions using the following command:
   ```bash
   amplify auth add-permission
   ```

You can also set up groups and permissions using Amplify Studio, which provides a visual interface for managing authorization rules.

![Studio Admin Queries](https://raw.githubusercontent.com/albac/albac.dev/v1.3/images/admin_queries_studio.png)

---

## Step 3: Modify Your NextJS Code

Now that we have set up the authentication provider, social provider, groups, and permissions, we need to modify our NextJS code to handle the sign-in and sign-out workflow and display a list of blogs that the user can edit.

**1.** Load the authentication setup by calling `Amplify.configure` and loading the `aws_exports` configuration in the [`_app.js`](https://github.com/albac/albac.dev/blob/v1.3/pages/_app.tsx#L22-L28) file.

   ```javascript
   Amplify.configure({
     ...awsconfig,
     ssr: true,
     DataStore: {
       authModeStrategyType: AuthModeStrategyType.MULTI_AUTH,
     },
   });
   ```
   This enables server-side rendering (SSR) and the  [`MULTI_AUTH`](https://docs.amplify.aws/lib/datastore/setup-auth-rules/q/platform/js/#configure-multiple-authorization-types) strategy for our data store, allowing us to have permissions for both Cognito groups and social provider groups.

**2.** Add the `Authenticator.Provider` to your [`_app.js`](https://github.com/albac/albac.dev/blob/v1.3/pages/_app.tsx#L37-L39) file:
   
```javascript
   <Authenticator.Provider>
       <Component {...pageProps} />
   </Authenticator.Provider>
   ```
   This sets up the authentication provider for your application.

**3.** Use the [`useAuthenticator`](https://ui.docs.amplify.aws/react/connected-components/authenticator/advanced#useauthenticator-hook)  hook in your [`NavBar-Menu`](https://github.com/albac/albac.dev/blob/v1.3/components/DesktopMenu.js#L14) component to check if the user is authenticated. Show the SignOut button if the user is authenticated against Cognito or the Google provider; otherwise, show the SignIn button to allow users to authenticate.
```javascript
const { user } = useAuthenticator((context) => [context.user]);
...
...
 {user ? <SignOutButton username={user.username} /> : <SignInButton />}
...
```

**4.** Create the necessary routes and components for the sign-in and sign-out functionality.

On the [`SignIn button`](https://github.com/albac/albac.dev/blob/v1.3/pages/signin.js) we only use next/link to redirect the request to the /signin page:

```
<Link className="text-white" href="/signin">
```

On the [`SignIn page`](https://github.com/albac/albac.dev/blob/v1.3/pages/signin.js) we are using the [`Authenticator component`](https://ui.docs.amplify.aws/react/connected-components/authenticator), customized with our Logo and use **`ThemeProvider`** to enable dark mode:

```javascript
...
import {
  Authenticator,
  defaultDarkModeOverride,
  ThemeProvider,
  useTheme,
  View,
} from "@aws-amplify/ui-react";
...
...
 const theme = {
    name: "my-theme",
    overrides: [defaultDarkModeOverride],
    tokens: {
      components: {
        textareafield: {
          rows: { value: "{20}" },
          size: { value: "large" },
          resize: { value: "vertical" },
        },
      },
    },
  };

  const components = {
    Header() {
      const { tokens } = useTheme();

      return (
        <div className="mx-32">
        <View textAlign="center" padding={tokens.space.large}>
          <ImageS3 alt="Amplify logo" src="albac_logo" />
        </View>
        </div>
      );
    },
  };
...
...
          <Authenticator components={components}>
            <>{errorMessage && <p>Error: {errorMessage}</p>}</>
            <ThemeProvider theme={theme} colorMode="system" />
          </Authenticator>
...

```

**5.** Protect restricted routes from non-authenticated users. Wrap the components that require authentication with the `Authenticator` component.

On the [`blog-edit page`](https://github.com/albac/albac.dev/blob/v1.3/pages/blog-edit/%5Bid%5D.js#L71-L83), we do the same to protect from non-authenticated users.

```javascript
          <Authenticator components={components}>
            <>{errorMessage && <p>Error: {errorMessage}</p>}</>
            <ThemeProvider theme={theme} colorMode="system">
              <NewPostsUpdateForm
                mode="Dark"
                id={id}
                onSuccess={() => router.push("/blog/" + id)}
                onError={(error) => {
                  setErrorMessage(error);
                }}
              />
            </ThemeProvider>
          </Authenticator>
```

After this is setup you should be able to see the login page from Amplify ui component and able using cognito.

![Amplify Cognito](https://raw.githubusercontent.com/albac/albac.dev/v1.3/images/amplify_google_login.png)

By following these steps, you should be able to implement user authentication in your NextJS blog application using AWS Amplify, NextJS, and Google Sign-In.

---

## Conclusion

In this tutorial, we have learned how to implement user authentication in a blog application using the powerful combination of AWS Amplify, NextJS, and Google Sign-In. By following the step-by-step guide, you can enhance your blog application and provide a secure environment for users to manage their blogs.

User authentication is an essential feature for web applications, and with AWS Amplify, the process becomes seamless and efficient. By integrating Google Sign-In as a social provider, you allow users to authenticate themselves easily while maintaining a high level of security.

By implementing user authentication, you can ensure that only authorized users can access and edit their blogs, enhancing the overall user experience and adding an extra layer of security to your application. Additionally, with the flexibility and scalability of AWS Amplify, you can easily adapt and expand your authentication system as your application grows.

---

### Reference

* [**Amplify Official Documentation for Authentication**](https://docs.amplify.aws/lib/auth/social/q/platform/js/#configure-auth-category)
* [**Amplify Authorization Types Documentation**](https://docs.amplify.aws/lib/datastore/setup-auth-rules/q/platform/js/#configure-multiple-authorization-types)
* [**Amplify Official documentation for the Authenticator component**](https://ui.docs.amplify.aws/react/connected-components/authenticator)
* [**New UseAuthenticator Hook**](https://ui.docs.amplify.aws/react/connected-components/authenticator/advanced#useauthenticator-hook)
* [**This blog used AuthStatus on UseAuthenticator hook together with user property**](https://www.xiegerts.com/post/amplify-ui-auth-nextjs/)


---