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 };
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>;
}
// 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} />;
}
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;
},
},
};
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*"] };
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: [...] });
Build authenticated scraping dashboards? My Apify tools + NextAuth = secure data apps.
Custom auth + data solution? Email spinov001@gmail.com
Top comments (0)