Busque em todas as páginas da documentação
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥
npm install next-auth@beta// auth.ts (raiz do projeto)
import NextAuth from "next-auth";
import GitHub from "next-auth/providers/github";
import Google from "next-auth/providers/google";
export const { handlers, signIn, signOut, auth } = NextAuth({
providers: [
GitHub({
clientId: process.env.AUTH_GITHUB_ID!,
clientSecret: process.env.AUTH_GITHUB_SECRET!,
}),
Google({
clientId: process.env.AUTH_GOOGLE_ID!,
clientSecret: process.env.AUTH_GOOGLE_SECRET!,
}),
],
});// app/api/auth/[...nextauth]/route.ts
import { handlers } from "@/auth";
export const { GET, POST } = handlers;// .env.local
AUTH_SECRET=your-random-secret-at-least-32-chars
AUTH_GITHUB_ID=...
AUTH_GITHUB_SECRET=...
AUTH_GOOGLE_ID=...
AUTH_GOOGLE_SECRET=...Quando usar isso: Você precisa de login OAuth (GitHub, Google, etc.), gerenciamento de sessão e proteção de rotas em uma aplicação Next.js App Router.
// app/components/AuthButtons.tsx
import { auth, signIn, signOut } from "@/auth";
export async function SignInButton() {
const session = await auth();
if (session?.user) {
return (
<div className="flex items-center gap-3">
{session.user.image && (
<img
src={session.user.image}
alt=""
className="w-8 h-8 rounded-full"
/>
)}
<span className="text-sm">{session.user.name}</span>
<form
action={async () => {
"use server";
await signOut();
}}
>
<button className="text-sm text-gray-500 hover:text-gray-700">
Sair
</button>
</form>
</div>
);
}
return (
<div className="flex gap-2">
<form
action={async () => {
"use server";
await signIn("github");
}}
>
<button className="bg-gray-900 text-white px-4 py-2 rounded text-sm">
Entrar com GitHub
</button>
</form>
<form
action={async () => {
"use server";
await signIn("google");
}}
>
<button className="bg-blue-600 text-white px-4 py-2 rounded text-sm">
Entrar com Google
</button>
</form>
</div>
);
}// app/dashboard/page.tsx
import { auth } from "@/auth";
import { redirect } from "next/navigation";
export default async function DashboardPage() {
const session = await auth();
if (!session) {
redirect("/api/auth/signin");
}
return (
<div className="max-w-2xl mx-auto p-6">
<h1 className="text-2xl font-bold">Dashboard</h1>
<p className="mt-2">Bem-vindo, {session.user?.name}!</p>
<pre className="mt-4 bg-gray-100 p-4 rounded text-sm">
{JSON.stringify(session, null, 2)}
</pre>
</div>
);
}// middleware.ts
import { auth } from "./auth";
export default auth((req) => {
const isLoggedIn = !!req.auth;
const isProtected = req.nextUrl.pathname.startsWith("/dashboard");
if (isProtected && !isLoggedIn) {
return Response.redirect(new URL("/api/auth/signin", req.nextUrl));
}
});
export const config = {
matcher: ["/dashboard/:path*", "/settings/:path*"],
};O que isso demonstra:
auth()auth(), signIn(), signOut() e handlers de uma única configuraçãoauth() retorna a sessão atual em Server Components, Server Actions, rotas de API e middlewarehandlers fornece manipuladores de rota GET e POST para a rota catch-all /api/auth/[...nextauth]AUTH_SECRET é necessário em produção para assinar JWTs; gere com npx auth secretProvedor de Credenciais (email/senha):
import Credentials from "next-auth/providers/credentials";
import { z } from "zod";
import bcrypt from "bcryptjs";
import { prisma } from "@/lib/prisma";
export const { handlers, signIn, signOut, auth } = NextAuth({
providers: [
Credentials({
credentials: {
email: { label: "Email", type: "email" },
password: { label: "Password", type: "password" },
},
authorize: async (credentials) => {
const parsed = z
.object({
email: z.string().email(),
password: z.string().min(8),
})
.safeParse(credentials);
if (!parsed.success) return null;
const user = await prisma.user.findUnique({
where: { email: parsed.data.email },
});
if (!user || !user.password) return null;
const valid = await bcrypt.compare(parsed.data.password, user.password);
if (!valid) return null;
return { id: String(user.id), name: user.name, email: user.email };
},
}),
],
});Adaptador de banco de dados Prisma:
npm install @auth/prisma-adapterimport { PrismaAdapter } from "@auth/prisma-adapter";
import { prisma } from "@/lib/prisma";
export const { handlers, signIn, signOut, auth } = NextAuth({
adapter: PrismaAdapter(prisma),
providers: [GitHub, Google],
session: { strategy: "database" }, // Use sessões de banco de dados em vez de JWT
});Estendendo a sessão com campos personalizados:
export const { handlers, signIn, signOut, auth } = NextAuth({
providers: [GitHub],
callbacks: {
async jwt({ token, user }) {
if (user) {
token.role = user.role; // Adiciona role do usuário do banco de dados
}
return token;
},
async session({ session, token }) {
session.user.id = token.sub!;
session.user.role = token.role as string;
return session;
},
},
});// types/next-auth.d.ts
import { DefaultSession } from "next-auth";
declare module "next-auth" {
interface Session {
user: {
id: string;
role: string;
} & DefaultSession["user"];
}
}Acesso à sessão no lado do cliente:
// app/providers.tsx
"use client";
import { SessionProvider } from "next-auth/react";
export function AuthProvider({ children }: { children: React.ReactNode }) {
return <SessionProvider>{children}</SessionProvider>;
}
// app/components/ClientProfile.tsx
"use client";
import { useSession } from "next-auth/react";
export function ClientProfile() {
const { data: session, status } = useSession();
if (status === "loading") return <p>Carregando...</p>;
if (!session) return <p>Não autenticado</p>;
return <p>Autenticado como {session.user?.name}</p>;
}Session e JWT através de aumento de módulo em types/next-auth.d.tsauth() retorna Session | null; sempre verifique se é nulo antes de acessar session.userUser pode ser estendido para campos de banco de dados personalizadosimport type { Session } from "next-auth";
async function getUser(): Promise<Session["user"] | null> {
const session = await auth();
return session?.user ?? null;
}AUTH_SECRET ausente - O aplicativo trava em produção sem AUTH_SECRET. Correção: Gere-o com npx auth secret e adicione às suas variáveis de ambiente. Necessário para assinatura de JWT.
URL de callback incorreta - Provedores OAuth rejeitam redirecionamentos se a URL de callback não corresponder. Correção: Registre https://seudominio.com/api/auth/callback/github (e /google) nas configurações do desenvolvedor de cada provedor.
Sessão nula em componentes cliente - auth() só funciona no lado do servidor. Correção: Use SessionProvider e o hook useSession() para componentes cliente. Envolva seu layout com <SessionProvider>.
Middleware é executado em todas as requisições - Sem um matcher, o middleware de autenticação é executado em ativos estáticos, rotas de API, etc. Correção: Sempre configure config.matcher para limitar o middleware a caminhos protegidos.
Limitações do provedor Credentials - O provedor Credentials não suporta sessões de banco de dados prontas para uso (apenas JWT). Correção: Use a estratégia JWT com credenciais. Para sessões de banco de dados, use provedores OAuth com um adaptador de banco de dados.
Compatibilidade com o runtime Edge - Alguns adaptadores de banco de dados e bcrypt não funcionam no runtime Edge. Correção: Use bcryptjs em vez de bcrypt. Verifique a compatibilidade do adaptador com o Edge. Use runtime: "nodejs" no middleware, se necessário.
Migração de v4 para v5 - Auth.js v5 tem uma API significativamente diferente do NextAuth v4. Correção: Siga o guia de migração oficial. Mudanças importantes: NextAuth() exporta auth em vez de usar getServerSession(), e next-auth/react é apenas para componentes cliente.
| Biblioteca | Melhor para | Contrapartida |
|---|---|---|
| Auth.js / NextAuth v5 | Gerenciamento completo de OAuth + sessão para Next.js | Configuração complexa para fluxos personalizados |
| Clerk | Componentes de UI de autenticação prontos para uso | Serviço pago, dependência de fornecedor |
| Supabase Auth | Integração com o ecossistema Supabase | Vinculado ao Supabase |
| Lucia | Autenticação leve, DIY | Configuração mais manual, menos abstração |
| Kinde | Autenticação B2B com organizações | Serviço pago |
| JWT Personalizado | Controle total | Deve lidar com segurança, atualização, revogação você mesmo |
Session | null contendo informações do usuário e expiraçãouseSession() de next-auth/react em vez dissonull antes de acessar session.usersignIn("github")auth() retornam a sessãoAUTH_SECRET é necessário para assinar JWTs em produçãonpx auth secret e adicione às suas variáveis de ambiente// middleware.ts
import { auth } from "./auth";
export default auth((req) => {
if (!req.auth && req.nextUrl.pathname.startsWith("/dashboard")) {
return Response.redirect(new URL("/api/auth/signin", req.nextUrl));
}
});
export const config = {
matcher: ["/dashboard/:path*"],
};Sempre defina config.matcher para limitar o middleware a caminhos protegidos.
<SessionProvider> de next-auth/reactuseSession() em componentes clienteuseSession() retorna { data: session, status } onde status é "loading", "authenticated", ou "unauthenticated"Credentials de next-auth/providers/credentialscredentials e uma função authorizeauthorize valida as credenciais e retorna um objeto de usuário ou nullcallbacks: {
async jwt({ token, user }) {
if (user) token.role = user.role;
return token;
},
async session({ session, token }) {
session.user.role = token.role as string;
return session;
},
}Também estenda o tipo Session através de aumento de módulo em types/next-auth.d.ts.
// types/next-auth.d.ts
import { DefaultSession } from "next-auth";
declare module "next-auth" {
interface Session {
user: {
id: string;
role: string;
} & DefaultSession["user"];
}
}Isso adiciona id e role a session.user em todo o seu aplicativo.
auth() é uma função apenas do servidor e não pode ser chamada em componentes cliente<SessionProvider> e o hook useSession() para acesso à sessão no lado do clienteSessionProvider envolva a árvore de componentes em seu layoutimport { PrismaAdapter } from "@auth/prisma-adapter";
export const { handlers, auth, signIn, signOut } = NextAuth({
adapter: PrismaAdapter(prisma),
session: { strategy: "database" },
providers: [GitHub, Google],
});Instale @auth/prisma-adapter e defina session.strategy como "database".
matcher, o middleware é executado em todas as rotas, incluindo _next/static, imagens e rotas de APIconfig.matcher para limitá-lo a caminhos protegidosmatcher: ["/dashboard/:path*", "/settings/:path*"]auth() em vez de exigir getServerSession(authOptions)NextAuth() que retorna auth, signIn, signOut e handlersnext-auth/react (useSession, SessionProvider) é apenas para componentes clienteauth.ts na raiz do projetoRevisado por Chris St. John·Última atualização: 19 de jul. de 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥