1. YouTube Summaries
  2. Implementing AWS Cognito Authentication in Next.js

Implementing AWS Cognito Authentication in Next.js

By scribe 4 minute read

Create articles from any YouTube video or use our API to get YouTube transcriptions

Start for free
or, create a free article to see how easy it is.

Introduction to AWS Cognito Authentication in Next.js

AWS Cognito is a powerful authentication and authorization service that can be seamlessly integrated with Next.js applications. This guide will walk you through the process of implementing Cognito authentication in a Next.js project, from initial setup to advanced features.

Setting Up AWS Cognito

To begin, you'll need to set up a Cognito User Pool in the AWS Console:

  1. Navigate to the Amazon Cognito service in the AWS Console
  2. Click "Create user pool"
  3. Choose "Email" as the sign-in option
  4. Configure password policies and MFA settings as needed
  5. Enable self-registration and email verification
  6. Select "Send email with Cognito" for message delivery (switch to Amazon SES for production)
  7. Name your user pool (e.g., "nextjs-tutorial")
  8. Create an app client without a client secret
  9. Ensure "Allow user SRP auth for Cognito" is selected in Advanced settings

Configuring Amplify in Next.js

Install the necessary packages:

npm install aws-amplify @aws-amplify/adapter-nextjs

Create a configuration file src/app/amplify-cognito-config.ts:

import { Amplify } from 'aws-amplify';
import { type ResourcesConfig } from 'aws-amplify';

const config: ResourcesConfig = {
  Auth: {
    Cognito: {
      userPoolId: process.env.NEXT_PUBLIC_USER_POOL_ID!,
      userPoolClientId: process.env.NEXT_PUBLIC_USER_POOL_CLIENT_ID!,
    },
  },
};

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

export default function configureAmplifyClientSide() {
  return null;
}

Update your root layout to include the Amplify configuration:

import ConfigureAmplifyClientSide from '@/app/amplify-cognito-config';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <ConfigureAmplifyClientSide />
        {children}
      </body>
    </html>
  );
}

Create a server-side utility src/utils/amplify-server.ts:

import { createServerRunner } from '@aws-amplify/adapter-nextjs';
import config from '@/app/amplify-cognito-config';

export const { runWithAmplifyServerContext } = createServerRunner(config);

Implementing Sign Up, Sign In, and Sign Out

Create authentication forms for sign up, sign in, and sign out. Here's an example of a sign-up form:

import { useFormState } from 'react-dom';
import { handleSignUp } from '@/lib/cognito-actions';

export function SignUpForm() {
  const [state, formAction] = useFormState(handleSignUp, null);

  return (
    <form action={formAction}>
      <input type="email" name="email" required />
      <input type="text" name="name" required />
      <input type="password" name="password" required />
      <button type="submit">Create Account</button>
      {state?.error && <p>{state.error}</p>}
    </form>
  );
}

Implement the corresponding Cognito actions in lib/cognito-actions.ts:

import { signUp, confirmSignUp, signIn, signOut } from 'aws-amplify/auth';

export async function handleSignUp(prevState: any, formData: FormData) {
  const email = formData.get('email') as string;
  const password = formData.get('password') as string;
  const name = formData.get('name') as string;

  try {
    await signUp({
      username: email,
      password,
      attributes: { email, name },
      autoSignIn: { enabled: true },
    });
    return { redirect: '/auth/confirm-signup' };
  } catch (error) {
    return { error: getErrorMessage(error) };
  }
}

// Implement similar functions for confirmSignUp, signIn, and signOut

Adding Authorization with Middleware

Create a middleware file src/middleware.ts to protect routes:

import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import { authenticatedUser } from '@/utils/amplify-server';

export async function middleware(request: NextRequest) {
  const response = NextResponse.next();
  const user = await authenticatedUser({ request, response });

  const isOnDashboard = request.nextUrl.pathname.startsWith('/dashboard');
  const isInAdminArea = request.nextUrl.pathname.startsWith('/dashboard/admin');

  if (isOnDashboard && !user) {
    return NextResponse.redirect(new URL('/auth/login', request.url));
  }

  if (isInAdminArea && !user?.isAdmin) {
    return NextResponse.redirect(new URL('/dashboard', request.url));
  }

  return response;
}

export const config = {
  matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'],
};

Managing User Profiles

Implement functions to update user attributes, email, and password:

import { updateUserAttribute, updatePassword } from 'aws-amplify/auth';

export async function handleUpdateUserAttribute(prevState: any, formData: FormData) {
  const name = formData.get('name') as string;
  const email = formData.get('email') as string;

  try {
    await updateUserAttribute({
      userAttribute: {
        attributeKey: email ? 'email' : 'name',
        value: email || name,
      },
    });
    return { success: true };
  } catch (error) {
    return { error: getErrorMessage(error) };
  }
}

export async function handleUpdatePassword(prevState: any, formData: FormData) {
  const oldPassword = formData.get('currentPassword') as string;
  const newPassword = formData.get('newPassword') as string;

  try {
    await updatePassword({ oldPassword, newPassword });
    return { success: true };
  } catch (error) {
    return { error: getErrorMessage(error) };
  }
}

Implementing Password Reset

Add functionality for users to reset forgotten passwords:

import { resetPassword, confirmResetPassword } from 'aws-amplify/auth';

export async function handleResetPassword(prevState: any, formData: FormData) {
  const email = formData.get('email') as string;

  try {
    await resetPassword({ username: email });
    return { redirect: '/auth/reset-password/confirm' };
  } catch (error) {
    return { error: getErrorMessage(error) };
  }
}

export async function handleConfirmResetPassword(prevState: any, formData: FormData) {
  const email = formData.get('email') as string;
  const newPassword = formData.get('newPassword') as string;
  const confirmationCode = formData.get('confirmationCode') as string;

  try {
    await confirmResetPassword({ username: email, newPassword, confirmationCode });
    return { redirect: '/auth/login' };
  } catch (error) {
    return { error: getErrorMessage(error) };
  }
}

Conclusion

Implementing AWS Cognito authentication in a Next.js application provides a robust and scalable solution for user management. This guide covered the essential steps to set up Cognito, integrate it with Next.js using the Amplify library, and implement key features such as sign-up, sign-in, authorization, profile management, and password reset.

By following these steps, you can create a secure and user-friendly authentication system for your Next.js application. Remember to consult the AWS Amplify documentation for more advanced features and best practices in production environments.

As you continue to develop your application, consider implementing additional security measures, such as multi-factor authentication, and explore Cognito's integration with other AWS services to enhance your application's capabilities.

Article created from: https://youtu.be/wiWDOgIu7cU

Ready to automate your
LinkedIn, Twitter and blog posts with AI?

Start for free