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

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 Googleredirect_uri: para onde o Google deve mandar o usuário depois da autorizaçãoscope: 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:
| Termo | Explicação simples | Onde aparece |
|---|---|---|
| Client ID | Identidade pública do seu aplicativo | Arquivo .env.local e parâmetros da URL no navegador |
| Client Secret | Senha do aplicativo, que deve permanecer secreta | Apenas no código do backend e nas variáveis de ambiente |
| Authorization Code | Código de retirada de uso único | Parâmetro code na URL de callback |
| Access Token | Chave que realmente permite obter os dados | No código do backend; não deve ser enviado ao frontend |
| Redirect URI | Endereço de retorno depois da autorização | Configuração do aplicativo OAuth e parâmetros da URL de autorização |
| Scope | Conjunto de permissões solicitadas | Parâmetros da URL de autorização, como “email profile” |
| State | String aleatória usada contra ataques CSRF | Parâ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:
- O code só pode ser usado uma vez e perde a validade depois disso
- A troca pelo token também exige o client_secret, conhecido apenas pelo backend
- O servidor OAuth ainda verifica se o
redirect_uricorresponde 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:
-
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. -
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.
- A convenção do prefixo AUTH_: o NextAuth.js v5 reconhece automaticamente variáveis no formato
AUTH_PROVIDER_IDeAUTH_PROVIDER_SECRET. Assim, você não precisa escreverprocess.env.XXXno 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:
httpversushttps: 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/googleprecisa estar absolutamente correto, sem barras extras ou ausentes - Não adicione parâmetros de consulta: termine em
/google. O Google adicionará?code=xxxautomaticamente
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árioaccess_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íodosresponse_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:
- Abra as ferramentas do desenvolvedor do navegador e selecione a aba Network
- Clique no botão de login e examine a URL usada no redirecionamento ao Google
- Localize o parâmetro
redirect_urie copie o valor completo - Volte ao Google Console e cole exatamente esse valor em Authorized redirect URIs
- 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
| Item | GitHub | |
|---|---|---|
| Dificuldade da configuração | Média; é preciso ativar uma API | Simples; basta criar o aplicativo |
| Redirect URI | Rígido; deve corresponder exatamente | Flexível; aceita curingas |
| Exigência de HTTPS | Obrigatório em produção | localhost pode usar http |
| Configuração de Scope | Precisa ser informada explicitamente | O padrão costuma ser suficiente |
| Dados do usuário | email, name, picture | login, 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 login | Cenário | Requisitos | Experiência do usuário |
|---|---|---|---|
| Plataforma Aberta — aplicativo para site | Site independente | Qualificação empresarial, domínio com registro ICP e HTTPS | Login por QR code, com suporte a PC |
| Autorização Web de conta oficial | Página H5 dentro do WeChat | Conta oficial verificada | Apenas no navegador do WeChat |
| WeCom | Sistema corporativo interno | Conta WeCom | Apenas 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:
- Acesse https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login
- Entre pelo QR code para receber um AppID e um Secret de teste
- O domínio de callback pode ser um domínio temporário do seu túnel de rede
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 atualunionid: 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
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
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
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
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
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?
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?
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?
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?
```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?
• 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?
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
Guia completo Next.js
Se você chegou pela busca, o caminho mais rápido é ir para o post anterior ou próximo desta série.
Anterior
Tutorial de Server Actions no Next.js: boas práticas para formulários e validação
Aprenda na prática a processar formulários com Server Actions no Next.js, validar dados com Zod, aplicar medidas de segurança e melhorar a experiência do usuário.
Parte 6 de 26
Próximo
Guia completo de internacionalização no Next.js: boas práticas com next-intl
Um guia detalhado de internacionalização com o App Router do Next.js, incluindo a configuração completa do next-intl, o design de rotas multilíngues, boas práticas para gerenciar traduções e exemplos de código
Parte 8 de 26



Comentários
Entre com GitHub para comentar