Guia Completo NextAuth.js

Entendendo o NextAuth

1. Fluxo de Autenticação Básico

  • Quando um usuário clica em "Login", o NextAuth inicia o fluxo de autenticação
  • O usuário é redirecionado para o provedor (ex: Google, GitHub)
  • Após autenticar no provedor, o usuário volta para sua aplicação
  • O NextAuth cria uma sessão segura e gerencia ela automaticamente

2. Sessões e Tokens

  • Quando autenticado, o NextAuth cria uma sessão
  • Esta sessão contém informações básicas do usuário (email, nome, imagem)
  • O token da sessão é armazenado em um cookie seguro
  • Por padrão, sessões duram 30 dias
  • A sessão é verificada e atualizada automaticamente

3. Hooks Principais

// useSession: verifica se existe uma sessão ativa
const { data: session } = useSession()

// signIn: inicia o processo de login
signIn() // login geral
signIn("google") // login específico com Google

// signOut: encerra a sessão
signOut()

4. Proteção de Rotas

Você pode proteger rotas de duas maneiras:

a. Via Middleware (a nível de rota):

// Bloqueia acesso a rotas não autorizadas
export const config = {
  matcher: ["/dashboard/:path*"]
}

b. Via Verificação de Sessão (dentro do componente):

if (!session) {
  redirect("/login")
}

5. Fluxo de Dados

Usuário → Clica em Login → NextAuth inicia fluxo →
Provedor (ex: Google) → Autorização → Volta para app →
NextAuth cria sessão → Usuário logado

6. Como ele guarda os dados

  • Cookies seguros para sessão
  • Por padrão, guarda apenas dados básicos:
    • Nome
    • Email
    • Imagem do perfil
  • Você pode estender para guardar mais dados

7. Benefícios práticos

  • Gerenciamento automático de sessão
  • Proteção contra CSRF
  • Rotação automática de tokens
  • Múltiplos provedores de autenticação
  • Sistema de callbacks para personalização

8. Callbacks importantes

callbacks: {
  // Executado quando sessão é criada/atualizada
  async session({ session, user }) {
    return session
  },

  // Executado quando usuário faz login
  async signIn({ user, account, profile }) {
    return true
  },

  // Personaliza o JWT
  async jwt({ token, user, account }) {
    return token
  }
}

9. Estados de Autenticação

const { status } = useSession()

// status pode ser:
"loading" // verificando sessão
"authenticated" // usuário logado
"unauthenticated" // usuário não logado

Implementação Passo a Passo

1. Instalação

npm install next-auth@latest

2. Configuração Inicial

Crie um arquivo de configuração em /app/api/auth/[...nextauth]/route.ts:

import NextAuth from "next-auth";
import GoogleProvider from "next-auth/providers/google";

const handler = NextAuth({
  providers: [
    GoogleProvider({
      clientId: process.env.GOOGLE_ID!,
      clientSecret: process.env.GOOGLE_SECRET!,
    }),
  ],
});

export { handler as GET, handler as POST };

3. Variáveis de Ambiente

Crie um arquivo .env.local:

NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=sua_chave_secreta_aqui # Você pode gerar usando: openssl rand -base64 32
GOOGLE_ID=seu_google_client_id
GOOGLE_SECRET=seu_google_client_secret

4. Configuração do Provider

No seu layout raiz (app/layout.tsx):

import { SessionProvider } from "next-auth/react";

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html>
      <body>
        <SessionProvider>{children}</SessionProvider>
      </body>
    </html>
  );
}

5. Implementação nos Componentes

'use client'
import { useSession, signIn, signOut } from "next-auth/react";

export default function Component() {
  const { data: session } = useSession();

  if (session) {
    return (
      <>
        Logado como {session.user?.email} <br />
        <button onClick={() => signOut()}>Sair</button>
      </>
    );
  }
  return (
    <>
      Não está logado <br />
      <button onClick={() => signIn()}>Entrar</button>
    </>
  );
}

6. Middleware para Proteção de Rotas

Crie middleware.ts na raiz do projeto:

export { default } from "next-auth/middleware";

export const config = {
  matcher: ["/dashboard/:path*", "/perfil"],
};

7. Configuração do Google OAuth

  1. Acesse o Google Cloud Console (https://console.cloud.google.com)
  2. Crie um novo projeto
  3. Habilite a API do Google+
  4. Vá para "Credenciais" e crie uma nova credencial OAuth 2.0
  5. Configure as URIs de redirecionamento autorizadas:
  6. Copie o Client ID e Client Secret para suas variáveis de ambiente

8. Verificação de Autenticação em Rotas Específicas

import { getServerSession } from "next-auth/next";

export default async function Page() {
  const session = await getServerSession();

  if (!session) {
    // Usuário não está autenticado
    return <div>Acesso negado</div>;
  }

  return <div>Conteúdo protegido</div>;
}

9. Adicionando Múltiplos Providers

import GithubProvider from "next-auth/providers/github";

const handler = NextAuth({
  providers: [
    GoogleProvider({
      clientId: process.env.GOOGLE_ID!,
      clientSecret: process.env.GOOGLE_SECRET!,
    }),
    GithubProvider({
      clientId: process.env.GITHUB_ID!,
      clientSecret: process.env.GITHUB_SECRET!,
    }),
  ],
});

Dicas de Uso

  1. Sempre use o hook useSession em componentes client-side
  2. Para componentes server-side, use getServerSession
  3. Mantenha suas chaves secretas seguras e nunca as exponha no código
  4. Use o middleware para proteger múltiplas rotas de uma vez
  5. Aproveite os callbacks para personalizar o comportamento da autenticação
  6. Considere implementar um fallback para quando o JavaScript estiver desabilitado
  7. Teste diferentes fluxos de autenticação em desenvolvimento antes de ir para produção

Troubleshooting Comum

  1. Erro de NEXTAUTH_SECRET não definido

    • Certifique-se de que a variável está definida no .env.local
  2. Erro de callback URL

    • Verifique se as URLs de callback estão corretamente configuradas no provedor
  3. Sessão não persistindo

    • Verifique se o SessionProvider está corretamente configurado no layout raiz
  4. Erro de CORS

    • Certifique-se de que NEXTAUTH_URL está corretamente configurado
  5. Problemas com TypeScript

    • Verifique se os tipos estão corretamente importados e declarados