Auth completa con Auth.js en Next.js
Antes de empezar
Sección titulada «Antes de empezar»Esta receta ensambla Auth.js v5 con App Router. Requiere un cliente Prisma exportado desde src/lib/prisma.ts, usuarios con email, passwordHash y name, y el alias @/* hacia src/*. Guarda la configuración en src/auth.ts y las rutas bajo src/app. El registro y la recuperación de cuenta se implementan aparte. Define AUTH_SECRET y, para GitHub, AUTH_GITHUB_ID y AUTH_GITHUB_SECRET en el servidor.
Preparación
Sección titulada «Preparación»pnpm add next-auth@betapnpm add bcryptpnpm add -D @types/bcryptbun add next-auth@betabun add bcryptbun add -d @types/bcryptnpm install next-auth@betanpm install bcryptnpm install -D @types/bcryptimport bcrypt from "bcrypt"import NextAuth from "next-auth"import Credentials from "next-auth/providers/credentials"import GitHub from "next-auth/providers/github"import { prisma } from "@/lib/prisma"
export const { handlers, auth, signIn, signOut } = NextAuth({ providers: [ GitHub, Credentials({ credentials: { email: {}, password: {} }, authorize: async (credentials) => { if (typeof credentials.email !== "string" || typeof credentials.password !== "string") return null const usuario = await prisma.user.findUnique({ where: { email: credentials.email as string } }) if (!usuario?.passwordHash) return null
const valido = await bcrypt.compare( credentials.password as string, usuario.passwordHash ) return valido ? { id: usuario.id, email: usuario.email, name: usuario.name } : null } }) ]})Route Handler
Sección titulada «Route Handler»import { handlers } from "@/auth"
export const { GET, POST } = handlersproxy.ts
Sección titulada «proxy.ts»import { NextResponse } from "next/server"import { auth } from "@/auth"
export default auth(request => { if (!request.auth?.user) return NextResponse.redirect(new URL("/login", request.url))})
export const config = { matcher: ["/dashboard/:path*"]}Formulario de login (Server Action)
Sección titulada «Formulario de login (Server Action)»import { signIn } from "@/auth"
export default function LoginPage() { return ( <form action={async (formData) => { "use server" await signIn("credentials", { email: formData.get("email"), password: formData.get("password"), redirectTo: "/dashboard" }) }} > <input aria-label="Email" name="email" type="email" required /> <input aria-label="Contraseña" name="password" type="password" required /> <button type="submit">Entrar</button> </form> )}Página protegida
Sección titulada «Página protegida»import { auth } from "@/auth"import { redirect } from "next/navigation"
export default async function DashboardPage() { const session = await auth() if (!session?.user) redirect("/login") return <h1>Hola, {session.user.name}</h1>}Consideraciones
Sección titulada «Consideraciones»El proxy facilita la navegación, pero las páginas, Server Actions y APIs deben comprobar la sesión al acceder a datos. El login del ejemplo muestra el flujo de éxito: captura AuthError para presentar credenciales incorrectas y vuelve a lanzar los errores de redirección de Next.js. Ver manejo de sesión.
Cerrar sesión
Sección titulada «Cerrar sesión»import { signOut } from "@/auth"
export function LogoutButton() { return <form action={async () => { "use server" await signOut({ redirectTo: "/login" }) }}><button type="submit">Cerrar sesión</button></form>}Comprobación
Sección titulada «Comprobación»Visita /dashboard sin sesión, inicia sesión con un usuario de prueba y vuelve a visitarlo. Debe mostrar su nombre. Cierra sesión y recarga: debe volver a /login. Comprueba también contraseña incorrecta y acceso directo a APIs. No basta con ocultar botones en el navegador.
Fuentes
Sección titulada «Fuentes»-
Cada pieza está documentada a fondo en Auth.js en Next.js — aquí solo el ensamblado end-to-end.
-
El provider
Credentialssigue necesitando bcrypt a mano dentro deauthorize— Auth.js no reemplaza esa parte del flujo, solo el manejo de sesión alrededor.