Next.js + Auth.js v5
Adicione autenticação a um app Next.js 15 com Auth.js v5 (anteriormente NextAuth), incluindo OAuth do GitHub e proteção de rotas baseada em sessão.
Busque em todas as páginas da documentação
Adicione autenticação a um app Next.js 15 com Auth.js v5 (anteriormente NextAuth), incluindo OAuth do GitHub e proteção de rotas baseada em sessão.
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥
npm install next-auth@beta.env.local:
npx auth secretauth.ts na raiz do projeto exportando handlers configurados, auth, signIn, e signOut.app/api/auth/[...nextauth]/route.ts que reexporta os handlers.AUTH_GITHUB_ID, AUTH_GITHUB_SECRET) a .env.local.middleware.ts que usa a exportação auth para proteger rotas..env.localAUTH_SECRET=<string de 32+ caracteres de `npx auth secret`>
AUTH_GITHUB_ID=<id do cliente da app oauth do github>
AUTH_GITHUB_SECRET=<segredo do cliente da app oauth do github>
auth.ts (raiz do projeto)import NextAuth from "next-auth";
import GitHub from "next-auth/providers/github";
export const \{ handlers, auth, signIn, signOut \} = NextAuth(\{
providers: [GitHub],
session: \{ strategy: "jwt" \},
callbacks: \{
authorized: async (\{ auth \}) => !!auth,
\},
\});app/api/auth/[...nextauth]/route.tsexport \{ GET, POST \} from "@/auth";Espere - na v5 você exporta do objeto handlers em vez disso:
import \{ handlers \} from "@/auth";
export const \{ GET, POST \} = handlers;middleware.tsexport \{ auth as middleware \} from "@/auth";
export const config = \{
matcher: ["/dashboard/:path*"],
\};app/dashboard/page.tsximport \{ auth, signOut \} from "@/auth";
export default async function DashboardPage() \{
const session = await auth();
return (
<main className="mx-auto max-w-xl p-8">
<h1 className="text-2xl font-bold">Dashboard</h1>
<p className="mt-4">Bem-vindo, \{session?.user?.name\}</p>
<form
action=\{async () => \{
"use server";
await signOut();
\}\}
>
<button type="submit" className="mt-4 rounded bg-black px-4 py-2 text-white">
Sair
</button>
</form>
</main>
);
\}app/page.tsx (botão de login)import \{ auth, signIn \} from "@/auth";
export default async function Home() \{
const session = await auth();
if (session?.user) \{
return <a href="/dashboard">Ir para o dashboard</a>;
\}
return (
<form
action=\{async () => \{
"use server";
await signIn("github", \{ redirectTo: "/dashboard" \});
\}\}
>
<button type="submit">Entrar com GitHub</button>
</form>
);
\}O Auth.js v5 centraliza a configuração em um único arquivo auth.ts na raiz, que exporta todas as funções que você precisa em outros lugares. A função auth() é isomórfica - ela lê a sessão dos cookies em Server Components, Server Actions, Route Handlers e middleware. A importação de middleware export \{ auth as middleware \} transforma o Auth.js em um guard ciente de matchers que redireciona usuários não autenticados para a página de login.
Por baixo dos panos, o Auth.js define um cookie JWT assinado e criptografado por padrão (session.strategy: "jwt"). Você pode mudar para sessões de banco de dados adicionando um adaptador Prisma/Drizzle.
Google, Credentials, Email, etc. ao array providers.@auth/prisma-adapter, passe adapter: PrismaAdapter(prisma), e defina session: \{ strategy: "database" \}.pages: \{ signIn: "/login" \} na configuração do NextAuth e crie sua própria página /login que chama signIn().jwt e session para incluir um claim de role, e então verifique-o no middleware ou em Server Components.auth() em RSC vs useSession() no cliente: código do servidor usa await auth(); código do cliente envolve o app com <SessionProvider> e chama useSession().auth.config.ts livre de adaptadores Node-only e importe apenas a configuração leve no middleware.Estenda a interface Session usando module augmentation para que seus claims customizados sejam tipados em todos os lugares:
// types/next-auth.d.ts
import \{ DefaultSession \} from "next-auth";
declare module "next-auth" \{
interface Session \{
user: \{
id: string;
role: "admin" | "user";
\} & DefaultSession["user"];
\}
\}Após isso, session.user.role será fortemente tipado em todos os lugares onde você chamar auth().
AUTH_SECRET deve ser longo o suficiente. O Auth.js v5 requer 32+ caracteres. Gere com npx auth secret - não digite um manualmente.fs, crypto.randomBytes na forma legada, drivers de banco de dados). Mantenha lógica pesada fora de middleware.ts./_next/static e imagens se você não for cuidadoso. Use um negative lookahead como /((?!api|_next/static|_next/image|favicon.ico).*).https://yourapp.com/api/auth/callback/github. Uma barra final ou protocolo errado quebra o login com um erro vago.http://localhost:3000 e outra para produção.auth.ts na raiz do projeto, não em app/. Colocá-lo dentro de app/ faz o Next.js tratá-lo como uma rota. Mantenha-o na raiz do projeto ou sob lib/ e use alias conforme necessário.| Ferramenta | Estilo | Ideal para |
|---|---|---|
| Auth.js (NextAuth v5) | OSS, integrado ao framework | A maioria dos apps Next.js, fluxos OAuth |
| Clerk | SaaS pago | UI polida, configuração rápida, orgs/times |
| Lucia Auth | DIY leve | Controle total, aprendizado, fluxos customizados |
| Supabase Auth | Empacotado com DB Supabase | Apps que já usam Supabase |
| Kinde | SaaS pago | Flags de funcionalidade + auth combinados |
| JWT Customizado | Crie o seu | Requisitos especializados |
Na raiz do projeto (mesmo nível de next.config.js) ou em lib/auth.ts. Não o coloque dentro do diretório app/ - o Next.js interpretará arquivos lá como rotas.
Execute npx auth secret. Ele escreve um valor criptograficamente aleatório de 32+ caracteres em .env.local automaticamente. Não reutilize segredos entre ambientes.
JWT é stateless, rápido e o padrão - perfeito para a maioria dos apps. Sessões de banco de dados requerem um adaptador, mas oferecem revogação instantânea, armazenamento maior e listagem fácil de sessões entre dispositivos. Escolha sessões de banco de dados para apps com recursos de logout-de-todos-os-lugares ou kick-user pelo admin.
Defina pages: \{ signIn: "/login" \} na configuração do NextAuth, então crie app/login/page.tsx que renderiza sua própria UI e chama signIn("github") de uma Server Action.
import \{ auth \} from "@/auth";
const session = await auth();
if (!session?.user) redirect("/login");Em Client Components, envolva o app com <SessionProvider> e chame useSession() em vez disso.
O bundle do middleware usa o runtime Edge, que não pode incluir código Node-only como o adaptador Prisma. Divida sua configuração: coloque a lista leve de provedores em auth.config.ts e importe apenas isso em middleware.ts. Mantenha o adaptador no auth.ts completo que os Server Components usam.
Quase sempre uma incompatibilidade de URL de callback. Sua app OAuth do GitHub (ou Google) deve listar a URL de produção exata: https://yourapp.com/api/auth/callback/github. Fique atento a barras finais, http vs https, e o subdomínio www.
Use a callback jwt para adicionar o role ao token, então espelhe-o na sessão:
callbacks: \{
async jwt(\{ token, user \}) \{
if (user) token.role = user.role;
return token;
\},
async session(\{ session, token \}) \{
session.user.role = token.role as "admin" | "user";
return session;
\},
\}Use module augmentation em types/next-auth.d.ts:
declare module "next-auth" \{
interface Session \{
user: \{ id: string; role: string \} & DefaultSession["user"];
\}
\}Certifique-se de que types/next-auth.d.ts está incluído no seu tsconfig.json.
auth() retorna Session | null, e mesmo quando não é null, user é opcional. Sempre refine:
const session = await auth();
if (!session?.user) redirect("/login");Após essa verificação, session.user é refinado para o tipo definido.
Chame signOut() do Auth.js. Em um Server Component, você o envolve em uma Server Action:
<form action=\{async () => \{ "use server"; await signOut(); \}\}>
<button type="submit">Sair</button>
</form>Em um Client Component, importe signOut de next-auth/react e chame-o diretamente.
Clerk é mais rápido de configurar e inclui UI polida, orgs e MFA prontos para uso - mas é pago. Auth.js é gratuito e totalmente customizável, mas requer mais configuração. Escolha Clerk se velocidade de lançamento e recursos importam mais que o custo; escolha Auth.js se você quer controle total ou zero vendor lock-in.
Revisado por Chris St. John·Última atualização: 10 de jul. de 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥