Alternar tema

Guia completo de login OAuth no Next.js: Google, GitHub e WeChat

Easton editorial illustration: deployment dock

Você clica em “Entrar com Google”, a página abre o Google, você autoriza o acesso e, ao voltar, o login já está concluído.

É um processo que todo mundo já viu inúmeras vezes. Mas, quando chega a hora de adicionar um login de terceiros ao próprio projeto, surgem várias dúvidas: por que há dois redirecionamentos? O que é uma URL de callback? O que significa redirect_uri_mismatch? Por que funciona localmente e falha depois da implantação?

Na primeira vez que configurei OAuth, li uma pilha de documentação repleta de termos como “código de autorização”, access_token e client_secret. Quanto mais eu lia, mais confuso ficava. Foram dois dias e muitos tropeços até eu entender o processo de verdade.

Neste artigo, quero explicar o login OAuth da maneira mais direta possível. Sem acumular jargão ou teoria desnecessária: vamos entender como ele realmente funciona e como configurar login com Google, GitHub e WeChat no Next.js. No fim, você vai perceber que não é nenhum bicho de sete cabeças.

O que é OAuth 2.0, afinal? Uma explicação simples

Primeiro, uma analogia do dia a dia

Imagine que você mora em um condomínio e fez uma compra online. Você quer que o entregador leve o pacote até a porta do apartamento, mas existe um problema: a entrada do condomínio é controlada, e ele não consegue passar.

Uma solução tradicional seria entregar seu cartão de acesso ao entregador. Isso seria arriscado: com o cartão em mãos, ele poderia voltar e entrar no condomínio quando quisesse.

Uma solução mais inteligente seria avisar a portaria de que uma entrega está chegando. O porteiro emite para o entregador um passe temporário, com regras como “válido apenas hoje, das 14h às 16h, e somente para o bloco A”. Depois da entrega, o passe deixa de funcionar.

Essa é a ideia central do OAuth.

Na analogia:

  • Você = o usuário que quer entrar
  • O entregador = o aplicativo de terceiros, como o site que você desenvolveu
  • A portaria = o provedor OAuth, como Google, WeChat ou GitHub
  • O cartão de acesso = sua senha, que não deve ser entregue a outra pessoa
  • O passe temporário = o access_token, que expira e possui permissões limitadas

Você não precisa entregar sua senha ao aplicativo terceiro. Basta autorizá-lo a obter um “passe temporário” com o provedor OAuth.

As cinco etapas do OAuth no fluxo de código de autorização

Agora vamos aplicar esse processo ao login OAuth em um projeto Next.js.

Primeira etapa: o usuário clica no botão “Entrar com Google” no seu site.

Segunda etapa: seu site redireciona o usuário para a página de autorização do Google, por meio de uma URL parecida com esta:

https://accounts.google.com/o/oauth2/auth?
  client_id=ID_do_seu_aplicativo
  &redirect_uri=http://localhost:3000/api/auth/callback/google
  &response_type=code
  &scope=openid email profile
  &state=string_aleatória

Nesse momento, seu site está dizendo ao Google: “Sou este aplicativo (client_id), o usuário quer entrar usando uma conta de vocês. Peça a confirmação dele e, depois, envie-o de volta para este endereço (redirect_uri)”.

Terceira etapa: na página do Google, o usuário vê uma mensagem informando que o aplicativo quer acessar seus dados básicos e clica em “Permitir”.

Quarta etapa: o Google redireciona o usuário de volta ao seu site (redirect_uri) e inclui na URL um código de autorização (code):

http://localhost:3000/api/auth/callback/google?code=ABCD1234&state=string_aleatória

Esse código é apenas uma credencial provisória, não o passe definitivo. Ele expira rapidamente, normalmente em dez minutos, e só pode ser usado uma vez.

Quinta etapa: o backend do seu site envia esse código, junto com o client_secret, ao Google para trocá-lo por um access_token real:

// Código do backend (versão simplificada)
const response = await fetch('https://oauth2.googleapis.com/token', {
  method: 'POST',
  body: JSON.stringify({
    code: 'ABCD1234',
    client_id: 'ID_do_seu_aplicativo',
    client_secret: 'senha_do_seu_aplicativo',
    redirect_uri: 'http://localhost:3000/api/auth/callback/google',
    grant_type: 'authorization_code',
  }),
})

const { access_token } = await response.json()

Com o access_token, seu site pode consultar os dados do usuário no Google, como e-mail, foto e nome.

Sexta etapa (opcional): usar o access_token para obter os dados do usuário:

const userInfo = await fetch('https://www.googleapis.com/oauth2/v2/userinfo', {
  headers: {
    Authorization: `Bearer ${access_token}`,
  },
})

Quando todo o fluxo termina, seu site sabe quem é o usuário, pode criar uma sessão e mantê-lo autenticado.

Os principais conceitos, sem complicação

Talvez alguns termos ainda pareçam confusos. Vamos explicá-los em linguagem simples:

  • client_id: é o “documento de identidade” do seu aplicativo no Google. Pode ser público; não há problema se alguém o vir.

  • client_secret: é a “senha” do seu aplicativo. Nunca pode vazar e deve ser usada apenas no backend. Se outra pessoa obtiver seu client_secret, poderá se passar pelo aplicativo para acessar dados de usuários.

  • redirect_uri: indica para qual endereço o Google deve enviar o usuário depois da autorização. Essa URL precisa ser cadastrada antes no Google Cloud Console e é validada de forma rigorosa. Até uma barra extra pode gerar erro — sim, é o irritante redirect_uri_mismatch.

  • state: uma string aleatória usada para evitar ataques CSRF. Você gera o state ao iniciar a autorização, e o Google o devolve sem alterações. É preciso comparar o valor recebido com o enviado; se forem diferentes, a solicitação pode ter sido falsificada.

  • code: é o código de autorização temporário. Ele expira em cerca de dez minutos e só pode ser usado uma vez. Serve para comprovar que “o usuário autorizou o acesso no Google”.

  • access_token: é o “passe” de verdade. Com ele, seu site pode consultar dados no Google em nome do usuário. O access_token também expira, geralmente depois de uma hora ou de alguns dias, dependendo do provedor.

Por que existem duas etapas, uma para o code e outra para o access_token?

Talvez você se pergunte por que o Google não devolve logo o access_token, em vez de exigir uma troca intermediária.

O motivo é segurança. O code passa por um redirecionamento do navegador e fica visível no frontend, enquanto o access_token é transmitido diretamente entre servidores, sem aparecer no navegador. Se o token fosse retornado na URL, ele poderia vazar pelo histórico, pelos logs ou por ferramentas de monitoramento de rede. A troca do código pelo token exige o client_secret, que existe apenas no backend, tornando o processo muito mais seguro.

Como configurar login com Google usando Next.js e NextAuth.js

Por que escolher NextAuth.js?

Implementar todo o fluxo OAuth por conta própria dá bastante trabalho: você precisa processar callbacks, gerenciar sessões, evitar ataques CSRF, armazenar tokens e cuidar de vários outros detalhes.

A boa notícia é que existe uma biblioteca chamada NextAuth.js — agora conhecida como Auth.js v5 — feita especificamente para isso. Ela tem mais de 15 mil estrelas no GitHub, uma comunidade ativa e suporte a mais de 50 provedores OAuth, incluindo Google, GitHub, WeChat e Twitter. A versão mais recente funciona com o App Router do Next.js 14+ e é mais simples de configurar do que as anteriores.

Em resumo, NextAuth.js elimina cerca de 80% do trabalho repetitivo.

Primeira etapa: criar um aplicativo no Google Cloud

Antes de escrever código, você precisa “cadastrar” seu aplicativo no Google e obter um client_id e um client_secret.

  1. Abra o Google Cloud Console e entre com sua conta Google.

  2. Se nunca usou a plataforma, crie primeiro um projeto. O nome pode ser qualquer um, como “My Next.js App”.

  3. No menu lateral, acesse “APIs e serviços” → “Credenciais”.

  4. Clique em “Criar credenciais” e selecione “ID do cliente OAuth”.

  5. No primeiro acesso, talvez seja necessário configurar a “Tela de consentimento OAuth”. Informe o nome do aplicativo e um e-mail de suporte; o restante pode ficar para depois. Escolha o tipo de usuário “Externo”. Durante os testes, não é necessário passar pela verificação.

  6. Volte à criação do ID de cliente OAuth e selecione “Aplicativo da Web” como tipo de aplicativo.

  7. Este é o ponto mais importante: configure as “URIs de redirecionamento autorizadas”. Adicione estes dois endereços:

    • Desenvolvimento local: http://localhost:3000/api/auth/callback/google
    • Produção, depois da implantação: https://yourdomain.com/api/auth/callback/google

    A URL precisa ser exatamente igual à usada no código. Uma barra a mais ou a menos já provoca o erro redirect_uri_mismatch. Eu mesmo tropecei nisso na primeira configuração.

  8. Clique em “Criar”. Uma janela exibirá o Client ID e o Client Secret. Copie os dois valores para usá-los em seguida.

Segunda etapa: instalar NextAuth.js e configurar as variáveis de ambiente

No projeto Next.js, instale o pacote:

npm install next-auth@beta

É importante usar a versão @beta, que corresponde à v5 mais recente.

Depois, crie o arquivo .env.local na raiz do projeto e preencha o Client ID e o Secret obtidos anteriormente:

GOOGLE_CLIENT_ID=seu_Client_ID.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=seu_Client_Secret
NEXTAUTH_SECRET=gere_uma_string_aleatória
NEXTAUTH_URL=http://localhost:3000

Você pode gerar o NEXTAUTH_SECRET com este comando:

openssl rand -base64 32

Ao implantar em produção, lembre-se de trocar o NEXTAUTH_URL pelo seu domínio.

Terceira etapa: criar o arquivo de configuração do NextAuth

Crie app/api/auth/[...nextauth]/route.ts. Se o projeto usa Pages Router, o caminho é pages/api/auth/[...nextauth].ts:

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

export const authOptions = {
  providers: [
    GoogleProvider({
      clientId: process.env.GOOGLE_CLIENT_ID!,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
    }),
  ],
  callbacks: {
    async signIn({ user, account, profile }) {
      // Callback executado após o login; você pode salvar o usuário no banco aqui
      console.log("Login do usuário:", user)
      return true // true permite o login
    },
    async session({ session, token }) {
      // Personaliza o conteúdo da sessão
      if (session.user) {
        session.user.id = token.sub // Adiciona o ID do usuário à sessão
      }
      return session
    },
  },
}

const handler = NextAuth(authOptions)
export { handler as GET, handler as POST }

Pronto. NextAuth.js processa automaticamente todo o fluxo OAuth. A rota /api/auth/callback/google também é criada pela biblioteca, então você não precisa implementá-la.

Quarta etapa: criar o botão de login

Em qualquer componente, você pode criar o botão desta forma:

'use client' // O App Router exige que este seja um Client Component

import { signIn, signOut, useSession } from "next-auth/react"

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

  if (session) {
    // O usuário está autenticado
    return (
      <div>
        <p>Olá, {session.user?.name}</p>
        <img src={session.user?.image || ''} alt="Foto de perfil" />
        <button onClick={() => signOut()}>Sair</button>
      </div>
    )
  }

  // O usuário não está autenticado
  return <button onClick={() => signIn('google')}>Entrar com Google</button>
}

signIn('google') redireciona automaticamente para a página de autorização do Google. Depois da autorização, o usuário volta ao site já autenticado. É bem simples.

Quinta etapa: envolver o layout raiz com SessionProvider

Para usar useSession em todos os componentes, envolva o conteúdo do layout raiz com o Provider:

// 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>
  )
}

Tudo pronto. Agora você tem um aplicativo Next.js com login pelo Google.

Solução de problemas comuns

Problema 1: redirect_uri_mismatch

Esse é o erro mais comum, e eu também o encontrei na primeira configuração.

A mensagem costuma ser: Error 400: redirect_uri_mismatch.

Causa: a URL de callback cadastrada no Google Cloud Console não corresponde à URL usada na solicitação.

Solução:

  1. Confirme se a “URI de redirecionamento autorizada” no Google Cloud Console é http://localhost:3000/api/auth/callback/google e verifique se não há uma barra extra.
  2. Confirme se NEXTAUTH_URL no .env.local é http://localhost:3000.
  3. Se você mudou a porta, por exemplo para 3001, altere-a nos dois lugares.

Problema 2: funciona no desenvolvimento local, mas o login falha depois da implantação

Eu também já passei por isso. Localmente, o login funcionava perfeitamente; depois da implantação na Vercel, o botão não fazia nada ou retornava um erro.

Causa: as variáveis de ambiente de produção não foram atualizadas.

Solução:

  1. Adicione a URL do domínio de produção às “URIs de redirecionamento autorizadas” no Google Cloud Console: https://yourdomain.com/api/auth/callback/google.
  2. Nas configurações de variáveis de ambiente da Vercel, ou da sua plataforma de hospedagem, defina NEXTAUTH_URL como https://yourdomain.com.
  3. Faça uma nova implantação.

Problema 3: a session continua null depois do login

Se useSession() sempre retorna uma session nula, verifique se você esqueceu de envolver o layout raiz com <SessionProvider>.

Problema 4: TypeError: Cannot read property ‘user’ of null

Normalmente, isso acontece porque a session ainda está carregando quando o código tenta acessar session.user.

Solução: confirme primeiro se a session existe:

const { data: session, status } = useSession()

if (status === 'loading') {
  return <div>Carregando...</div>
}

if (!session) {
  return <div>Não autenticado</div>
}

// Agora é seguro acessar session.user

Configuração do login com GitHub e principais diferenças

Depois de configurar o Google, adicionar o GitHub fica bem mais fácil. Ainda assim, existem algumas diferenças importantes entre os dois.

Diferenças entre o OAuth do GitHub e o do Google

O que eles têm em comum: ambos usam o fluxo padrão de código de autorização do OAuth 2.0, com as mesmas etapas gerais.

As diferenças:

  1. Controle de permissões mais detalhado: o scope do GitHub é mais específico que o do Google. Por padrão, o aplicativo acessa apenas dados públicos. Para obter o e-mail do usuário, especialmente se for privado, é preciso solicitar a permissão user:email.
  2. Configuração de callback mais flexível: o Google exige a URL completa de callback; no GitHub, a configuração é menos rígida.
  3. Tipos de aplicativo: o GitHub permite OAuth Apps associados a contas pessoais ou organizações.

Primeira etapa: criar um OAuth App no GitHub

  1. Entre no GitHub, clique na foto de perfil no canto superior direito e acesse Settings. No menu lateral, abra “Developer settings”.

  2. Clique em “OAuth Apps” → “New OAuth App”.

  3. Preencha os dados do aplicativo:

    • Application name: nome do aplicativo, que aparecerá na tela de autorização
    • Homepage URL: página inicial do site, como http://localhost:3000
    • Authorization callback URL: use http://localhost:3000/api/auth/callback/github
  4. Clique em “Register application”, depois em “Generate a new client secret” e copie o Client ID e o Client Secret.

Segunda etapa: configurar as variáveis de ambiente

Adicione a configuração do GitHub ao .env.local:

GITHUB_CLIENT_ID=seu_GitHub_Client_ID
GITHUB_CLIENT_SECRET=seu_GitHub_Client_Secret

Terceira etapa: atualizar a configuração do NextAuth

No arquivo route.ts criado anteriormente, adicione GitHubProvider:

import NextAuth from "next-auth"
import GoogleProvider from "next-auth/providers/google"
import GitHubProvider from "next-auth/providers/github"

export const authOptions = {
  providers: [
    GoogleProvider({
      clientId: process.env.GOOGLE_CLIENT_ID!,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
    }),
    GitHubProvider({
      clientId: process.env.GITHUB_CLIENT_ID!,
      clientSecret: process.env.GITHUB_CLIENT_SECRET!,
      // Para obter o e-mail privado do usuário, adicione esta configuração
      authorization: {
        params: {
          scope: 'read:user user:email'
        }
      }
    }),
  ],
  callbacks: {
    // ... callbacks anteriores
  },
}

const handler = NextAuth(authOptions)
export { handler as GET, handler as POST }

Quarta etapa: atualizar os botões de login

Adicione a opção de login com GitHub ao componente:

return (
  <div>
    <button onClick={() => signIn('google')}>Entrar com Google</button>
    <button onClick={() => signIn('github')}>Entrar com GitHub</button>
  </div>
)

Pronto.

Entendendo o scope, ou escopo de permissões

O scope do GitHub controla quais dados do usuário seu aplicativo pode acessar. Os mais usados são:

  • read:user: lê dados públicos e privados do perfil, como nome, foto e bio
  • user:email: lê os e-mails do usuário, inclusive os privados
  • public_repo: acessa os repositórios públicos do usuário
  • repo: acessa todos os repositórios, públicos e privados; é uma permissão ampla e deve ser usada com cuidado

Para um fluxo de login, read:user user:email é suficiente.

Sem o scope user:email, NextAuth.js só obtém o e-mail público. Se o usuário ocultou o endereço nas configurações do GitHub, session.user.email será null. Passei um bom tempo tentando descobrir se havia algo errado no meu código por causa disso.

Um detalhe importante: o usuário do GitHub pode não ter e-mail público

Ao contrário do Google, que exige um e-mail, o GitHub permite ocultá-lo. Se seu aplicativo depende do endereço, por exemplo para enviar notificações, verifique-o no callback signIn:

async signIn({ user, account }) {
  if (account?.provider === 'github' && !user.email) {
    // O usuário não forneceu um e-mail público; você pode recusar o login ou avisá-lo
    console.log("Usuário do GitHub sem e-mail")
    return false // Recusa o login
  }
  return true
}

Configuração do login com WeChat: particularidades do mercado chinês

Agora vamos falar sobre o WeChat. Para ser sincero, esse login é bem mais complexo que Google e GitHub, principalmente porque o ecossistema funciona de outra maneira.

Por que o login com WeChat é diferente?

Estas são as principais diferenças:

  1. Exige leitura de QR code: em sites para desktop, o usuário precisa abrir o WeChat no celular e ler um QR code para autorizar o acesso. Não basta clicar em uma página como no Google ou GitHub.
  2. Não existe Provider oficial no NextAuth.js: NextAuth.js não inclui um provider para WeChat, então você precisa criar um.
  3. Há mais restrições para o callback: o WeChat exige um domínio de callback com registro ICP e não aceita localhost, o que dificulta os testes locais.
  4. Existem openid e unionid: a identificação do usuário funciona de forma particular. O mesmo usuário recebe um openid diferente em cada aplicativo. Para compartilhar dados entre vários aplicativos, é necessário usar o unionid.

Primeira etapa: cadastrar-se na WeChat Open Platform

  1. Acesse a WeChat Open Platform e crie uma conta.

  2. Crie um “aplicativo para sites”. Não se trata de uma conta oficial nem de um Mini Program.

  3. Preencha os dados do site, envie capturas de tela e aguarde a análise. O processo normalmente leva de um a três dias úteis.

  4. Depois da aprovação, você receberá um AppID e um AppSecret, equivalentes a client_id e client_secret.

  5. Na área de informações de desenvolvimento, configure o domínio de callback autorizado. Informe apenas o domínio, sem o caminho completo, por exemplo yourdomain.com.

Segunda etapa: criar um Provider personalizado para WeChat

Como NextAuth.js não inclui um provider para WeChat, precisamos criá-lo. Adicione o arquivo lib/wechat-provider.ts ao projeto:

import type { OAuthConfig, OAuthUserConfig } from "next-auth/providers"

export interface WeChatProfile {
  openid: string
  nickname: string
  headimgurl: string
  sex: number
  province: string
  city: string
  country: string
  unionid?: string
}

export default function WeChatProvider<P extends WeChatProfile>(
  options: OAuthUserConfig<P>
): OAuthConfig<P> {
  return {
    id: "wechat",
    name: "WeChat",
    type: "oauth",
    
    // URL de autorização do WeChat para aplicativos de sites em desktop
    authorization: {
      url: "https://open.weixin.qq.com/connect/qrconnect",
      params: {
        scope: "snsapi_login",
        appid: options.clientId,
        response_type: "code",
      },
    },
    
    // URL para trocar o código de autorização pelo access_token
    token: {
      url: "https://api.weixin.qq.com/sns/oauth2/access_token",
      params: {
        appid: options.clientId,
        secret: options.clientSecret,
        grant_type: "authorization_code",
      },
    },
    
    // URL para obter os dados do usuário
    userinfo: {
      url: "https://api.weixin.qq.com/sns/userinfo",
      async request({ tokens, provider }) {
        const res = await fetch(
          `${provider.userinfo?.url}?access_token=${tokens.access_token}&openid=${tokens.openid}&lang=zh_CN`
        )
        return await res.json()
      },
    },
    
    // Converte os dados do WeChat para o formato padrão do NextAuth
    profile(profile) {
      return {
        id: profile.openid,
        name: profile.nickname,
        email: null, // O WeChat não fornece e-mail
        image: profile.headimgurl,
      }
    },
    
    options,
  }
}

Terceira etapa: configurar as variáveis de ambiente

Adicione as configurações do WeChat ao .env.local:

WECHAT_CLIENT_ID=seu_AppID_do_WeChat
WECHAT_CLIENT_SECRET=seu_AppSecret_do_WeChat

Quarta etapa: usar o Provider no NextAuth

Atualize route.ts:

import WeChatProvider from "@/lib/wechat-provider"

export const authOptions = {
  providers: [
    GoogleProvider({...}),
    GitHubProvider({...}),
    WeChatProvider({
      clientId: process.env.WECHAT_CLIENT_ID!,
      clientSecret: process.env.WECHAT_CLIENT_SECRET!,
    }),
  ],
}

Quinta etapa: como testar no ambiente local?

Esse é um ponto complicado. Como o WeChat não aceita localhost como domínio de callback, não é possível testar a integração localmente de forma direta.

Existem duas alternativas:

Opção 1: usar uma ferramenta de túnel

Use ngrok ou cpolar para expor o serviço local à internet:

# Instale o ngrok
brew install ngrok

# Inicie o túnel para o serviço local
ngrok http 3000

O ngrok fornecerá um domínio temporário, como https://abc123.ngrok.io. Cadastre esse domínio como domínio de callback na WeChat Open Platform e atualize o NEXTAUTH_URL no .env.local:

NEXTAUTH_URL=https://abc123.ngrok.io

Opção 2: configurar o arquivo hosts

Adicione esta linha ao arquivo hosts local — /etc/hosts no macOS e Linux ou C:\Windows\System32\drivers\etc\hosts no Windows:

127.0.0.1 dev.yourdomain.com

Depois, acesse http://dev.yourdomain.com:3000 e cadastre dev.yourdomain.com como domínio de callback na WeChat Open Platform.

Essa opção tem uma limitação: o WeChat exige que o domínio de callback tenha registro ICP, portanto dev.yourdomain.com ainda pode ser recusado. Na prática, a primeira opção é mais confiável.

Tratamento específico do login com WeChat

O WeChat não fornece o e-mail do usuário. Se seu aplicativo depende dessa informação, será necessário tratar o caso separadamente:

async signIn({ user, account }) {
  if (account?.provider === 'wechat') {
    // O usuário do WeChat não tem e-mail; você pode pedir que ele o informe
    // Outra opção é usar o openid como identificador único no banco de dados
    console.log("openid do usuário do WeChat:", user.id)
  }
  return true
}

Boas práticas de segurança para evitar erros comuns

Depois de configurar o login OAuth, ainda há alguns detalhes de segurança importantes. Aprendi muitos deles da maneira difícil.

1. Nunca exponha o client_secret

Forma errada:

// ❌ Nunca faça isso!
const clientSecret = "abc123def456" // Valor fixo no código

Se você colocar o client_secret no frontend ou enviá-lo para um repositório Git, outra pessoa poderá se passar pelo seu aplicativo e acessar dados dos usuários.

Forma correta:

  • Armazene-o em uma variável de ambiente e inclua .env.local no .gitignore
  • Use o client_secret apenas no backend. A API route do NextAuth.js roda no servidor, portanto é apropriada
  • Em produção, use o gerenciador de variáveis de ambiente da plataforma, como Settings → Environment Variables na Vercel

2. Para que serve o parâmetro state: proteção contra CSRF

O fluxo OAuth usa um parâmetro chamado state para evitar ataques CSRF.

Um possível ataque funciona assim: alguém cria um link malicioso com um código de autorização falsificado e tenta convencer você a clicar. Se o aplicativo não validar o state, poderá aceitar o código forjado e trocá-lo por um token.

A boa notícia é que NextAuth.js faz essa validação automaticamente, sem exigir código adicional.

Se você implementar OAuth manualmente, sem NextAuth.js:

  1. Gere um state aleatório ao iniciar a autorização e armazene-o na session ou em um cookie.
  2. No callback, confira se o state retornado é igual ao valor enviado.
  3. Recuse a solicitação se os valores forem diferentes.

3. Lista de URLs de callback permitidas

Cadastre no provedor OAuth — Google, GitHub ou WeChat — todas as URLs de callback que poderão ser usadas:

  • Ambiente de desenvolvimento: http://localhost:3000/api/auth/callback/[provider]
  • Ambiente de preview: https://preview.yourdomain.com/api/auth/callback/[provider]
  • Ambiente de produção: https://yourdomain.com/api/auth/callback/[provider]

Não use curingas, como https://*.yourdomain.com. Embora pareçam convenientes, eles reduzem a segurança. Liste explicitamente todos os domínios para evitar que um invasor explore uma URL inesperada.

4. Segurança no armazenamento de tokens

Por padrão, NextAuth.js usa JWT para armazenar a session, com o token salvo em um cookie HttpOnly. Essa é uma boa escolha:

  • HttpOnly: o JavaScript do frontend não consegue ler o cookie, o que ajuda a impedir o roubo do token em ataques XSS
  • Secure em produção: o cookie só é enviado por HTTPS, reduzindo o risco de interceptação

O que você deve fazer:

  • Não envie o access_token ao frontend. NextAuth.js não faz isso por padrão, e você também não deve adicioná-lo manualmente
  • Se precisar persistir dados do usuário, salve-os no banco no callback signIn e mantenha apenas o essencial na session, como ID e e-mail

5. Prazo de validade do código de autorização

O código de autorização do OAuth expira rapidamente, em cerca de dez minutos, e só pode ser usado uma vez.

Essa é uma medida de segurança: mesmo que alguém intercepte o code, talvez ele já tenha expirado ou já tenha sido usado quando o invasor tentar aproveitá-lo.

Se o usuário passar muito tempo na página de autorização, por exemplo porque foi tomar um café, o código pode expirar. NextAuth.js trata esse caso automaticamente e inicia uma nova autorização.

6. Checklist para o ambiente de produção

Antes da implantação, confira estes pontos:

  • Todas as variáveis de ambiente estão definidas (NEXTAUTH_URL, NEXTAUTH_SECRET e o client_id e client_secret de cada provider)?
  • NEXTAUTH_URL usa o domínio de produção, e não localhost?
  • As URLs de callback de produção foram cadastradas nos provedores OAuth?
  • .env.local está no .gitignore, garantindo que os secrets não sejam enviados ao Git?
  • O NEXTAUTH_SECRET de produção foi gerado aleatoriamente, sem reutilizar o valor do ambiente de desenvolvimento?

Resumo

Depois de tantos detalhes, vamos recapitular.

OAuth funciona essencialmente como um “passe temporário”: você não entrega sua senha a um aplicativo terceiro; apenas o autoriza a obter do provedor OAuth uma credencial com prazo de validade e permissões limitadas, o access_token. O processo acontece em duas partes: primeiro, o code comprova que o usuário autorizou o acesso; depois, o backend troca code + client_secret pelo token real.

No Next.js, Google é a opção mais simples e o melhor ponto de partida. GitHub exige um pouco mais de atenção, principalmente ao scope e à possibilidade de o usuário não ter um e-mail público. WeChat é o caso mais particular: usa QR code, exige um provider personalizado e um domínio de callback com registro ICP, além de tornar os testes locais mais trabalhosos.

Em segurança, lembre-se de três princípios:

  1. Use o client_secret apenas no backend e nunca o exponha.
  2. Sempre valide o parâmetro state — NextAuth.js faz isso para você.
  3. Use uma lista explícita de URLs de callback, sem curingas.

Se esta é sua primeira configuração OAuth, recomendo começar pelo Google e seguir o código deste artigo etapa por etapa. Ver o login funcionar pela primeira vez dá uma ótima sensação.

Se surgir algum problema, não entre em pânico: em 90% dos casos, a causa é uma URL redirect_uri incorreta ou uma variável de ambiente ausente. Revise esses pontos e, normalmente, tudo volta a funcionar.

Por fim, consulte a documentação oficial do NextAuth.js para conhecer recursos avançados, como armazenamento de sessões no banco de dados, páginas de login personalizadas e configuração de JWT. A especificação oficial do OAuth 2.0, RFC 6749, também vale a leitura. Quando você entende o princípio, fica muito mais fácil diagnosticar novos problemas.

Agora é sua vez. Boa configuração!

Fluxo completo para configurar login OAuth de terceiros no Next.js

Configure do zero o login de terceiros com Google, GitHub e WeChat

⏱️ Estimated time: 2 hr

  1. 1

    Step 1: Instalar e inicializar o NextAuth.js

    Instale a dependência:
    • npm install next-auth
    • Crie app/api/auth/[...nextauth]/route.ts

    Configuração básica:
    • Defina NEXTAUTH_URL (local: http://localhost:3000; produção: domínio real)
    • Defina NEXTAUTH_SECRET (gere uma string aleatória)
    • Configure o array básico de providers
  2. 2

    Step 2: Configurar o login com Google

    Etapas:
    1. Acesse o Google Cloud Console
    2. Crie um ID de cliente OAuth
    3. Defina a URI de callback autorizada: http://localhost:3000/api/auth/callback/google
    4. Obtenha o Client ID e o Client Secret
    5. Adicione às variáveis de ambiente: GOOGLE_CLIENT_ID e GOOGLE_CLIENT_SECRET
    6. Adicione GoogleProvider à configuração do NextAuth

    Atenção: a URL de callback em produção precisa ser exatamente igual à cadastrada
  3. 3

    Step 3: Configurar o login com GitHub

    Etapas:
    1. Acesse GitHub Settings > Developer settings > OAuth Apps
    2. Crie um novo OAuth App
    3. Defina a Authorization callback URL: http://localhost:3000/api/auth/callback/github
    4. Obtenha o Client ID e o Client Secret
    5. Adicione às variáveis de ambiente: GITHUB_CLIENT_ID e GITHUB_CLIENT_SECRET
    6. Adicione GitHubProvider à configuração do NextAuth

    Atenção: o scope precisa incluir user:email para obter o e-mail
  4. 4

    Step 4: Configurar o login com WeChat (opcional)

    Etapas:
    1. Cadastre uma conta na WeChat Open Platform (exige verificação empresarial)
    2. Crie um aplicativo para sites e obtenha AppID e AppSecret
    3. Defina o domínio de callback autorizado (o domínio precisa ter registro ICP)
    4. Crie um Provider personalizado (o NextAuth não inclui WeChat)
    5. Implemente o fluxo de login por QR code

    Atenção: o login com WeChat é mais complexo; conclua primeiro Google e GitHub
  5. 5

    Step 5: Criar a página e os botões de login

    Crie o componente de login:
    • Use signIn('google') para iniciar o login
    • Use signOut() para sair
    • Use useSession() para obter os dados do usuário
    • Envolva o aplicativo com SessionProvider

    Exemplo:
    <button onClick={() => signIn('google')}>
    Entrar com Google
    </button>
  6. 6

    Step 6: Testar e depurar

    Pontos de teste:
    • Teste local: confirme que a URL de callback é http://localhost:3000
    • Produção: confirme que a URL de callback corresponde ao domínio real
    • Verifique se as variáveis de ambiente estão corretas
    • Consulte o console do navegador e os logs do servidor

    Erros comuns:
    • redirect_uri_mismatch: a URL de callback não corresponde
    • invalid_client: Client ID ou Secret incorreto
    • access_denied: o usuário recusou a autorização

FAQ

Como funciona o OAuth 2.0?
O OAuth 2.0 permite que o usuário autorize um aplicativo terceiro a acessar seus recursos sem fornecer a senha. O fluxo é: o usuário clica para entrar → é redirecionado ao provedor OAuth → concede a autorização → recebe um código de autorização → o código é trocado por um access_token → o token é usado para obter os dados do usuário.
Como resolver o erro redirect_uri_mismatch?
Esse erro indica que as URLs de callback não correspondem.

Solução:
1) Confirme que a URL cadastrada no provedor OAuth é exatamente igual à usada no código, incluindo protocolo, domínio, porta e caminho
2) No desenvolvimento local, use http://localhost:3000; em produção, use o domínio real
3) Verifique se há barras ou parâmetros extras
Qual é a diferença entre usar NextAuth.js e implementar OAuth manualmente?
NextAuth.js é uma solução pronta para OAuth:
• Oferece suporte a mais de 50 provedores
• Cuida automaticamente do fluxo de autorização, da sessão e da proteção contra CSRF

Na implementação manual, você precisa cuidar de:
• Troca do código de autorização
• Armazenamento do token
• Validação do state, entre outros detalhes

Isso exige mais código e aumenta o risco de erro, por isso é recomendável usar NextAuth.js.
Como obter o endereço de e-mail do usuário?
Cada provedor trata o e-mail de uma forma:
• Google: retorna o e-mail por padrão
• GitHub: exige user:email no scope, e o usuário precisa deixar o e-mail público
• WeChat: exige uma consulta por unionid

Se o e-mail não estiver disponível, você pode pedir que o usuário o informe depois do login.
Por que tudo funciona localmente, mas ocorre um erro em produção?
Geralmente, o problema está na configuração da URL de callback.

Verifique:
1) Se NEXTAUTH_URL está correto em produção
2) Se a URL de callback cadastrada no provedor OAuth inclui o domínio de produção
3) Se as variáveis de ambiente estão configuradas corretamente
4) Se algum firewall ou proxy está interferindo
É possível oferecer vários métodos de login ao mesmo tempo?
Sim. NextAuth.js permite configurar vários providers, e o usuário pode escolher Google, GitHub, WeChat ou outro método disponível. Basta indicar o nome do provider na função signIn().
O login OAuth é seguro?
OAuth 2.0 é um padrão do setor e oferece um bom nível de segurança.

Ainda assim, é preciso tomar alguns cuidados:
1) O client_secret deve permanecer confidencial e ser usado apenas no servidor
2) Use o parâmetro state para evitar ataques CSRF (NextAuth.js faz isso automaticamente)
3) Use uma lista de URLs de callback permitidas, sem curingas
4) Atualize as dependências regularmente

21 min de leitura · Publicado em: 19 dez 2025 · Atualizado em: 4 set 2026

Comentários

Entre com GitHub para comentar

Easton BlogEaston Blog