Esta guía documenta paso a paso cómo implementar autenticación con NextAuth, Prisma y credenciales en un proyecto Next.js con App Router (como "La Huanca").
npm install next-auth @auth/prisma-adapter @prisma/client bcryptjs
prisma/schema.prisma
model User {
id String @id @default(cuid())
name String?
email String @unique
emailVerified DateTime?
password String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
npx prisma migrate dev
npx prisma studio
Inserta un usuario con contraseña hasheada con bcryptjs.
src/auth.ts
import { PrismaAdapter } from "@auth/prisma-adapter";
import { prisma } from "@/lib/prisma";
import CredentialsProvider from "next-auth/providers/credentials";
import { compare } from "bcryptjs";
import type { NextAuthOptions } from "next-auth";
export const authOptions: NextAuthOptions = {
adapter: PrismaAdapter(prisma),
providers: [
CredentialsProvider({
name: "Credentials",
credentials: {
email: { label: "Correo", type: "text" },
password: { label: "Contraseña", type: "password" },
},
async authorize(credentials) {
const user = await prisma.user.findUnique({ where: { email: credentials?.email } });
if (!user) return null;
const isValid = await compare(credentials!.password, user.password);
if (!isValid) return null;
return { id: user.id, name: user.name, email: user.email };
},
}),
],
pages: { signIn: "/auth/login" },
session: { strategy: "jwt" },
secret: process.env.NEXTAUTH_SECRET,
};
app/api/auth/[...nextauth]/route.ts
import NextAuth from "next-auth";
import { authOptions } from "@/auth";
const handler = NextAuth(authOptions);
export { handler as GET, handler as POST };
components/auths/auth-provider.tsx
"use client";
import { SessionProvider } from "next-auth/react";
export function AuthProvider({ children }) {
return <SessionProvider>{children}</SessionProvider>;
}
components/auths/public-route.tsx
"use client";
import { useSession } from "next-auth/react";
import { useRouter } from "next/navigation";
import { useEffect } from "react";
export const PublicRoute = ({ children }) => {
const { status } = useSession();
const router = useRouter();
useEffect(() => {
if (status === "authenticated") {
router.push("/");
}
}, [status]);
return status === "loading" ? <p>Cargando...</p> : <>{children}</>;
};
app/auth/login/page.tsx
import { Login } from "@/components";
import { PublicRoute } from "@/components/auths/public-route";
export default function LoginPage() {
return (
<PublicRoute>
<Login />
</PublicRoute>
);
}
middleware.ts
import { withAuth } from "next-auth/middleware";
export default withAuth({
pages: {
signIn: "/auth/login",
},
});
export const config = {
matcher: ["/dashboard/:path*", "/admin/:path*"],
};
.env.local
NEXTAUTH_SECRET=clave-generada
NEXTAUTH_URL=http://localhost:3000
DATABASE_URL=postgresql://usuario:contraseña@localhost:5432/nombre
¡Listo! Ya tienes login funcional con NextAuth y credenciales para usar en cualquier proyecto Next.js moderno.