Add Login, Protect Pages, and Implement Role-Based Access using NextAuth.js
Secure user authentication is essential for any real-world web app. In this module, you’ll learn how to:
- Set up NextAuth.js with Google/GitHub login
- Customize the sign-in UI
- Protect routes with middleware
- Add role-based UI (admin vs. user)
✅ Step 1: Install and Configure next-auth
npm install next-auth
🔹 Add API Route: src/app/api/auth/[...nextauth]/route.ts
// src/app/api/auth/[...nextauth]/route.ts
import NextAuth from "next-auth";
import GoogleProvider from "next-auth/providers/google";
const handler = NextAuth({
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID!,
clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
}),
],
callbacks: {
async session({ session, token }) {
session.user.id = token.sub; // Add user ID
session.user.role = token.email === 'admin@example.com' ? 'admin' : 'user'; // Basic role logic
return session;
},
},
});
export { handler as GET, handler as POST };
🔹 Add Environment Variables
In your .env.local
:
GOOGLE_CLIENT_ID=your_google_client_id
GOOGLE_CLIENT_SECRET=your_google_client_secret
NEXTAUTH_SECRET=some-long-random-string
NEXTAUTH_URL=http://localhost:3000
Use https://generate-secret.vercel.app/32 to generate your NEXTAUTH_SECRET
.
✅ Step 2: Setup Auth Provider
Wrap your app with SessionProvider
.
🔹 src/app/layout.tsx
import { SessionProvider } from "next-auth/react";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html>
<body>
<SessionProvider>{children}</SessionProvider>
</body>
</html>
);
}
✅ Step 3: Add Login / Logout Buttons
🔹 src/components/AuthButton.tsx
"use client";
import { signIn, signOut, useSession } from "next-auth/react";
export default function AuthButton() {
const { data: session } = useSession();
if (session?.user) {
return (
<div className="flex items-center gap-4">
<span>Welcome, {session.user.name}</span>
<button onClick={() => signOut()} className="text-red-600">Logout</button>
</div>
);
}
return <button onClick={() => signIn("google")} className="text-blue-600">Login with Google</button>;
}
✅ Step 4: Protect Routes with Middleware
🔹 middleware.ts
import { getToken } from "next-auth/jwt";
import { NextResponse } from "next/server";
export async function middleware(req: Request) {
const token = await getToken({ req, secret: process.env.NEXTAUTH_SECRET });
if (!token) {
return NextResponse.redirect(new URL("/login", req.url));
}
return NextResponse.next();
}
export const config = {
matcher: ["/dashboard/:path*"], // Protect dashboard routes
};
✅ Step 5: Add Custom Login Page (Optional)
Create src/app/login/page.tsx
:
"use client";
import { signIn } from "next-auth/react";
export default function LoginPage() {
return (
<div className="p-8 text-center">
<h1 className="text-2xl font-bold mb-4">Login Required</h1>
<button
onClick={() => signIn("google")}
className="bg-blue-600 text-white px-4 py-2 rounded"
>
Sign in with Google
</button>
</div>
);
}
✅ Step 6: Role-Based UI Rendering
In any page or component:
"use client";
import { useSession } from "next-auth/react";
export default function Dashboard() {
const { data: session } = useSession();
if (!session) return <p>Loading...</p>;
return (
<div className="p-6">
<h1 className="text-xl">Dashboard</h1>
{session.user.role === "admin" ? (
<p className="text-green-600">Admin Access</p>
) : (
<p>User Access</p>
)}
</div>
);
}
✅ Roles are customizable in the session callback!
✅ Summary
Feature | Tool / Example |
---|---|
Auth integration | next-auth |
OAuth login | Google/GitHub providers |
Protect pages | middleware.ts + matcher |
Session access | useSession() from next-auth/react |
Custom roles | Add role via session() callback |
🔜 Coming Up Next:
In Module 10, we’ll learn how to optimize performance, handle SEO, add environment variables, and deploy your app to Vercel with custom domains and CI/CD setup.
Would you like Module 9 converted to Markdown or HTML for your blog?