A camada prévia ao código: provisionando a identidade do app no provedor#
Em qualquer implementação de autenticação OAuth 2.0, existe uma camada prévia ao código que precisa ser provisionada corretamente: a identidade do aplicativo junto ao provedor de identidade (neste caso, o Google). Sem essa etapa, qualquer biblioteca de autenticação (NextAuth.js, Auth.js v5, Passport.js, Lucia) falha com erros de redirect_uri_mismatch ou access_denied antes de qualquer linha de código do backend ser executada.
O OAuth 2.0 funciona sob o protocolo de delegação de autorização. O fluxo simplificado:
Usuário clica "Login com Google"
│
▼
App redireciona para accounts.google.com/o/oauth2/v2/auth
?client_id=SEU_CLIENT_ID
&redirect_uri=https://seuapp.com/api/auth/callback/google
&scope=openid profile email
&response_type=code
│
▼
Google valida:
1. SEU_CLIENT_ID existe?
2. redirect_uri está na lista de URIs autorizadas?
3. Os scopes solicitados estão aprovados?
│
✅ Tudo válido → Google autentica o usuário e retorna o authorization code
❌ Qualquer validação falha → error: redirect_uri_mismatch / access_denied
O objetivo da configuração no Google Cloud Console: registrar o aplicativo, definir quais dados serão acessados e autorizar explicitamente quais origens e URIs de callback são legítimas.
1) Introdução e delegação de autoridade#
O protocolo OAuth 2.0 é o padrão de mercado para delegação segura de autoridade na Web. Ele permite que uma aplicação cliente solicite acesso restrito a dados do perfil de um usuário (hospedados em um Provedor de Identidade, como o Google) sem que o usuário precise compartilhar suas credenciais primárias (senhas) com a aplicação. Em termos práticos de arquitetura de software, o sucesso desse ecossistema depende de uma configuração precisa na console do provedor. A menor discrepância em nomes de domínios, caminhos de callback ou permissões de escopo causa falhas catastróficas que interrompem o fluxo de onboarding dos usuários.
2) Provisionamento do projeto no Google cloud console#
O Google Cloud organiza todos os recursos de desenvolvimento e APIs em projetos isolados. É uma melhor prática de infraestrutura isolar ambientes corporativos para que chaves de homologação ou teste não compartilhem os mesmos privilégios de produção.
Para instanciar o ambiente:
- Acesse a console administrativa do Google Cloud.
- Na barra de navegação superior, clique no seletor de projetos e escolha Novo Projeto (New Project).
- Preencha o nome descritivo (ex:
meuapp-producao-auth) e associe a uma organização do Google Workspace se aplicável. - Clique em Criar (Create) e aguarde o término do provisionamento interno do contêiner.
3) OAuth consent screen: configuração essencial#
A tela de consentimento (OAuth Consent Screen) é a interface que o usuário final visualiza quando concorda em compartilhar seus dados com seu sistema.
3.1 tipo de usuário (user type)#
- Internal: Restringe o login apenas a e-mails pertencentes à mesma organização Google Workspace do projeto. Não exige processo de verificação formal do Google.
- External: Permite o login de qualquer conta de e-mail do Google (Gmail ou Workspace externa). Exige verificação antes de entrar em modo de produção pública.
3.2 escopos mínimos (scopes)#
Adicione exatamente os três escopos essenciais recomendados pelo padrão OpenID Connect (OIDC) para identificação do usuário:
openid: Para emissão do ID Token JWT..../auth/userinfo.email: Para leitura do e-mail principal..../auth/userinfo.profile: Para obter nome e avatar.
3.3 test users#
Enquanto o projeto estiver no modo Testing (não verificado), apenas e-mails explicitamente inseridos na lista de Test Users conseguirão efetuar o login. Contas externas não listadas receberão um erro HTTP 403 access_denied.
4) Criação e configuração das credenciais#
Acesse o menu Credentials -> Create Credentials -> OAuth client ID.
4.1 origens javascript autorizadas (authorized javascript origins)#
Domínio de origem que inicia a requisição HTTP.
- Desenvolvimento:
http://localhost:3000 - Produção:
https://meudominio.com.br - Regra estrita: Nunca insira barras ao final (trailing slash) ou caminhos de subpastas nestas URLs.
4.2 URIs de redirecionamento autorizadas (authorized redirect URIs)#
Caminho completo do endpoint (callback) que processará o código de autorização.
- Para NextAuth.js (App Router):
http://localhost:3000/api/auth/callback/googleehttps://meudominio.com.br/api/auth/callback/google.
5) Isolamento de segredos e configuração de ambiente#
Os dados gerados pelo Google Cloud consistem em um Client ID (identificador público) e um Client Secret (segredo criptográfico privado). O vazamento do Client Secret permite que atacantes falsifiquem requisições em nome do seu aplicativo.
- Armazene as credenciais exclusivamente no arquivo de variáveis locais
.env.local:
GOOGLE_CLIENT_ID=123456789-abcdef.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=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er_value_xxxxxx
NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=gerado_com_openssl_rand_base64
- Certifique-se de que o arquivo
.gitignoreestá bloqueando o envio de arquivos de variáveis para o repositório git:
# .gitignore
.env
.env.local
.env.*.local
*.env
6) Verificação pós-configuração de identidade#
Após registrar as chaves na console do Google Cloud, é essencial realizar testes para validar a consistência e a validade sintática do Client ID gerado:
- Teste o status e a integridade da chave do Client ID enviando uma chamada direta para o validador público de tokens do Google:
curl -s "https://oauth2.googleapis.com/tokeninfo?id_token=TESTE" | jq .
- Valide o fluxo simulando o acesso local ao endpoint de autenticação do seu servidor Next.js:
- Abra o navegador e acesse a rota local
http://localhost:3000/api/auth/signin/google. - Confirme se o servidor inicia o redirecionamento para
https://accounts.google.com/o/oauth2/v2/auth. - Verifique na barra de endereços do navegador se os parâmetros
client_ideredirect_uricoincidem exatamente com o registrado no console da nuvem.
7) Configuração de refresh tokens#
Para manter a experiência do usuário fluida e evitar desconexões frequentes a cada expiração do access token, configure o NextAuth para solicitar um refresh token durante o ciclo inicial de consentimento.
No arquivo src/auth.ts, ajuste o provider do Google adicionando os parâmetros de autorização offline e consent:
import NextAuth from "next-auth"
import Google from "next-auth/providers/google"
export const { handlers, auth, signIn, signOut } = NextAuth({
providers: [
Google({
clientId: process.env.GOOGLE_CLIENT_ID!,
clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
authorization: {
params: {
access_type: "offline", // Exige refresh token do Google
prompt: "consent", // Força exibição da tela para capturar refresh_token
},
},
}),
],
callbacks: {
async jwt({ token, account }) {
if (account) {
token.accessToken = account.access_token
token.refreshToken = account.refresh_token
token.expiresAt = account.expires_at // Timestamp de expiracao em segundos
}
return token
},
},
})
8) Tratamento de expiração e renovação de tokens#
O access token emitido pelo Google expira por padrão em 3600 segundos (1 hora). Para garantir a persistência das sessões ativas sem forçar re-autenticação manual, verifique e renove o token de acesso no servidor utilizando o refresh token:
- Função de utilidade para checar a expiração do token e renovação dinâmica:
// Validar expiração do token baseado em data/hora
const isTokenExpired = (token: any) => {
return Date.now() >= (token.expiresAt * 1000)
}
// Renovar access token com chamada de API ao Google OAuth2
const refreshAccessToken = async (token: any) => {
try {
const response = await fetch("https://oauth2.googleapis.com/token", {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({
client_id: process.env.GOOGLE_CLIENT_ID!,
client_secret: process.env.GOOGLE_CLIENT_SECRET!,
refresh_token: token.refreshToken,
grant_type: "refresh_token",
}),
})
const data = await response.json()
if (!response.ok) throw data
return {
...token,
accessToken: data.access_token,
expiresAt: Math.floor(Date.now() / 1000) + data.expires_in,
// Se o Google não retornar um novo refresh_token, mantém o atual
refreshToken: data.refresh_token ?? token.refreshToken,
}
} catch (error) {
console.error("Falha ao renovar o access token do Google:", error)
return { ...token, error: "RefreshAccessTokenError" }
}
}
9) Implementação de fluxo de logout seguro#
O encerramento de sessão deve limpar os vestígios locais da autenticação no NextAuth e opcionalmente guiar o usuário na remoção do token junto ao provedor de identidade.
Adicione o controle de encerramento seguro na interface do seu aplicativo de frontend:
import { signOut } from "next-auth/react"
// Estratégia 1: Logout local limpando cookies da aplicacao
const handleLocalLogout = () => {
signOut({ redirect: true, callbackUrl: "/" })
}
// Estratégia 2: Logout combinado limpando sessao do Google
const handleGlobalLogout = () => {
// Redireciona para o logout do Google e retorna ao site após a limpeza
signOut({
callbackUrl: "https://accounts.google.com/Logout",
})
}
10) Políticas CORS e rate limiting no gateway#
As rotas da API de autenticação do Next.js devem ser protegidas contra ataques de força bruta, abuso de chamadas concorrentes e requisições maliciosas originadas em domínios não autorizados:
- Configure as diretivas de cabeçalhos de segurança CORS para a rota da API de autenticação no arquivo
next.config.js:
module.exports = {
async headers() {
return [
{
source: "/api/auth/:path*",
headers: [
{ key: "Access-Control-Allow-Origin", value: process.env.NEXTAUTH_URL || "*" },
{ key: "Access-Control-Allow-Methods", value: "GET, POST, OPTIONS" },
{ key: "Access-Control-Allow-Headers", value: "Content-Type, Authorization" },
],
},
]
},
}
- Implemente rate limiting básico baseado no endereço IP de origem no arquivo
middleware.tspara blindar as tentativas de login:
import { NextResponse } from "next/server"
import type { NextRequest } from "next/request"
const rateLimitMap = new Map<string, number[]>()
export function middleware(request: NextRequest) {
const ip = request.ip || "127.0.0.1"
const now = Date.now()
const windowMs = 15 * 60 * 1000 // Janela de 15 minutos
const maxRequests = 20
if (request.nextUrl.pathname.startsWith("/api/auth/signin")) {
if (!rateLimitMap.has(ip)) {
rateLimitMap.set(ip, [])
}
const requests = rateLimitMap.get(ip)!
const recentRequests = requests.filter(time => time > now - windowMs)
if (recentRequests.length >= maxRequests) {
return NextResponse.json({ error: "Limite de tentativas excedido. Tente novamente mais tarde." }, { status: 429 })
}
recentRequests.push(now)
rateLimitMap.set(ip, recentRequests)
}
return NextResponse.next()
}
11) Auditoria de SSL/TLS, domínio e política de privacidade#
Para o funcionamento correto do OAuth 2.0 em produção, todos os endpoints envolvidos devem rodar sob conexões HTTPS seguras com certificados digitais válidos e domínio validado.
- Teste o status SSL e verifique as datas de expiração do certificado digital do servidor principal da aplicação:
echo | openssl s_client -connect meudominio.com.br:443 2>/dev/null | openssl x509 -noout -dates
- Valide o status de verificação de propriedade do domínio consultando o registro TXT associado ao Google Cloud no DNS público:
dig TXT _google-domain-verification.meudominio.com.br +short
- Certifique-se de que a política de privacidade (exigência do console do Google para sair do modo Testing) está acessível publicamente via HTTPS:
curl -I https://meudominio.com.br/privacy
12) Logs de auditoria e rastreamento de autenticação#
Registrar eventos no ciclo de login auxilia na auditoria forense do comportamento do sistema e na detecção precoce de acessos suspeitos.
Implemente um callback de auditoria em src/auth.ts:
const logAuthAttempt = (email: string, success: boolean, provider: string) => {
console.log(JSON.stringify({
event: "oauth_auth_attempt",
email,
success,
provider,
timestamp: new Date().toISOString(),
}))
}
// Dentro da configuracao do NextAuth:
callbacks: {
async signIn({ user, account, profile }) {
if (profile?.email) {
logAuthAttempt(profile.email, true, account?.provider || "unknown")
}
return true
}
}
13) Checklists de configuração e matriz de riscos#
13.1 checklist operacional de integração do Google oauth2#
Certifique-se de validar todos os itens listados antes do lançamento:
- [ ] Projeto criado e isolado no Google Cloud Console com billing ativo.
- [ ] OAuth Consent Screen configurada como
Externalcom escoposopenid,emaileprofile. - [ ] Links reais de Política de Privacidade e Termos de Uso públicos e acessíveis via HTTPS.
- [ ] Usuários de teste adicionados à lista de Test Users na console.
- [ ] Credenciais do OAuth Client ID geradas com tipo de aplicação
Web application. - [ ] Endpoints e JavaScript origins configurados sem barras finais e caminhos adicionais.
- [ ] Variáveis salvadas exclusivamente no arquivo local
.env.locale ocultas no arquivo.gitignore. - [ ] Lógica de Refresh Tokens e renovação de expiração de token ativas no servidor.
- [ ] Cabeçalhos CORS e Rate Limit ativo no arquivo de
middleware.ts. - [ ] Logs de auditoria estruturados inseridos nos callbacks de autenticação.
13.2 matriz de riscos de autenticação e severidade#
| Risco / Ameaça | Severidade | Descrição | Ação de Mitigação Técnica |
|---|---|---|---|
| Vazamento do Secret | Crítica | Chave privada Client Secret exposta publicamente em repositórios Git públicos. | Armazenamento de chaves em variáveis de ambiente seguras e restrições rígidas no .gitignore. |
| Bloqueio de Contas | Alta | Usuários não conseguem logar recebendo erro 403 access_denied em homologação. | Adição manual de endereços de e-mail dos testadores na aba Test Users da console do Google Cloud. |
| Invalidação de Callback | Alta | Erro redirect_uri_mismatch impede o fluxo por discrepância de portas ou caminhos. | Cadastro detalhado e correspondência binária exata das URIs de callback cadastradas. |
| Ataques de Força Bruta | Média | Tentativas excessivas de requisições de login e inundações na API de callback. | Configuração de middleware com Rate Limit ativo baseado em IP e janela de requisições de 15 minutos. |
| Falha de Renovação | Média | O usuário é desconectado abruptamente após 1 hora devido ao access token do Google expirado. | Configuração de parâmetros de acesso offline e renovação dinâmica automática usando refresh tokens. |
Considerações práticas#
A integração do Google OAuth 2.0 com o NextAuth.js é mais do que a escrita de código de rotas; exige uma governança sólida de credenciais e segurança de rede. Ao isolar os segredos do repositório, monitorar o tempo de expiração dos tokens e auditar conexões seguras HTTPS de ponta a ponta, você constrói uma barreira de autenticação resiliente e em conformidade com as melhores práticas de cibersegurança do mercado.
Este artigo foi útil?
Deixe uma reação rápida para apoiar o conteúdo:
Este post está licenciado sob CC BY-NC.



Comentários
Participe da discussão abaixo.
0 comentários