Alternar tema

Login OAuth no Next.js: integração passo a passo com Google, GitHub e WeChat

Easton editorial illustration: monorepo project desk

Na semana passada, participei de um projeto de comunidade e o gerente de produto soltou: “Adicione login com o Google; deve ser rápido.” Pensei que seria apenas mais um login de terceiros. Já tinha lido alguns tutoriais e não parecia difícil. No fim, passei a tarde inteira configurando: erros de redirect_uri, falhas ao obter o token e uma sequência interminável de mensagens vermelhas no console. O pior era seguir a documentação oficial passo a passo e, mesmo assim, nada funcionar.

Depois percebi que o problema não estava no código, mas na minha compreensão superficial do fluxo OAuth. Eu entendia isoladamente conceitos como authorization code, access token e callback, mas me confundia quando precisava juntá-los.

Neste artigo, vou explicar o OAuth em linguagem simples. Em vez de repetir as descrições abstratas de um RFC, usarei a situação cotidiana de um amigo retirando uma encomenda para você. Assim, fica mais fácil entender por que existem code e token, qual é a função do callback e quais detalhes de configuração costumam causar erros. Depois, configuraremos três formas de login passo a passo: Google, o padrão internacional; GitHub, amigável para desenvolvedores; e WeChat, indispensável na China, mas também o mais trabalhoso.

Sendo sincero, o login com WeChat é a parte mais complicada: a documentação não é amigável, é necessária qualificação empresarial e os testes locais dão trabalho. Como ele é difícil de evitar em projetos voltados ao mercado chinês, reuni aqui os problemas que enfrentei, incluindo como depurar com um túnel de rede e como configurar um Provider personalizado. Ao final, você terá uma arquitetura de código capaz de atender logins nacionais e internacionais.

Como o fluxo OAuth realmente funciona

Entenda o OAuth com a retirada de uma encomenda

Quando conheci o OAuth, termos como authorization code e access token pareciam complicados. Depois entendi que a lógica é semelhante à de pedir para alguém retirar uma encomenda em seu lugar.

Imagine que há uma encomenda sua — os dados do usuário — em um ponto de retirada, mas você está no trabalho e não pode buscá-la. Um amigo — seu aplicativo Next.js — se oferece para fazer isso. O ponto não pode entregar o pacote a qualquer pessoa: precisa confirmar que você autorizou a retirada. O fluxo fica assim:

1. Você entrega ao amigo um código de retirada — esse é o authorization code. Ao clicar em “Entrar com o Google”, você é redirecionado à página de autorização do Google. Depois de aceitar, o Google gera um code temporário e o envia ao aplicativo como parâmetro da URL.

2. O amigo leva o código ao ponto de retirada — o backend do seu aplicativo troca o code por um access token. O ponto também precisa confirmar que esse amigo é realmente alguém em quem você confia, por isso você já cadastrou o número do documento dele, o client_secret.

3. Depois de confirmar a identidade, o ponto entrega a encomenda — quando código e documento estão corretos, o ponto entrega o pacote, isto é, os dados do usuário, ao amigo, que então o entrega a você. Esse é o processo de obter os dados do usuário com o access_token.

O ponto central é este: o código de retirada, o code, só pode ser usado uma vez. Mesmo que outra pessoa o veja, ele não serve sem o documento, o secret. Por isso, o code pode trafegar de forma visível na URL do navegador, enquanto o secret precisa permanecer no backend.

As quatro etapas essenciais

No fluxo técnico, são quatro etapas.

Etapa 1: redirecionar para a página de autorização do servidor OAuth

Quando o usuário clica em “Entrar com o Google”, o frontend monta uma URL e o redireciona ao Google:

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

Os principais parâmetros são:

  • client_id: a identidade do seu aplicativo no Google
  • redirect_uri: para onde o Google deve mandar o usuário depois da autorização
  • scope: quais dados do usuário você quer acessar

Etapa 2: o usuário autoriza e recebe o code

Depois que o usuário clica em “Permitir” na página do Google, o serviço o redireciona de volta ao aplicativo. A URL fica assim:

http://localhost:3000/api/auth/callback/google?code=4/0AfJohXl...&state=random123

Esse code é o código de retirada. Ele expira rapidamente, em geral dentro de 5 a 10 minutos, e só pode ser usado uma vez.

Etapa 3: o backend troca o code por um access_token

O backend do aplicativo — atenção: o backend, não o frontend — envia o code junto com o client_secret ao Google:

const response = await fetch('https://oauth2.googleapis.com/token', {
  method: 'POST',
  body: JSON.stringify({
    code: 'code_obtido_agora',
    client_id: 'your_client_id',
    client_secret: 'your_secret', // Nunca exponha isso no frontend
    redirect_uri: 'http://localhost:3000/api/auth/callback/google',
    grant_type: 'authorization_code'
  })
})

const { access_token } = await response.json()

O access_token é a verdadeira chave que permite obter os dados do usuário.

Etapa 4: usar o access_token para obter os dados do usuário

Com o token, você pode chamar a API do Google:

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

const user = await userInfo.json()
// { email: "[email protected]", name: "Zhang San", picture: "URL_do_avatar" }

Com esses dados, você pode criar ou atualizar o registro do usuário no seu banco, gerar uma session e concluir o login.

Tabela de consulta rápida

Organizei os termos mais comuns para facilitar a consulta:

TermoExplicação simplesOnde aparece
Client IDIdentidade pública do seu aplicativoArquivo .env.local e parâmetros da URL no navegador
Client SecretSenha do aplicativo, que deve permanecer secretaApenas no código do backend e nas variáveis de ambiente
Authorization CodeCódigo de retirada de uso únicoParâmetro code na URL de callback
Access TokenChave que realmente permite obter os dadosNo código do backend; não deve ser enviado ao frontend
Redirect URIEndereço de retorno depois da autorizaçãoConfiguração do aplicativo OAuth e parâmetros da URL de autorização
ScopeConjunto de permissões solicitadasParâmetros da URL de autorização, como “email profile”
StateString aleatória usada contra ataques CSRFParâmetros das URLs de autorização e callback

Para que serve o parâmetro State? Ao iniciar a autorização, o aplicativo gera uma string aleatória, como “abc123”, salva-a na session e a envia ao servidor OAuth. No callback, verifica se o state devolvido também é “abc123”. Se não for, pode ser um ataque, e a solicitação é recusada. O NextAuth.js cuida disso automaticamente.

Por que não retornar o token diretamente?

Você pode se perguntar: se o objetivo final é obter o access_token, por que não devolvê-lo diretamente na URL? Por que criar uma etapa extra para trocar code por token?

Por segurança.

A URL na barra de endereços do navegador fica visível e pode aparecer no histórico, nos logs do servidor e para extensões do navegador. Retornar o token diretamente seria como divulgar em texto puro a chave dos dados do usuário, o que cria um risco grande.

Mesmo que um invasor intercepte o code, ele não consegue usá-lo sozinho, porque:

  1. O code só pode ser usado uma vez e perde a validade depois disso
  2. A troca pelo token também exige o client_secret, conhecido apenas pelo backend
  3. O servidor OAuth ainda verifica se o redirect_uri corresponde ao cadastrado

Assim, sem o secret, um invasor não consegue trocar o code pelo token e os dados do usuário continuam protegidos.

Esse modelo se chama “Authorization Code Flow”. É um dos fluxos mais seguros do OAuth 2.0 e é especialmente adequado a aplicativos Web com servidor backend. Também existe o “Implicit Flow”, que devolve o token diretamente, mas ele deixou de ser recomendado por ser pouco seguro.

Primeiros passos com NextAuth.js

Por que escolher NextAuth.js

Há várias maneiras de implementar login OAuth no Next.js. Você pode escrever tudo manualmente ou usar uma biblioteca. Eu tentei fazer por conta própria, encontrei incontáveis problemas e acabei migrando para o NextAuth.js.

Veja por que o recomendo.

Motivo 1: recomendado oficialmente e com ecossistema maduro

O NextAuth.js é uma solução de autenticação recomendada na documentação oficial do Next.js, tem mais de 70 mil estrelas no GitHub e é mantido ativamente. A versão v5, lançada em novembro de 2024, oferece suporte completo ao App Router e aos Server Components, sem preocupações de compatibilidade.

Motivo 2: mais de 30 provedores OAuth integrados

Google, GitHub, Facebook, Twitter e outros serviços comuns funcionam praticamente de imediato, com poucas linhas de configuração. Para provedores como o WeChat, que não vêm integrados, há um mecanismo de Provider personalizado, sem a necessidade de escrever todo o fluxo OAuth do zero.

Motivo 3: processamento automático da lógica complexa

Gerenciamento de session, assinatura de JWT, armazenamento em banco e proteção contra CSRF são automáticos. Você pode se concentrar na lógica do produto, como decidir se deve enviar um e-mail de boas-vindas no primeiro login.

Estrutura do arquivo principal de configuração

O núcleo do NextAuth.js é uma API route. Com o App Router, disponível no Next.js 13 ou posterior, o caminho do arquivo é:

app/api/auth/[...nextauth]/route.ts

[...nextauth] é uma catch-all route do Next.js. Isso significa que todas as solicitações para /api/auth/* são tratadas pelo arquivo, incluindo:

  • /api/auth/signin — página de login
  • /api/auth/callback/google — callback do Google
  • /api/auth/signout — logout
  • /api/auth/session — consulta da session atual

A configuração básica é esta:

// app/api/auth/[...nextauth]/route.ts
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_ID!,
      clientSecret: process.env.GITHUB_SECRET!,
    }),
  ],
  // Opcional: página de login personalizada
  pages: {
    signIn: '/login',
  },
  // Opcional: callbacks para processar a lógica posterior ao login
  callbacks: {
    async signIn({ user, account, profile }) {
      // Você pode verificar aqui se o usuário está na lista de permissões
      return true // Retornar false impede o login
    },
    async session({ session, token }) {
      // Adicione informações extras à session
      session.user.id = token.sub
      return session
    },
  },
}

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

A última linha, export { handler as GET, handler as POST }, é importante: o App Router exige a exportação explícita dos handlers dos métodos HTTP.

Convenções de nomes das variáveis de ambiente

O NextAuth.js tem algumas particularidades nos nomes das variáveis de ambiente, especialmente na versão v5.

Variáveis de ambiente obrigatórias:

# .env.local

# Configuração do NextAuth
NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=your-secret-key-here

# Ou use o novo nome, recomendado na v5
AUTH_SECRET=your-secret-key-here

# Google OAuth
GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secret

# Ou use o prefixo AUTH_, reconhecido automaticamente pela v5
AUTH_GOOGLE_ID=your-google-client-id
AUTH_GOOGLE_SECRET=your-google-client-secret

# GitHub OAuth
GITHUB_ID=your-github-client-id
GITHUB_SECRET=your-github-client-secret

# Ou
AUTH_GITHUB_ID=your-github-client-id
AUTH_GITHUB_SECRET=your-github-client-secret

Alguns pontos importantes:

  1. NEXTAUTH_URL: a URL completa do aplicativo. No ambiente de desenvolvimento, use http://localhost:3000. Em produção, ela precisa ser seu domínio real, incluindo https.

  2. NEXTAUTH_SECRET / AUTH_SECRET: chave usada para assinar o JWT. Ela precisa ser uma string aleatória. Gere-a assim:

openssl rand -base64 32

Nunca divulgue esse valor nem o envie ao Git. Se ele vazar, troque-o imediatamente, pois outra pessoa poderia falsificar uma session.

  1. A convenção do prefixo AUTH_: o NextAuth.js v5 reconhece automaticamente variáveis no formato AUTH_PROVIDER_ID e AUTH_PROVIDER_SECRET. Assim, você não precisa escrever process.env.XXX no código.

Instalação e configuração mínima

Apesar de todos esses detalhes, começar é simples.

Etapa 1: instale

npm install next-auth
# ou
pnpm add next-auth

Etapa 2: crie a API route

Crie app/api/auth/[...nextauth]/route.ts e cole o código anterior.

Etapa 3: crie o .env.local

NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=string_gerada_por_openssl_rand_-base64_32

Etapa 4: adicione um botão de login ao frontend

// app/login/page.tsx
'use client'

import { signIn } from 'next-auth/react'

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

Etapa 5: envolva o aplicativo com o Provider

Para usar useSession() em Client Components, adicione um Provider:

// app/layout.tsx
import { SessionProvider } from 'next-auth/react'

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        <SessionProvider>
          {children}
        </SessionProvider>
      </body>
    </html>
  )
}

Com isso, o esqueleto básico está pronto. O botão ainda apresentará erro porque os aplicativos OAuth do Google e do GitHub não foram configurados. É o que faremos a seguir.

Configuração prática do login com Google

Configuração no Google Cloud Console

A configuração do OAuth do Google tem duas partes: criar o aplicativo OAuth no Google Cloud Console e integrá-lo ao Next.js.

Etapa 1: abra o Google Cloud Console

Acesse https://console.cloud.google.com com sua conta do Google. No primeiro acesso, o serviço pedirá que você crie um projeto. Escolha qualquer nome, como “Meu blog”.

Etapa 2: ative a Google+ API

Embora o Google+ tenha sido encerrado há muito tempo, o OAuth ainda depende dessa API. No menu à esquerda, acesse “APIs & Services” → “Library”, procure “Google+ API”, abra o resultado e clique em “Enable”.

Etapa 3: crie as credenciais OAuth

  • Abra “Credentials” no menu à esquerda
  • Clique em “Create Credentials” → “OAuth client ID”
  • No primeiro acesso, será necessário configurar a “OAuth consent screen”. Informe o nome do aplicativo e o e-mail de suporte; os demais campos podem ser ignorados inicialmente
  • Em Application type, selecione “Web application”
  • Em Name, use qualquer nome, como “Next.js App”

Etapa 4: configure as Redirect URIs — a parte mais importante

Esse é o ponto que mais causa erros. Em Authorized redirect URIs, informe dois endereços.

Ambiente de desenvolvimento:

http://localhost:3000/api/auth/callback/google

Ambiente de produção, quando a implantação estiver pronta:

https://yourdomain.com/api/auth/callback/google

Observe estes detalhes:

  • http versus https: use http no desenvolvimento local. Em produção, o Google exige https
  • Porta: se o projeto roda localmente na porta 3001, use localhost:3001; não omita a porta
  • Caminho: /api/auth/callback/google precisa estar absolutamente correto, sem barras extras ou ausentes
  • Não adicione parâmetros de consulta: termine em /google. O Google adicionará ?code=xxx automaticamente

Clique em “Create”. O Client ID e o Client Secret aparecerão em seguida; copie e guarde os dois.

Etapa 5: copie os valores para o .env.local

GOOGLE_CLIENT_ID=seu_Client_ID.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=GOCSPX-xxxxxxxxxxxx

Integração no código Next.js

Já adicionamos o GoogleProvider à configuração do NextAuth.js. Se as variáveis de ambiente estiverem corretas, ele funcionará. Ainda podemos aprimorar a configuração:

// app/api/auth/[...nextauth]/route.ts
import GoogleProvider from "next-auth/providers/google"

export const authOptions = {
  providers: [
    GoogleProvider({
      clientId: process.env.GOOGLE_CLIENT_ID!,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
      authorization: {
        params: {
          prompt: "consent",
          access_type: "offline",
          response_type: "code"
        }
      }
    }),
  ],
}

Os parâmetros de authorization.params fazem o seguinte:

  • prompt: "consent": mostra a página de autorização a cada login, o que facilita os testes. Em produção, você pode remover esse parâmetro; o Google lembrará a escolha do usuário
  • access_type: "offline": retorna um refresh token. Assim, depois do primeiro login, o token pode ser renovado mesmo com o usuário offline. Adicione essa opção apenas se precisar acessar dados do usuário por longos períodos
  • response_type: "code": define explicitamente o authorization code flow

Teste do fluxo de login

Inicie o Next.js:

npm run dev

Acesse http://localhost:3000/login e clique em “Entrar com o Google”. Você será redirecionado à página de autorização do Google. Depois de clicar em “Permitir”, deve voltar ao seu aplicativo.

Consulte a session em qualquer página:

// app/page.tsx
import { getServerSession } from "next-auth"
import { authOptions } from "./api/auth/[...nextauth]/route"

export default async function Home() {
  const session = await getServerSession(authOptions)

  if (session) {
    return <div>Olá, {session.user?.name}</div>
  }

  return <div>Você não entrou</div>
}

Ou faça isso em um Client Component:

'use client'
import { useSession } from "next-auth/react"

export default function Profile() {
  const { data: session, status } = useSession()

  if (status === "loading") return <div>Carregando...</div>
  if (!session) return <div>Você não entrou</div>

  return (
    <div>
      <img src={session.user?.image} alt="Avatar" />
      <p>{session.user?.name}</p>
      <p>{session.user?.email}</p>
    </div>
  )
}

Solução de erros comuns

Erro 1: redirect_uri_mismatch

Mensagem completa:

Error 400: redirect_uri_mismatch
The redirect URI in the request, http://localhost:3000/api/auth/callback/google,
does not match the ones authorized for the OAuth client.

Causa: a URI configurada no Google Console não corresponde exatamente à URI real do callback.

Como investigar:

  1. Abra as ferramentas do desenvolvedor do navegador e selecione a aba Network
  2. Clique no botão de login e examine a URL usada no redirecionamento ao Google
  3. Localize o parâmetro redirect_uri e copie o valor completo
  4. Volte ao Google Console e cole exatamente esse valor em Authorized redirect URIs
  5. Verifique o protocolo, http ou https, a porta, o caminho e possíveis barras extras

Erro 2: Access blocked: This app’s request is invalid

Esse erro indica que você não configurou a OAuth consent screen ou não adicionou usuários de teste.

Para resolver:

  • Volte ao Google Console → “OAuth consent screen”
  • Em User Type, selecione “External”, para publicação externa, ou “Internal”, para uso dentro da empresa
  • Preencha as informações do aplicativo
  • Se o tipo for External e o aplicativo ainda não estiver publicado, adicione o e-mail da sua conta de teste em “Test users”

Erro 3: problema com a porta

Se o ambiente local roda em localhost:3001, mas o redirect URI está configurado como localhost:3000, o erro também ocorrerá.

A solução mais simples é sempre usar a porta 3000 ou cadastrar vários redirect URIs no Google Console, um para cada porta, como 3000, 3001 e 3002.

Erro 4: exigência de HTTPS

Depois da implantação, o Google rejeitará o domínio se ele ainda usar http. Em produção, é obrigatório usar https. Plataformas como Vercel e Netlify fornecem https automaticamente.

Configuração do login com GitHub

Configuração do GitHub OAuth App

A configuração OAuth do GitHub é mais simples que a do Google. Não é necessário ativar uma API; basta criar um OAuth App.

Etapa 1: abra Developer settings

Entre no GitHub, clique no avatar no canto superior direito → Settings → role até o fim do menu à esquerda → Developer settings → OAuth Apps → New OAuth App.

Etapa 2: preencha os dados do aplicativo

  • Application name: escolha qualquer nome; os usuários não o verão
  • Homepage URL: em desenvolvimento local, use http://localhost:3000; em produção, use seu domínio
  • Authorization callback URL: use http://localhost:3000/api/auth/callback/github

A callback URL do GitHub é mais flexível e pode ser alterada depois, ao contrário da configuração rígida do Google.

Clique em Register application para gerar o Client ID. Depois, clique em “Generate a new client secret” para gerar o Secret. Ele só será exibido uma vez, portanto salve-o.

Etapa 3: copie os valores para o .env.local

GITHUB_ID=seu_Client_ID
GITHUB_SECRET=seu_Client_Secret

Integração no Next.js

Configuração do NextAuth.js:

import GitHubProvider from "next-auth/providers/github"

export const authOptions = {
  providers: [
    GitHubProvider({
      clientId: process.env.GITHUB_ID!,
      clientSecret: process.env.GITHUB_SECRET!,
    }),
  ],
}

É só isso; nenhuma configuração extra é necessária.

Diferenças entre GitHub e Google

ItemGoogleGitHub
Dificuldade da configuraçãoMédia; é preciso ativar uma APISimples; basta criar o aplicativo
Redirect URIRígido; deve corresponder exatamenteFlexível; aceita curingas
Exigência de HTTPSObrigatório em produçãolocalhost pode usar http
Configuração de ScopePrecisa ser informada explicitamenteO padrão costuma ser suficiente
Dados do usuárioemail, name, picturelogin, email, avatar_url

Um detalhe importante: o e-mail do GitHub pode ser null se o usuário ativou a proteção de privacidade do endereço. Faça essa verificação no código:

const userEmail = session.user?.email || 'E-mail não informado'

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

Três formas de login com WeChat

Esse é o ponto que mais causa confusão. O WeChat oferece três formas de login, cada uma para um cenário diferente:

Forma de loginCenárioRequisitosExperiência do usuário
Plataforma Aberta — aplicativo para siteSite independenteQualificação empresarial, domínio com registro ICP e HTTPSLogin por QR code, com suporte a PC
Autorização Web de conta oficialPágina H5 dentro do WeChatConta oficial verificadaApenas no navegador do WeChat
WeComSistema corporativo internoConta WeComApenas para funcionários da empresa

Aqui abordaremos a primeira opção: login de aplicativo para site na Plataforma Aberta, adequado a um site Next.js independente.

Configuração da Plataforma Aberta do WeChat

Pré-requisitos:

  • Licença comercial da empresa; desenvolvedores individuais não são aceitos
  • Domínio com registro ICP
  • Certificado HTTPS

Etapa 1: cadastre uma conta de desenvolvedor

Acesse https://open.weixin.qq.com, clique em “Registrar”, escolha o tipo “desenvolvedor de aplicativo para site”, envie a licença comercial e aguarde a análise, que costuma levar de 1 a 2 dias úteis.

Etapa 2: crie o aplicativo para site

Depois da aprovação, acesse o centro de gerenciamento → aplicativos para site → criar aplicativo para site e informe:

  • Nome do aplicativo
  • Descrição do aplicativo
  • Site oficial do aplicativo: seu domínio, que precisa ter registro ICP
  • Domínio de callback de autorização: informe apenas o domínio, sem protocolo nem caminho, como yourdomain.com

Ao contrário do Google e do GitHub, o WeChat solicita apenas o domínio, não a URL completa. Ele corresponderá automaticamente a todos os caminhos sob esse domínio.

Envie a solicitação e aguarde outra análise, que leva de 1 a 7 dias. Depois da aprovação, você receberá o AppID e o AppSecret.

Etapa 3: defina as variáveis de ambiente

WECHAT_APP_ID=seu_AppID
WECHAT_APP_SECRET=seu_AppSecret

Provider personalizado do NextAuth.js

O WeChat não tem um Provider integrado, então você precisa criar um. A boa notícia é que o NextAuth.js oferece um mecanismo próprio para isso:

// app/api/auth/[...nextauth]/route.ts

const WeChatProvider = {
  id: "wechat",
  name: "WeChat",
  type: "oauth",
  authorization: {
    url: "https://open.weixin.qq.com/connect/qrconnect",
    params: {
      appid: process.env.WECHAT_APP_ID,
      scope: "snsapi_login",
      response_type: "code",
    },
  },
  token: {
    url: "https://api.weixin.qq.com/sns/oauth2/access_token",
    async request({ params, provider }) {
      const response = await fetch(
        `https://api.weixin.qq.com/sns/oauth2/access_token?appid=${process.env.WECHAT_APP_ID}&secret=${process.env.WECHAT_APP_SECRET}&code=${params.code}&grant_type=authorization_code`
      )
      const tokens = await response.json()
      return { tokens }
    },
  },
  userinfo: {
    url: "https://api.weixin.qq.com/sns/userinfo",
    async request({ tokens }) {
      const response = await fetch(
        `https://api.weixin.qq.com/sns/userinfo?access_token=${tokens.access_token}&openid=${tokens.openid}`
      )
      return await response.json()
    },
  },
  profile(profile) {
    return {
      id: profile.unionid || profile.openid,
      name: profile.nickname,
      email: null, // O WeChat não fornece e-mail
      image: profile.headimgurl,
    }
  },
}

export const authOptions = {
  providers: [
    WeChatProvider,
    // ...outros providers
  ],
}

Como testar no ambiente de desenvolvimento

A parte mais difícil do login com WeChat é o teste local, porque ele exige HTTPS e um domínio com registro ICP. Normalmente uso uma destas duas abordagens.

Opção 1: túnel de rede — recomendada

Use ngrok ou cpolar para expor a porta local 3000 na Internet:

# Usando ngrok
ngrok http 3000

# Ou cpolar, mais estável na China
cpolar http 3000

O serviço gerará um domínio temporário, como https://abc123.ngrok.io. Cadastre esse domínio como domínio de callback de autorização na Plataforma Aberta do WeChat.

Opção 2: conta de teste

O WeChat oferece uma conta de teste que não exige qualificação empresarial:

Mas apenas você poderá usar essa conta de teste. Outros usuários que escanearem o código verão a mensagem “a conta oficial não foi seguida”.

Particularidades do login com WeChat

Diferença 1: devolve openid e unionid

  • openid: identificador único do usuário no aplicativo atual
  • unionid: identificador único do usuário em todos os aplicativos vinculados à mesma conta da Plataforma Aberta; ele só existe quando vários aplicativos estão vinculados

Recomendo usar unionid como identificador do usuário e recorrer a openid quando unionid não estiver disponível.

Diferença 2: não fornece e-mail

A API do WeChat não retorna o e-mail, portanto email é null no profile. Se o seu sistema de usuários exige e-mail, você terá que pedir que o usuário o informe separadamente.

Diferença 3: o access_token expira rapidamente

Os tokens do Google e do GitHub costumam durar uma hora. O token do WeChat dura apenas duas horas e tem um limite diário de renovações, aparentemente dez. Por isso, trate a lógica de renovação com cuidado.

Conclusão

Percorremos todo o fluxo de login de terceiros, dos fundamentos do OAuth à configuração prática nas três plataformas.

Revisão dos pontos principais:

  • A separação entre code e token existe por segurança. O code pode trafegar de forma visível no navegador, mas o secret deve permanecer no backend
  • O NextAuth.js permite que você se concentre na lógica do produto sem cuidar manualmente de detalhes como gerenciamento de Session e proteção contra CSRF
  • A configuração do Google é a mais rígida, pois o redirect URI precisa corresponder exatamente; o GitHub é o mais amigável; o WeChat tem a maior barreira, mas é indispensável na China
  • O login com WeChat exige qualificação empresarial e domínio com registro ICP; durante o desenvolvimento, você pode depurar com túnel de rede e conta de teste

Dicas práticas:

  • Gere o NEXTAUTH_SECRET com openssl rand -base64 32; não o escreva manualmente
  • Cadastre no Google Console redirect URIs para algumas portas diferentes, evitando erros quando precisar trocar a porta local
  • O e-mail do GitHub pode ser null; trate esse valor no código
  • O unionid do WeChat é mais adequado que openid como identificador único entre aplicativos

Sendo sincero, a parte mais difícil do login de terceiros não é escrever o código, mas entender as decisões de design do OAuth e as diferenças de configuração entre as plataformas. Se este artigo evitar que você enfrente alguns dos mesmos problemas, já terá cumprido seu objetivo.

Na próxima vez que alguém pedir para “adicionar login com o Google”, você provavelmente não passará outra tarde inteira configurando tudo.

Configuração completa de login OAuth no Next.js

Passo a passo completo, dos fundamentos do OAuth à configuração de login com Google, GitHub e WeChat.

⏱️ Estimated time: 2 hr

  1. 1

    Step 1: Entenda o fluxo OAuth com a analogia da retirada de encomenda

    Ideia central do OAuth: você não precisa entregar sua senha a um aplicativo de terceiros; basta autorizá-lo a obter uma credencial temporária junto ao provedor OAuth.

    Analogia da retirada de encomenda:
    • Você (usuário) → quem quer entrar
    • Amigo (aplicativo Next.js) → quem retira a encomenda para você
    • Ponto de retirada (provedor OAuth) → Google, GitHub ou WeChat
    • Cartão de acesso (senha) → não pode ser entregue a terceiros
    • Credencial temporária (access_token) → tem prazo e permissões limitadas

    Fluxo em quatro etapas:
    1. Você entrega ao amigo o código de retirada (authorization code)
    2. O amigo leva o código e o documento ao ponto de retirada (troca code + client_secret por access_token)
    3. Depois de confirmar a identidade, o ponto entrega a encomenda (dados do usuário)
    4. O amigo entrega a encomenda a você (login concluído)

    Pontos importantes:
    • O código de retirada (code) só pode ser usado uma vez e expira rapidamente, em geral em 10 minutos
    • O documento (client_secret) precisa permanecer secreto e ser usado apenas no servidor
    • A credencial temporária (access_token) tem prazo e permissões limitadas
  2. 2

    Step 2: Configure o login com Google

    1. Crie um cliente OAuth no Google Cloud Console:
    • Acesse https://console.cloud.google.com
    • Crie um projeto → APIs e serviços → Credenciais → Criar ID do cliente OAuth
    • Tipo de aplicativo: aplicativo da Web
    • URI de redirecionamento autorizado: http://localhost:3000/api/auth/callback/google

    2. Obtenha client_id e client_secret

    3. Configure o NextAuth.js:
    ```ts
    // app/api/auth/[...nextauth]/route.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!,
    })
    ],
    }

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

    4. Defina as variáveis de ambiente:
    ```
    GOOGLE_CLIENT_ID=seu_client_id
    GOOGLE_CLIENT_SECRET=seu_client_secret
    NEXTAUTH_URL=http://localhost:3000
    NEXTAUTH_SECRET=string_aleatoria
    ```

    5. Use na página:
    ```tsx
    import { signIn } from 'next-auth/react'

    <button onClick={() => signIn('google')}>
    Entrar com o Google
    </button>
    ```
  3. 3

    Step 3: Configure o login com GitHub

    1. Crie um OAuth App no GitHub:
    • Acesse https://github.com/settings/developers
    • Clique em New OAuth App
    • Authorization callback URL: http://localhost:3000/api/auth/callback/github

    2. Obtenha o Client ID e o Client Secret

    3. Configure o NextAuth.js:
    ```ts
    import GitHubProvider from 'next-auth/providers/github'

    providers: [
    GitHubProvider({
    clientId: process.env.GITHUB_CLIENT_ID!,
    clientSecret: process.env.GITHUB_CLIENT_SECRET!,
    })
    ]
    ```

    4. Defina as variáveis de ambiente:
    ```
    GITHUB_CLIENT_ID=seu_client_id
    GITHUB_CLIENT_SECRET=seu_client_secret
    ```

    Ponto importante: a configuração do GitHub é parecida com a do Google; muda apenas o provedor OAuth.
  4. 4

    Step 4: Configure o login com WeChat, que exige tratamento especial

    1. Cadastre o aplicativo na Plataforma Aberta do WeChat:
    • Acesse https://open.weixin.qq.com
    • Crie um aplicativo para site
    • Obtenha AppID e AppSecret
    • É necessário ter qualificação empresarial

    2. Configure o domínio de callback de autorização:
    • Formato: yourdomain.com, sem http:// nem https://
    • O domínio precisa ter registro ICP

    3. Configure um Provider personalizado:
    ```ts
    import WeChatProvider from 'next-auth/providers/wechat'

    providers: [
    WeChatProvider({
    clientId: process.env.WECHAT_CLIENT_ID!,
    clientSecret: process.env.WECHAT_CLIENT_SECRET!,
    })
    ]
    ```

    4. Use um túnel de rede nos testes locais:
    • Use ngrok ou frp
    • Configure o endereço do túnel como callback
    • Depois dos testes, troque-o pelo endereço de produção

    Pontos importantes:
    • O login com WeChat exige qualificação empresarial
    • O teste local exige um túnel de rede
    • unionid é mais adequado que openid como identificador único do usuário
  5. 5

    Step 5: Resolva erros comuns

    Erro 1: redirect_uri_mismatch
    • Causa: a URL de callback não corresponde à cadastrada
    • Solução: configure o redirect_uri correto no painel do provedor OAuth
    • Atenção: cadastre as URLs de callback local e de produção

    Erro 2: variáveis de ambiente ausentes
    • Verifique se o arquivo .env.local existe
    • Verifique se os nomes das variáveis estão corretos
    • Verifique se as variáveis de ambiente foram configuradas no Vercel Dashboard

    Erro 3: funciona localmente, mas falha depois da implantação
    • Causa: as URLs de callback local e de produção são diferentes
    • Solução: cadastre o redirect_uri de produção no painel do provedor OAuth
    • Formato: https://yourdomain.com/api/auth/callback/google

    Recomendações de segurança:
    • O client_secret precisa permanecer secreto e ser usado apenas no servidor
    • Use o parâmetro state para evitar ataques CSRF
    • Valide o parâmetro state na URL de callback

FAQ

Como o fluxo OAuth realmente funciona?
Use a retirada de uma encomenda como analogia para entender o OAuth.

Cenário: há uma encomenda sua (dados do usuário) no ponto de retirada, mas você está no trabalho e não pode buscá-la. Um amigo seu (o aplicativo Next.js) se oferece para fazer isso.

Fluxo:
1. Você entrega um código de retirada ao amigo (authorization code)
• Ao clicar no botão ‘Entrar com o Google’, você é redirecionado à página de autorização do Google
• Depois que você aceita, o Google gera um code temporário e o envia ao aplicativo como parâmetro da URL

2. O amigo leva o código ao ponto de retirada (troca code + client_secret por access_token)
• O backend do aplicativo envia code + client_secret ao Google para obter o access_token
• O Google ainda precisa confirmar se esse amigo é realmente alguém em quem você confia, usando o client_secret

3. Após confirmar a identidade, o ponto entrega a encomenda (dados do usuário)
• Quando code + client_secret estão corretos, o Google entrega a encomenda (dados do usuário) ao amigo
• O amigo então a entrega a você (login concluído)

Pontos importantes:
• O código de retirada (code) só pode ser usado uma vez e expira rapidamente, em geral em 10 minutos
• O documento (client_secret) precisa permanecer secreto e ser usado apenas no servidor
• A credencial temporária (access_token) tem prazo e permissões limitadas

Vantagem: você não precisa entregar sua senha a um aplicativo de terceiros; basta autorizá-lo a obter uma credencial temporária junto ao provedor OAuth.
O que significa o erro redirect_uri_mismatch?
Causa do erro: a URL de callback não corresponde à cadastrada.

O provedor OAuth valida a URL de callback e retorna esse erro quando ela é diferente da configuração.

Como resolver:
1. Cadastre o redirect_uri correto no painel do provedor OAuth
2. Desenvolvimento local: http://localhost:3000/api/auth/callback/google
3. Produção: https://yourdomain.com/api/auth/callback/google
4. Atenção: cadastre tanto a URL local quanto a de produção

Erros comuns:
• Cadastrar apenas a URL local e esquecer a de produção
• Digitar a URL de callback incorretamente, com uma barra a mais ou a menos
• Usar o protocolo errado, http em vez de https ou vice-versa

Como verificar:
• Consulte o caminho de callback padrão do NextAuth.js: /api/auth/callback/[provider]
• Confirme que o redirect_uri cadastrado no provedor OAuth corresponde exatamente a esse caminho

Observação: a configuração pode levar alguns minutos para entrar em vigor.
Por que o login com WeChat é o mais trabalhoso?
Problemas:

1. Exige qualificação empresarial
• Desenvolvedores individuais não podem solicitar o acesso
• São necessários documentos como uma licença comercial
• A análise costuma levar de 1 a 3 dias úteis

2. A documentação não é amigável
• A documentação oficial não é clara o bastante
• As mensagens de erro não são específicas
• A depuração é difícil

3. O teste local é complicado
• É necessário usar um túnel de rede, como ngrok ou frp
• A configuração da URL de callback é complexa
• O ambiente de teste tem várias limitações

4. A configuração é complexa
• É necessário configurar um Provider personalizado
• É preciso entender a diferença entre unionid e openid
• O domínio de callback de autorização precisa ter registro ICP

Soluções:
• Use um túnel de rede para depurar
• Configure um Provider personalizado
• Use unionid, mais adequado que openid como identificador único do usuário
• Aguarde a análise com paciência

Sugestão: quando possível, priorize o login com Google ou GitHub e ofereça WeChat como opção adicional.
Como configurar um Provider personalizado?
O login com WeChat exige um Provider personalizado:

```ts
import type { OAuthConfig, OAuthUserConfig } from 'next-auth/providers'

function WeChatProvider(options: OAuthUserConfig<WeChatProfile>): OAuthConfig<WeChatProfile> {
return {
id: 'wechat',
name: 'WeChat',
type: 'oauth',
authorization: {
url: 'https://open.weixin.qq.com/connect/qrconnect',
params: {
appid: options.clientId,
redirect_uri: options.callbackUrl,
response_type: 'code',
scope: 'snsapi_login',
state: 'state',
},
},
token: {
url: 'https://api.weixin.qq.com/sns/oauth2/access_token',
},
userinfo: {
url: 'https://api.weixin.qq.com/sns/userinfo',
},
profile(profile) {
return {
id: profile.openid,
name: profile.nickname,
email: null,
image: profile.headimgurl,
}
},
...options,
}
}
```

Pontos importantes:
• Configure a URL de authorization
• Configure a URL de token
• Configure a URL de userinfo
• Implemente a função profile

Observação: a configuração do login com WeChat é relativamente complexa. Consulte a documentação oficial ou use um Provider pronto.
Qual é a diferença entre unionid e openid?
openid:
• Identificador único do usuário no aplicativo atual
• O openid é diferente em cada aplicativo
• Adequado a cenários com um único aplicativo

unionid:
• Identificador único do usuário na Plataforma Aberta do WeChat
• O mesmo usuário tem o mesmo unionid em aplicativos diferentes
• Adequado a cenários com vários aplicativos

Como escolher:
• Um aplicativo → use openid
• Vários aplicativos → use unionid

Exemplo de código:
```ts
// Obter unionid
const response = await fetch(
`https://api.weixin.qq.com/sns/userinfo?access_token=${accessToken}&openid=${openid}`
)
const data = await response.json()
const unionid = data.unionid // Identificador único do usuário
```

Pontos importantes:
• unionid é mais adequado que openid como identificador único do usuário
• É necessária a autorização do usuário para obter unionid
• É preciso configurar a Plataforma Aberta do WeChat para usar unionid
Como testar o login com WeChat localmente?
Problema: o login com WeChat exige a configuração de um domínio de callback de autorização, e localhost não pode ser cadastrado.

Solução: use um túnel de rede.

1. Use ngrok:
```bash
ngrok http 3000
```

2. Obtenha o endereço público:
```
https://xxxxx.ngrok.io
```

3. Configure a URL de callback:
• Na Plataforma Aberta do WeChat: https://xxxxx.ngrok.io/api/auth/callback/wechat
• No .env.local: NEXTAUTH_URL=https://xxxxx.ngrok.io

4. Teste:
• Acesse https://xxxxx.ngrok.io
• Clique para entrar com o WeChat
• Teste o fluxo

Cuidados:
• O endereço da versão gratuita do ngrok muda, portanto é preciso atualizá-lo a cada reinicialização
• Não use ngrok em produção
• Depois dos testes, troque para o endereço de produção

Sugestão: use uma solução própria de túnel, como frp, para ter um endereço mais estável.

20 min de leitura · Publicado em: 19 dez 2025 · Atualizado em: 8 set 2026

Comentários

Entre com GitHub para comentar

Easton BlogEaston Blog