Autenticacion en Next.js con Auth.js v5: Guia Completa
Implementa autenticacion en tu app Next.js con Auth.js v5 (NextAuth). OAuth con Google y GitHub, sesiones, middleware para proteger rutas, y roles de usuario paso a paso.
Autenticacion en Next.js con Auth.js v5: Guia Completa
La autenticacion en Next.js con Auth.js v5 es el estandar actual para implementar login en aplicaciones con App Router. Auth.js (antes NextAuth.js) maneja OAuth con proveedores como Google y GitHub, sesiones con JWT o base de datos, middleware para proteger rutas, y callbacks para personalizar el flujo completo. Todo esto sin depender de un servicio de pago.
Esta guia cubre la implementacion completa: desde instalar el paquete hasta proteger rutas con roles de usuario. Codigo funcional, sin atajos.
Que es Auth.js v5 y por que importa
Auth.js v5 es la version actual de lo que antes conocias como NextAuth.js. El renombramiento refleja que la libreria ya no es exclusiva de Next.js -- soporta SvelteKit, SolidStart y otros frameworks. Pero para el ecosistema de Next.js, sigue siendo la solucion de autenticacion open-source por defecto.
Las diferencias principales con NextAuth v4:
- Disenado para App Router: funciona nativamente con Server Components, Server Actions y middleware
- Configuracion centralizada: un solo archivo
auth.tsen la raiz del proyecto - Edge compatible: el middleware corre en el edge runtime sin problemas
- API simplificada: menos boilerplate, mas convencion
Si ya usaste NextAuth v4, el salto a v5 cambia la estructura del proyecto pero los conceptos son los mismos.
Instalacion y configuracion inicial
Empecemos instalando Auth.js en un proyecto Next.js existente con App Router.
$ Version correcta
El paquete sigue llamandose next-auth en npm, pero a partir de la version 5 es oficialmente Auth.js. Asegurate de instalar next-auth@5 y no la version 4.
Crear el archivo de configuracion
El corazon de Auth.js v5 es un archivo auth.ts en la raiz del proyecto. Aqui defines proveedores, callbacks y opciones de sesion:
// auth.ts
import NextAuth from 'next-auth'
import Google from 'next-auth/providers/google'
import GitHub from 'next-auth/providers/github'
export const { handlers, signIn, signOut, auth } = NextAuth({
providers: [
Google,
GitHub,
],
})Eso es todo para una configuracion basica. Auth.js lee automaticamente las variables de entorno AUTH_GOOGLE_ID, AUTH_GOOGLE_SECRET, AUTH_GITHUB_ID y AUTH_GITHUB_SECRET.
Variables de entorno
Agrega estas variables a tu archivo .env.local:
# .env.local
# Secret para firmar tokens (genera uno con: npx auth secret)
AUTH_SECRET=tu_secret_generado_aqui
# Google OAuth
AUTH_GOOGLE_ID=tu_google_client_id
AUTH_GOOGLE_SECRET=tu_google_client_secret
# GitHub OAuth
AUTH_GITHUB_ID=tu_github_client_id
AUTH_GITHUB_SECRET=tu_github_client_secret$ Ese comando genera un AUTH_SECRET aleatorio y lo agrega a tu .env.local automaticamente. Si necesitas una guia mas detallada sobre como manejar variables de entorno en tu proyecto, revisa la guia de variables de entorno en Next.js y Vercel.
Configurar proveedores OAuth
Obtener credenciales de Google
Para configurar Google como proveedor de login, necesitas crear un proyecto en Google Cloud Console:
- Ve a Google Cloud Console
- Crea un proyecto nuevo o selecciona uno existente
- Ve a APIs & Services > Credentials
- Click en Create Credentials > OAuth client ID
- Selecciona Web application como tipo
- En Authorized redirect URIs agrega:
http://localhost:3000/api/auth/callback/google - Copia el Client ID y Client Secret a tu
.env.local
URI de redireccion en produccion
Cuando hagas deploy, necesitas agregar tambien la URI de produccion: https://tudominio.com/api/auth/callback/google. Si no la agregas, el login con Google va a fallar en produccion con un error de redirect_uri mismatch.
Obtener credenciales de GitHub
La configuracion de GitHub es mas directa:
- Ve a GitHub Developer Settings
- Click en New OAuth App
- Homepage URL:
http://localhost:3000 - Authorization callback URL:
http://localhost:3000/api/auth/callback/github - Click en Register application
- Copia el Client ID y genera un Client Secret
Para produccion, crea una OAuth App separada con la URL de tu dominio real.
Route Handler
Auth.js necesita un Route Handler que maneje todas las rutas de autenticacion (/api/auth/*). Crealo con esta estructura:
app/
└── api/
└── auth/
└── [...nextauth]/
└── route.ts
// app/api/auth/[...nextauth]/route.ts
import { handlers } from '@/auth'
export const { GET, POST } = handlersDos lineas. El objeto handlers que exportaste desde auth.ts contiene toda la logica para sign in, sign out, callbacks y sesiones. El catch-all route ([...nextauth]) captura todas las rutas bajo /api/auth/.
Componentes de Sign In y Sign Out
Boton de Sign In (Server Component)
Auth.js v5 te permite usar Server Actions directamente para el login:
// components/sign-in.tsx
import { signIn } from '@/auth'
export function SignIn() {
return (
<div>
<form
action={async () => {
'use server'
await signIn('google')
}}
>
<button type="submit">Iniciar sesion con Google</button>
</form>
<form
action={async () => {
'use server'
await signIn('github')
}}
>
<button type="submit">Iniciar sesion con GitHub</button>
</form>
</div>
)
}Boton de Sign Out (Server Component)
// components/sign-out.tsx
import { signOut } from '@/auth'
export function SignOut() {
return (
<form
action={async () => {
'use server'
await signOut()
}}
>
<button type="submit">Cerrar sesion</button>
</form>
)
}Boton de Sign In (Client Component)
Si necesitas un boton con interactividad del lado del cliente (por ejemplo, mostrar un loading state):
// components/sign-in-button.tsx
'use client'
import { signIn } from 'next-auth/react'
import { useState } from 'react'
export function SignInButton() {
const [cargando, setCargando] = useState(false)
async function handleSignIn(proveedor: string) {
setCargando(true)
await signIn(proveedor, { callbackUrl: '/dashboard' })
}
return (
<div>
<button
onClick={() => handleSignIn('google')}
disabled={cargando}
>
{cargando ? 'Redirigiendo...' : 'Google'}
</button>
<button
onClick={() => handleSignIn('github')}
disabled={cargando}
>
{cargando ? 'Redirigiendo...' : 'GitHub'}
</button>
</div>
)
}Server vs Client
Nota la diferencia de imports: en Server Components importas signIn desde @/auth, en Client Components desde next-auth/react. Cada uno tiene su propio mecanismo. Si esta distincion te genera dudas, la guia de Server Components vs Client Components lo explica a fondo.
Obtener la sesion del usuario
Este es el punto mas importante de toda la configuracion. Necesitas acceder a la sesion en tres contextos diferentes: Server Components, Client Components y middleware.
En Server Components: auth()
// app/dashboard/page.tsx
import { auth } from '@/auth'
import { redirect } from 'next/navigation'
import { SignOut } from '@/components/sign-out'
export default async function DashboardPage() {
const sesion = await auth()
// Si no hay sesion, redirigir al login
if (!sesion?.user) {
redirect('/api/auth/signin')
}
return (
<div>
<h1>Dashboard</h1>
<p>Bienvenido, {sesion.user.name}</p>
<p>Email: {sesion.user.email}</p>
{sesion.user.image && (
<img
src={sesion.user.image}
alt={sesion.user.name ?? 'Avatar'}
width={64}
height={64}
/>
)}
<SignOut />
</div>
)
}La funcion auth() retorna la sesion completa o null si el usuario no esta autenticado. Al ser una funcion async, funciona perfectamente en Server Components.
En Client Components: useSession()
Para Client Components, necesitas envolver tu aplicacion con el SessionProvider y usar el hook useSession:
// app/layout.tsx
import { SessionProvider } from 'next-auth/react'
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="es">
<body>
<SessionProvider>
{children}
</SessionProvider>
</body>
</html>
)
}// components/user-info.tsx
'use client'
import { useSession } from 'next-auth/react'
export function UserInfo() {
const { data: sesion, status } = useSession()
if (status === 'loading') {
return <p>Cargando...</p>
}
if (status === 'unauthenticated') {
return <p>No has iniciado sesion</p>
}
return (
<div>
<p>Hola, {sesion?.user?.name}</p>
<p>{sesion?.user?.email}</p>
</div>
)
}El hook useSession retorna tres estados posibles: loading, authenticated y unauthenticated. Siempre maneja los tres.
En middleware: auth como wrapper
Auth.js v5 exporta auth como un wrapper de middleware que te da acceso a la sesion:
// middleware.ts
import { auth } from '@/auth'
export default auth((req) => {
const estaAutenticado = !!req.auth
// Logica de proteccion de rutas (ver siguiente seccion)
})
export const config = {
matcher: ['/dashboard/:path*', '/perfil/:path*', '/admin/:path*'],
}Proteger rutas con middleware
El middleware es la primera linea de defensa para rutas protegidas. Se ejecuta antes de que el Server Component cargue, asi que el usuario nunca ve contenido que no deberia ver.
// middleware.ts
import { auth } from '@/auth'
import { NextResponse } from 'next/server'
// Rutas que requieren autenticacion
const RUTAS_PROTEGIDAS = ['/dashboard', '/perfil', '/configuracion']
// Rutas solo para usuarios NO autenticados
const RUTAS_AUTH = ['/login', '/registro']
export default auth((req) => {
const { nextUrl } = req
const estaAutenticado = !!req.auth
const esRutaProtegida = RUTAS_PROTEGIDAS.some(ruta =>
nextUrl.pathname.startsWith(ruta)
)
const esRutaAuth = RUTAS_AUTH.some(ruta =>
nextUrl.pathname.startsWith(ruta)
)
// Sin sesion intentando acceder a ruta protegida
if (esRutaProtegida && !estaAutenticado) {
const loginUrl = new URL('/api/auth/signin', nextUrl.origin)
loginUrl.searchParams.set('callbackUrl', nextUrl.pathname)
return NextResponse.redirect(loginUrl)
}
// Con sesion intentando acceder a login/registro
if (esRutaAuth && estaAutenticado) {
return NextResponse.redirect(new URL('/dashboard', nextUrl.origin))
}
return NextResponse.next()
})
export const config = {
matcher: [
'/dashboard/:path*',
'/perfil/:path*',
'/configuracion/:path*',
'/login',
'/registro',
],
}Matcher especifico
Usa matcher para ejecutar el middleware solo en las rutas necesarias. No uses matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'] a menos que realmente necesites proteger todas las rutas. Un matcher especifico es mas eficiente y mas facil de debuggear.
Para una guia mas completa sobre seguridad en rutas y otros patrones de proteccion, revisa la guia de seguridad en aplicaciones Next.js.
Sesiones con base de datos: Prisma Adapter
Por defecto, Auth.js usa JWT para las sesiones. El token se guarda en una cookie y no necesitas base de datos. Pero si necesitas mas control -- revocar sesiones, ver sesiones activas, o guardar datos adicionales del usuario -- necesitas un adapter de base de datos.
Instalar dependencias
$ Schema de Prisma
Auth.js requiere tablas especificas para manejar usuarios, cuentas, sesiones y tokens de verificacion:
// prisma/schema.prisma
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
}
model User {
id String @id @default(cuid())
name String?
email String? @unique
emailVerified DateTime?
image String?
role String @default("user")
accounts Account[]
sessions Session[]
}
model Account {
id String @id @default(cuid())
userId String
type String
provider String
providerAccountId String
refresh_token String?
access_token String?
expires_at Int?
token_type String?
scope String?
id_token String?
session_state String?
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([provider, providerAccountId])
}
model Session {
id String @id @default(cuid())
sessionToken String @unique
userId String
expires DateTime
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
}
model VerificationToken {
identifier String
token String @unique
expires DateTime
@@unique([identifier, token])
}Sincronizar la base de datos
$ Configurar el adapter
Actualiza tu archivo auth.ts para usar el adapter de Prisma:
// auth.ts
import NextAuth from 'next-auth'
import Google from 'next-auth/providers/google'
import GitHub from 'next-auth/providers/github'
import { PrismaAdapter } from '@auth/prisma-adapter'
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
export const { handlers, signIn, signOut, auth } = NextAuth({
adapter: PrismaAdapter(prisma),
providers: [
Google,
GitHub,
],
session: {
strategy: 'database', // Cambiar de JWT a sesiones en DB
},
})JWT vs Database
Al agregar un adapter, Auth.js cambia automaticamente a sesiones en base de datos. Si quieres seguir usando JWT (por ejemplo, para compatibilidad con edge runtime en middleware), especifica session: { strategy: 'jwt' } explicitamente.
Callbacks: personalizar el flujo de autenticacion
Los callbacks son funciones que Auth.js ejecuta en momentos clave del flujo de autenticacion. Los dos mas importantes son jwt y session.
JWT Callback
Se ejecuta cada vez que se crea o actualiza un JWT. Aqui puedes agregar datos personalizados al token:
// auth.ts
import NextAuth from 'next-auth'
import Google from 'next-auth/providers/google'
import GitHub from 'next-auth/providers/github'
export const { handlers, signIn, signOut, auth } = NextAuth({
providers: [Google, GitHub],
callbacks: {
// Se ejecuta al crear/actualizar el JWT
jwt({ token, user }) {
// 'user' solo esta disponible en el primer sign in
if (user) {
token.role = user.role ?? 'user'
token.id = user.id
}
return token
},
// Se ejecuta al leer la sesion (auth(), useSession, etc.)
session({ session, token }) {
if (session.user) {
session.user.role = token.role as string
session.user.id = token.id as string
}
return session
},
},
})Extender los tipos de TypeScript
Para que TypeScript reconozca los campos personalizados que agregaste a la sesion y al token, necesitas extender los tipos:
// types/next-auth.d.ts
import { DefaultSession } from 'next-auth'
declare module 'next-auth' {
interface Session {
user: {
id: string
role: string
} & DefaultSession['user']
}
interface User {
role?: string
}
}
declare module 'next-auth/jwt' {
interface JWT {
role?: string
id?: string
}
}Authorized Callback
El callback authorized se ejecuta en el middleware y determina si una peticion debe continuar o redirigirse:
// auth.ts (agregando authorized callback)
export const { handlers, signIn, signOut, auth } = NextAuth({
providers: [Google, GitHub],
callbacks: {
authorized({ auth, request }) {
const estaAutenticado = !!auth?.user
const esRutaProtegida = request.nextUrl.pathname.startsWith('/dashboard')
if (esRutaProtegida && !estaAutenticado) {
return false // Redirige a la pagina de sign in
}
return true // Permite el acceso
},
jwt({ token, user }) {
if (user) {
token.role = user.role ?? 'user'
token.id = user.id
}
return token
},
session({ session, token }) {
if (session.user) {
session.user.role = token.role as string
session.user.id = token.id as string
}
return session
},
},
})Control de acceso por roles
Con los callbacks configurados, implementar roles es cuestion de leer el campo role de la sesion en tus componentes.
Middleware con roles
// middleware.ts
import { auth } from '@/auth'
import { NextResponse } from 'next/server'
const PERMISOS_RUTA: Record<string, string[]> = {
'/dashboard': ['user', 'editor', 'admin'],
'/editor': ['editor', 'admin'],
'/admin': ['admin'],
}
export default auth((req) => {
const { nextUrl } = req
const usuario = req.auth?.user
if (!usuario) {
return NextResponse.redirect(
new URL('/api/auth/signin', nextUrl.origin)
)
}
// Buscar si la ruta tiene restriccion de roles
const permisoRequerido = Object.entries(PERMISOS_RUTA).find(
([ruta]) => nextUrl.pathname.startsWith(ruta)
)
if (permisoRequerido) {
const [, rolesPermitidos] = permisoRequerido
const rolUsuario = usuario.role ?? 'user'
if (!rolesPermitidos.includes(rolUsuario)) {
return NextResponse.redirect(
new URL('/sin-acceso', nextUrl.origin)
)
}
}
return NextResponse.next()
})
export const config = {
matcher: ['/dashboard/:path*', '/editor/:path*', '/admin/:path*'],
}Verificacion de roles en Server Components
El middleware protege la ruta, pero tambien debes verificar en el Server Component para operaciones sensibles:
// app/admin/page.tsx
import { auth } from '@/auth'
import { redirect } from 'next/navigation'
export default async function AdminPage() {
const sesion = await auth()
if (!sesion?.user || sesion.user.role !== 'admin') {
redirect('/sin-acceso')
}
return (
<div>
<h1>Panel de administracion</h1>
<p>Solo usuarios con rol admin pueden ver esto.</p>
</div>
)
}Componente condicional por rol
// components/role-gate.tsx
import { auth } from '@/auth'
interface RoleGateProps {
rolesPermitidos: string[]
children: React.ReactNode
fallback?: React.ReactNode
}
export async function RoleGate({
rolesPermitidos,
children,
fallback = null,
}: RoleGateProps) {
const sesion = await auth()
const rolUsuario = sesion?.user?.role ?? 'user'
if (!rolesPermitidos.includes(rolUsuario)) {
return <>{fallback}</>
}
return <>{children}</>
}// Uso en cualquier page
import { RoleGate } from '@/components/role-gate'
export default function DashboardPage() {
return (
<div>
<h1>Dashboard</h1>
{/* Visible para todos los autenticados */}
<p>Contenido general del dashboard</p>
{/* Solo visible para admins */}
<RoleGate rolesPermitidos={['admin']}>
<section>
<h2>Estadisticas del sistema</h2>
{/* contenido de admin */}
</section>
</RoleGate>
</div>
)
}Estructura final del proyecto
Despues de implementar todo, tu proyecto deberia tener esta estructura:
mi-app/
├── auth.ts (configuracion central de Auth.js)
├── middleware.ts (proteccion de rutas)
├── types/
│ └── next-auth.d.ts (tipos extendidos de sesion)
├── app/
│ ├── api/
│ │ └── auth/
│ │ └── [...nextauth]/
│ │ └── route.ts (route handler)
│ ├── dashboard/
│ │ └── page.tsx (ruta protegida)
│ ├── admin/
│ │ └── page.tsx (ruta protegida por rol)
│ └── layout.tsx (SessionProvider)
├── components/
│ ├── sign-in.tsx (boton de login)
│ ├── sign-out.tsx (boton de logout)
│ ├── sign-in-button.tsx (version client component)
│ ├── user-info.tsx (info del usuario en client)
│ └── role-gate.tsx (acceso condicional por rol)
├── prisma/
│ └── schema.prisma (schema con tablas de Auth.js)
└── .env.local (secrets de OAuth y DB)
Seguridad: proteger tus secrets de OAuth
Los client secrets de Google y GitHub son credenciales sensibles. Si se filtran en tu repositorio, un atacante podria usarlos para suplantar tu aplicacion y obtener acceso a las cuentas de tus usuarios.
Verifica que tu .gitignore incluya:
# .gitignore
.env
.env.local
.env.*.localSi tu proyecto vive en GitHub, datahogo puede escanear tu repositorio para detectar secrets de OAuth o API keys que se hayan commiteado accidentalmente. Si encuentra algo, genera un PR con el fix.
Ademas de proteger las credenciales, asegurate de configurar correctamente las URIs de callback en tus proveedores OAuth. No uses wildcards ni patrones permisivos -- especifica la URL exacta de tu dominio.
Auth.js vs Clerk vs Supabase Auth
Auth.js no es la unica opcion. Dependiendo de tu proyecto, otra solucion puede ser mejor:
| Caracteristica | Auth.js v5 | Clerk | Supabase Auth |
|---|---|---|---|
| Precio | Gratis (open-source) | Gratis hasta 10k MAU, luego de pago | Gratis con Supabase |
| Setup | Manual (tu configuras todo) | Minimo (SDK con UI incluida) | Medio (parte del ecosistema Supabase) |
| UI de login | Tu la construyes | Pre-construida y personalizable | Componente opcional |
| OAuth providers | 80+ proveedores | 20+ proveedores | 15+ proveedores |
| Base de datos | Tu la eliges (Prisma, Drizzle, etc.) | Managed por Clerk | PostgreSQL de Supabase |
| Self-hosted | Si | No | Si |
| App Router | Nativo | Nativo | Con @supabase/ssr |
| Roles/permisos | Manual con callbacks | Incluido (Organizations) | Con RLS de PostgreSQL |
Cuando elegir cada uno
Auth.js v5 es la mejor opcion cuando quieres control total, no quieres depender de un servicio externo, y no te importa escribir mas codigo. Es gratis sin limites de usuarios.
Clerk es ideal cuando necesitas ir rapido. Su SDK incluye componentes de UI para sign in, sign up, perfil de usuario y organizaciones. El programa de creadores de Clerk ofrece beneficios para proyectos open-source y creadores de contenido. Si tu prioridad es velocidad de desarrollo sobre control, vale la pena evaluarlo.
Supabase Auth tiene sentido si ya usas Supabase como tu base de datos. Viene integrado y los permisos se manejan con Row Level Security directamente en PostgreSQL. Si quieres explorar esta opcion, revisa la guia de Supabase con Next.js.
Errores comunes y como solucionarlos
Error: "OAUTH_CALLBACK_ERROR"
[auth][error] OAuthCallbackError: ...Causa: La URI de callback registrada en el proveedor (Google/GitHub) no coincide con la URL de tu aplicacion.
Solucion: Verifica que la URI en la consola del proveedor sea exactamente https://tudominio.com/api/auth/callback/google (o /github). No olvides el protocolo https en produccion.
Error: "SESSION_NOT_FOUND" con adapter de base de datos
Causa: Las tablas de Auth.js no existen en tu base de datos.
Solucion:
$ Verifica que tu schema de Prisma tenga los modelos User, Account, Session y VerificationToken exactamente como los define la documentacion de Auth.js.
El middleware no detecta la sesion
Causa comun: Estas usando session: { strategy: 'database' } pero el middleware corre en edge runtime, que no tiene acceso a la base de datos.
Solucion: Usa JWT para las sesiones si necesitas que el middleware funcione en el edge:
// auth.ts
export const { handlers, signIn, signOut, auth } = NextAuth({
adapter: PrismaAdapter(prisma),
providers: [Google, GitHub],
session: {
strategy: 'jwt', // JWT funciona en edge runtime
},
})Con esta configuracion, el adapter se usa para guardar usuarios y cuentas, pero las sesiones se manejan con JWT.
useSession retorna undefined
Causa: Falta el SessionProvider en el layout.
Solucion: Asegurate de envolver tu aplicacion con <SessionProvider> en el layout raiz, como se muestra en la seccion de Client Components.
Resumen
Implementar autenticacion en Next.js con Auth.js v5 se reduce a estos pasos:
- Instalar
next-auth@5y configurarauth.tscon tus proveedores - Obtener credenciales de OAuth en Google Cloud Console y GitHub Developer Settings
- Crear el Route Handler en
app/api/auth/[...nextauth]/route.ts - Componentes de login/logout con Server Actions o Client Components
- Leer la sesion con
auth()en el servidor,useSession()en el cliente - Proteger rutas con middleware y el callback
authorized - Agregar Prisma adapter si necesitas sesiones en base de datos
- Implementar roles con callbacks y verificacion en componentes
La documentacion oficial de Auth.js cubre escenarios mas avanzados como email/password, magic links y proveedores personalizados. Lo que tienes aqui es una base solida para la mayoria de proyectos con Next.js y App Router.
Recursos adicionales
Preguntas frecuentes
Cual es la diferencia entre Auth.js y NextAuth?
Auth.js es la evolucion de NextAuth.js. A partir de la version 5, el proyecto se renombro a Auth.js para soportar multiples frameworks (no solo Next.js). Si usabas NextAuth v4, Auth.js v5 es su sucesor directo.
Auth.js es gratis?
Si, Auth.js es completamente open-source y gratuito. No hay plan de pago ni limites de usuarios. Los unicos costos son los de tu base de datos si usas sesiones en DB.
Debo usar JWT o sesiones en base de datos?
JWT es mas simple y no requiere base de datos, ideal para apps sin backend propio. Sesiones en DB dan mas control (puedes revocar sesiones, ver sesiones activas) y son mejor para apps con datos sensibles.
Puedo usar Auth.js con el App Router de Next.js?
Si, Auth.js v5 fue disenado especificamente para el App Router. Funciona con Server Components, Server Actions, middleware y Route Handlers nativamente.
Auth.js vs Clerk vs Supabase Auth, cual es mejor?
Auth.js es gratis y open-source pero requiere mas configuracion. Clerk es un servicio managed con UI pre-construida, ideal si quieres velocidad de desarrollo. Supabase Auth viene incluido si ya usas Supabase. La eleccion depende de tu stack y presupuesto.
Articulos relacionados
Zod Avanzado: Discriminated Unions, Transforms y Pipes
Patrones avanzados de Zod: discriminated unions, transforms, pipes, preprocess, y como validar datos complejos en TypeScript con schemas reutilizables.
tRPC + Next.js: APIs Type-Safe sin REST
Implementa tRPC en Next.js para APIs 100% type-safe. Sin schemas de API, sin fetch manual, sin types duplicados. End-to-end type safety con TypeScript.
Webhooks en Next.js: Recibe y Procesa Eventos
Implementa webhooks en Next.js para recibir eventos de Stripe, GitHub, Clerk y otros servicios. Verificacion de firmas, tipado y manejo de errores.