DEV Community

Cover image for Supercharge Your Authentication with Next-Auth in Next.js
rowjay007
rowjay007

Posted on

Supercharge Your Authentication with Next-Auth in Next.js

In the ever-evolving world of web development, Next.js has proven to be a game-changer, much like how TypeScript revolutionized JavaScript. One area where Next.js truly shines is in its approach to handling authentication. Managing user credentials, such as usernames, passwords, and email identities, can be a complex and critical aspect of web application development.

In this comprehensive tutorial, we will delve deep into Next-Auth, an open-source authentication library designed to fortify authentication systems, especially for web applications built with the Next.js framework. By the end of this tutorial, you'll have a robust client-side authentication system in place, complete with passwordless login capabilities, thanks to NextAuth.js. We'll also incorporate Shadcn CSS for styling and Toast notifications to enhance the user experience.

Prerequisites:

Before we dive in, make sure you meet the following prerequisites:

A basic understanding of JavaScript and React.

Node.js is installed on your local machine.

  • A GitHub account.
  • A Gmail account.

Now, let's embark on our journey to supercharge authentication with Next-Auth in Next.js.

What is Next.js?

Next.js is a JavaScript framework that has transformed the process of building modern web applications. It offers a powerful toolkit, including features like server-side rendering, client-side routing, automatic code splitting, static site generation, and serverless API routes. These capabilities simplify web application development, boost performance, and elevate the overall developer experience.

Next-Auth and Its Features:

Next-Auth.js seamlessly integrates with Next.js, making it a formidable choice for handling authentication in web applications. It is designed to work with multiple authentication providers, particularly those using OAuth services. OAuth enables passwordless sign-ins and facilitates integration with various databases.

Getting Started: Setting Up Your Next.js App

We'll kick things off by creating a Next.js application called "client-next-auth" using the following settings:

npx create-next-app@lates
Enter fullscreen mode Exit fullscreen mode

client-next-auth

Next, we'll add the Next-Auth library to our project:

npm install next-auth
# or
yarn add next-auth
Enter fullscreen mode Exit fullscreen mode

Additionally, we'll incorporate Shadcn for styling, toast run npm run dev to spin up our application running on http://localhost:3000

pm install shadcn
# or
yarn add shadcn
Enter fullscreen mode Exit fullscreen mode

nextjs

To ensure the security of our application, we'll set up environment variables. Create a .env.local file in the root folder of your app and populate it with the following code, replacing placeholders with your provider's secrets:

NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=d9Fsl6rZfeoVIzexy47HVy8QJiHcXgvkv3UI84v8FPI=
GITHUB_CLIENT_ID=<GITHUB_CLIENT_ID>
GITHUB_CLIENT_SECRET=<GITHUB_CLIENT_SECRET>
Enter fullscreen mode Exit fullscreen mode

You can generate a secure NEXTAUTH_SECRET by using OpenSSL:

openssl rand -base64 32
Enter fullscreen mode Exit fullscreen mode

github auth

Configuring GitHub OAuth Authentication:

Now, let's configure GitHub OAuth authentication. To obtain OAuth credentials from GitHub:

Navigate to your GitHub account's Developer settings.

Under "OAuth Apps," create a new OAuth App, providing the necessary app details and permissions.

Copy the highlighted Client ID into GITHUB_CLIENT_ID and generate a client secret to place in GITHUB_CLIENT_SECRET.

github provider

Creating the Authentication Handler:

Next, we'll create an authentication handler by adding a new file named api/auth/[...nextauth]/route.ts and populating it with the following code:

import NextAuth from "next-auth";
import type { NextAuthOptions } from "next-auth";
import GitHubProvider from "next-auth/providers/github";
export const authOptions: NextAuthOptions = {
  providers: [
    GitHubProvider({
      clientId: process.env.GITHUB_CLIENT_ID ?? "",
      clientSecret: process.env.GITHUB_CLIENT_SECRET ?? "",
    }),
  ],
};
export const handler = NextAuth(authOptions);
export { handler as GET, handler as POST };
Enter fullscreen mode Exit fullscreen mode

To test our authentication setup, visit http://localhost:3000/api/auth/providers

provider

Let's try signing up at http://localhost:3000/api/auth/signin. Your authentication should be up and running!

signin

Implementing Session Management:
To ensure proper session management, we'll create a SessionProvider.tsx component. This component will handle our session.

"use client";

import { SessionProvider } from "next-auth/react";
export default SessionProvider;

Enter fullscreen mode Exit fullscreen mode

Now, let's make changes to the layout.tsx file. This update will enable us to display the authenticated user's information.

 <html lang="en">
      <body
        className={`bg-gray-100 min-h-screen flex items-center justify-center ${inter.className}`}
      >
        <SessionProvider session={session}>
          <main className="max-w-screen-xl mx-auto p-4">
            <NavRoute />
            {children}
          </main>
          <Toaster />
        </SessionProvider>
      </body>
    </html>
Enter fullscreen mode Exit fullscreen mode

In your page.tsx file, you can use getServerSession to display the authenticated user's information:

import { getServerSession } from "next-auth/next";

export default async function Home() {
  const session = await getServerSession();

  return (
    <div className="flex flex-col justify-center items-center bg-gray-100">
      <div className="mt-8 p-8 bg-white rounded-lg shadow-md text-center">
        <p className="text-xl font-semibold mb-4">
          You are currently signed in as
        </p>
        <div className="text-2xl font-bold text-blue-500">
          {session?.user?.name ? session?.user?.name : "Not signed in"}
        </div>
      </div>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Creating a Navigation Route Component:
To handle user authentication status and navigation, we'll create a NavRoute.tsx component:

"use client";
import { usePathname } from "next/navigation";
import Link from "next/link";
import { signIn, signOut, useSession } from "next-auth/react";
import { useToast } from "@/components/ui/use-toast";

const activeRoute =
  "block px-4 py-2 text-blue-500 bg-blue-100 hover:bg-blue-200";
const inactiveRoute = "block px-4 py-2 text-gray-500 hover:text-gray-700";

function AuthSession() {
  const { toast } = useToast();
  const { data: session } = useSession();

  const handleSignOut = async () => {
    await signOut();
    toast({
      description: "You have been signed out.",
    });
  };

  const handleSignIn = async () => {
    await signIn();
    toast({
      description: "You have been signed in.",
    });
  };

  return (
    <div className="text-center">
      {session ? (
        <>
          <p className="text-xl font-semibold">
            Signed in as {session?.user?.name}
          </p>
          <button
            className="mt-2 px-4 py-2 bg-blue-500 text-white hover:bg-blue-600 rounded"
            onClick={handleSignOut}
          >
            Sign out
          </button>
        </>
      ) : (
        <>
          <p className="text-xl font-semibold">Not signed in</p>
          <button
            className="mt-2 px-4 py-2 bg-blue-500 text-white hover:bg-blue-600 rounded"
            onClick={handleSignIn}
          >
            Sign in
          </button>
        </>
      )}
    </div>
  );
}

export default function NavRoute() {
  const pathname = usePathname();
  return (
    <div className="bg-gray-100 p-4">
      <AuthSession />
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Creating a Protected Route Component:
To create a protected route, add a page.tsx file in the app folder with the following code:

import { getServerSession } from "next-auth";
import { redirect } from "next/navigation";

export default async function ProtectedPage() {
  const session = await getServerSession();
  if (!session || !session.user) {
    redirect("/api/auth/signin");
  }

  return (
    <div className=" flex items-center justify-center bg-gray-100">
      <div className="bg-white p-8 rounded shadow-md">
        <h1 className="text-3xl font-bold mb-4">Protected Page</h1>
        <p className="text-gray-700 mb-4">This is a protected page.</p>
        <p className="text-gray-700">You can see if you are authenticated.</p>
      </div>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Updating the Navigation Route Component:
Now, update the NavRoute.tsx component to account for the new protected route:

export default function NavRoute() {
  const pathname = usePathname();
  return (
    <div className="bg-gray-100 p-4">
      <AuthSession />
      <hr className="my-4" />
      <ul>
        <li>
          <Link
            href="/"
            className={pathname === "/" ? activeRoute : inactiveRoute}
          >
            Enter Protected Route
          </Link>
        </li>
        <li>
          <Link
            href="/protected"
            className={pathname === "/protected" ? activeRoute : inactiveRoute}
          >
            Inactive Protected Route
          </Link>
        </li>
      </ul>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

With these changes, we now have a new user-friendly interface that enhances the accessibility of our application, allowing users to seamlessly navigate between various routes on our pages.

Let's take a look at the updated landing page.

unprotected

This is the access page for authenticated users.

protected

Authenticated users now have access to the newly added protected route.

authenticated

Conclusion:

With Next-Auth, you've successfully implemented multiple OAuth authentication providers along with protected routes and middleware, ensuring the best security and accessibility for your web application.

Feel free to customize and expand upon this foundation to build robust and secure authentication systems for your Next.js projects.

I'd like to give credit to the following resources that provided valuable insights and assistance throughout this tutorial:

LogRocket Blog - How to Use NextAuth.js for Client-Side Authentication in Next.js

NextAuth.js Official Documentation

Shadcn CSS - Toast Component Documentation

YouTube Tutorial - NextAuth.js Introduction

Top comments (0)