DEV Community

Alex Spinov
Alex Spinov

Posted on

NextAuth.js Has a Free API That Adds Authentication to Any Next.js App in Minutes

NextAuth.js (now Auth.js) is the standard authentication library for Next.js. Its API handles OAuth, credentials, sessions, and JWTs with minimal configuration.

Setup: One File, Full Auth

// app/api/auth/[...nextauth]/route.ts
import NextAuth from "next-auth";
import Google from "next-auth/providers/google";
import GitHub from "next-auth/providers/github";
import Credentials from "next-auth/providers/credentials";

const handler = NextAuth({
  providers: [
    Google({ clientId: process.env.GOOGLE_ID!, clientSecret: process.env.GOOGLE_SECRET! }),
    GitHub({ clientId: process.env.GITHUB_ID!, clientSecret: process.env.GITHUB_SECRET! }),
    Credentials({
      credentials: {
        email: { label: "Email", type: "email" },
        password: { label: "Password", type: "password" },
      },
      async authorize(credentials) {
        const user = await db.user.findUnique({ where: { email: credentials.email } });
        if (user && await verify(credentials.password, user.password)) return user;
        return null;
      },
    }),
  ],
});

export { handler as GET, handler as POST };
Enter fullscreen mode Exit fullscreen mode

Session API: Client + Server

// Client component
"use client";
import { useSession, signIn, signOut } from "next-auth/react";

function AuthButton() {
  const { data: session, status } = useSession();

  if (status === "loading") return <Spinner />;
  if (session) {
    return (
      <div>
        <img src={session.user.image} alt={session.user.name} />
        <span>{session.user.name}</span>
        <button onClick={() => signOut()}>Sign Out</button>
      </div>
    );
  }
  return <button onClick={() => signIn()}>Sign In</button>;
}
Enter fullscreen mode Exit fullscreen mode
// Server component / API route
import { getServerSession } from "next-auth";
import { authOptions } from "./auth";

async function ServerComponent() {
  const session = await getServerSession(authOptions);
  if (!session) redirect("/login");
  return <Dashboard user={session.user} />;
}
Enter fullscreen mode Exit fullscreen mode

Callbacks: Customize the Flow

const authOptions = {
  callbacks: {
    async signIn({ user, account, profile }) {
      // Block non-verified emails
      if (!profile?.email_verified) return false;
      // Allow only specific domains
      if (!user.email?.endsWith("@company.com")) return false;
      return true;
    },
    async jwt({ token, user, account }) {
      if (user) {
        token.role = user.role;
        token.teamId = user.teamId;
      }
      if (account) {
        token.accessToken = account.access_token;
      }
      return token;
    },
    async session({ session, token }) {
      session.user.role = token.role;
      session.user.teamId = token.teamId;
      session.accessToken = token.accessToken;
      return session;
    },
  },
};
Enter fullscreen mode Exit fullscreen mode

Middleware: Protect Routes

// middleware.ts
import { withAuth } from "next-auth/middleware";

export default withAuth({
  callbacks: {
    authorized: ({ token, req }) => {
      if (req.nextUrl.pathname.startsWith("/admin")) {
        return token?.role === "admin";
      }
      return !!token;
    },
  },
});

export const config = { matcher: ["/dashboard/:path*", "/admin/:path*"] };
Enter fullscreen mode Exit fullscreen mode

Database Adapters

import { PrismaAdapter } from "@auth/prisma-adapter";
import { DrizzleAdapter } from "@auth/drizzle-adapter";

// Prisma
NextAuth({ adapter: PrismaAdapter(prisma), providers: [...] });

// Drizzle
NextAuth({ adapter: DrizzleAdapter(db), providers: [...] });
Enter fullscreen mode Exit fullscreen mode

Build authenticated scraping dashboards? My Apify tools + NextAuth = secure data apps.

Custom auth + data solution? Email spinov001@gmail.com

Top comments (0)