Estratégias de autenticação em APIs públicas: API keys vs OAuth vs JWT

1. Introdução aos desafios de autenticação em APIs públicas

APIs públicas expostas à internet enfrentam um dilema fundamental: como permitir acesso controlado a recursos sem comprometer a segurança? Diferentemente de APIs internas, que operam em redes confiáveis, as APIs públicas precisam lidar com requisições de origens desconhecidas, ataques de força bruta, vazamento de credenciais e abuso de limites de taxa.

A primeira distinção crucial é entre autenticação (verificar quem é o cliente) e autorização (determinar o que esse cliente pode fazer). Enquanto a autenticação responde "quem está fazendo a requisição?", a autorização responde "essa requisição é permitida?".

As três estratégias mais adotadas — API Keys, OAuth 2.0 e JWT — atendem a diferentes cenários. API Keys são ideais para integrações simples servidor-a-servidor. OAuth 2.0 brilha quando há delegação de acesso entre aplicações de terceiros. JWT oferece uma abordagem stateless e portátil, frequentemente combinada com OAuth 2.0.

2. API Keys: simplicidade e casos de uso

API Keys são strings únicas geradas pelo provedor da API e enviadas pelo cliente em cada requisição, geralmente no header Authorization, na query string ou no corpo da requisição.

Exemplo de requisição com API Key:

GET /api/v1/dados HTTP/1.1
Host: api.exemplo.com
Authorization: Bearer sk_live_4f6g7h8j9k0l1m2n3o4p5q6r

Prós:
- Implementação trivial: geração, armazenamento e validação são diretos
- Baixa latência: sem necessidade de handshakes complexos
- Ideal para comunicação máquina-a-máquina (M2M)

Contras:
- Falta de granularidade: uma chave dá acesso a tudo que o plano permite
- Dificuldade de revogação: se exposta, é necessário invalidar e redistribuir
- Exposição em client-side: chaves em aplicações frontend podem ser extraídas

Melhores práticas:
- Implementar rotação automática de chaves a cada 90 dias
- Aplicar rate limiting por chave individual
- Armazenar chaves em cofres de segredos (HashiCorp Vault, AWS Secrets Manager)
- Nunca incluir chaves em repositórios Git ou logs

3. OAuth 2.0: delegação de acesso e fluxos complexos

OAuth 2.0 é um framework de autorização que permite que aplicações terceiras acessem recursos em nome de um usuário sem compartilhar sua senha. Os fluxos principais são:

  • Authorization Code com PKCE: padrão para aplicações web e mobile
  • Client Credentials: para comunicação servidor-a-servidor sem usuário
  • Implicit Grant: obsoleto, não recomendado para novos projetos

Fluxo Authorization Code (simplificado):

1. Usuário clica "Login com Google" no app
2. App redireciona para: https://auth.exemplo.com/authorize?response_type=code&client_id=123&redirect_uri=https://app.com/callback
3. Usuário autentica e autoriza
4. Servidor de autorização redireciona para redirect_uri com código: https://app.com/callback?code=abc123
5. App troca código por tokens: POST /token com grant_type=authorization_code
6. Resposta: { "access_token": "eyJhbGci...", "refresh_token": "def456", "expires_in": 3600 }

Trade-offs:
- Complexidade de implementação: múltiplos endpoints, redirects e validações
- Necessidade de servidor de autorização dedicado (Keycloak, Auth0, AWS Cognito)
- Overhead de rede: múltiplas requisições até obter o token final
- Benefícios: escopos granulares, revogação por token, suporte a refresh tokens

4. JWT (JSON Web Tokens): autenticação stateless e portabilidade

JWT é um formato compacto e autossuficiente para transmitir informações entre partes como um objeto JSON. O token é composto por três partes codificadas em Base64URL separadas por pontos: header, payload e signature.

Estrutura de um JWT:

Header: {"alg":"RS256","typ":"JWT"}
Payload: {"sub":"user123","name":"Maria","iat":1719000000,"exp":1719003600}
Signature: RSA-SHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), privateKey)

Token completo:
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyMTIzIiwibmFtZSI6Ik1hcmlhIiwiaWF0IjoxNzE5MDAwMDAwLCJleHAiOjE3MTkwMDM2MDB9.assinatura

Vantagens:
- Stateless: servidor não precisa armazenar sessão, apenas verificar a assinatura
- Autocontido: contém todas as informações do usuário e claims
- Portátil: funciona entre microsserviços sem consulta centralizada
- Eficiente: validação por criptografia assimétrica (RS256) ou simétrica (HS256)

Desafios:
- Revogação complexa: tokens válidos até expirarem — requer blacklists ou tokens de curta duração
- Tamanho do payload: quanto mais claims, maior o token (impacto em headers HTTP)
- Riscos de signature bypass: algoritmos "none" ou chaves fracas em implementações incorretas

Uso combinado: JWT é frequentemente usado como access token em fluxos OAuth 2.0, unindo a delegação do OAuth com a portabilidade do JWT.

5. Comparação prática: segurança, performance e escalabilidade

Critério API Keys OAuth 2.0 JWT
Facilidade de implementação Alta Baixa Média
Segurança Média Alta Alta
Granularidade de permissões Baixa Alta Média
Performance (validação) Alta (consulta DB simples) Média (chamada ao IdP) Alta (verificação local)
Revogação Difícil Fácil (revogação centralizada) Difícil (blacklists ou curta duração)
Escalabilidade Alta Média Alta
Ataques comuns Vazamento de chave CSRF, replay Signature bypass, replay

Performance: API Keys exigem consulta a banco ou cache a cada requisição. JWT permite validação local sem I/O. OAuth 2.0 com JWT como access token combina o melhor dos dois mundos: delegação via OAuth + validação stateless via JWT.

6. Implementando uma estratégia híbrida em APIs públicas

Uma abordagem robusta combina API Keys para automação (M2M) com OAuth 2.0 + JWT para usuários finais.

Middleware de autenticação (pseudocódigo):

function authenticate(request):
    auth_header = request.headers.get("Authorization")

    if auth_header starts with "Bearer ":
        token = extract_token(auth_header)

        if token contains "sk_" prefix:  # API Key
            return validate_api_key(token)
        else:  # JWT (OAuth access token)
            return validate_jwt(token)

    return 401 Unauthorized

Gerenciamento de tokens:
- API Keys: rotação a cada 90 dias, revogação imediata via admin
- JWT: access tokens com expiração de 15 minutos, refresh tokens com 7 dias
- Revogação centralizada: manter lista negra em Redis para JWT inválidos antes da expiração

Healthcheck e monitoramento:

GET /health/auth
Resposta: {
  "api_keys_active": 1250,
  "jwt_validations_last_minute": 3400,
  "revoked_tokens": 23,
  "expiration_policy": "access=15min, refresh=7d"
}

7. Conclusão e recomendações finais

A escolha da estratégia depende do perfil da API:

  • API pública para integrações M2M: API Keys com rotação e rate limiting
  • API pública com usuários finais e terceiros: OAuth 2.0 + JWT (Authorization Code com PKCE)
  • API híbrida: API Keys para automação + OAuth/JWT para usuários

Checklist para decisão:
1. Qual o nível de segurança necessário? (dados sensíveis → OAuth 2.0)
2. Quem são os consumidores? (máquinas → API Keys; humanos → OAuth)
3. Qual a infraestrutura disponível? (sem IdP → JWT puro ou API Keys)
4. Necessita de delegação de acesso? (sim → OAuth 2.0)

Tendências futuras: Passkeys (WebAuthn/FIDO2) para autenticação sem senha e Identidades Descentralizadas (DID/VC) para controle soberano de identidade prometem evoluir ainda mais o cenário de autenticação em APIs públicas.


Referências