Aprenda / Segurança web

FundamentosAula 4 de 1617 min0% da trilha

Autenticação por bearer token

Nenhum navegador reenvia um bearer token sozinho — e é exatamente essa diferença que muda o cálculo de segurança inteiro.

Sessão com cookie funciona muito bem pra um site tradicional, onde navegador e servidor são as únicas duas pontas envolvidas. Ela funciona mal (ou nem funciona) pra um app mobile nativo, um SPA consumindo uma API separada do domínio do front, ou um serviço backend chamando outro backend — nenhum desses tem "o navegador" cuidando de cookie pra eles. Pra esses casos, o mecanismo mais comum é o bearer token: um valor que o próprio cliente carrega e anexa manualmente em cada requisição.

O fluxo, passo a passo

App / SPA
API

Clique em “Reproduzir fluxo” para ver a requisição passo a passo.

requisição autenticada
GET /pedidos HTTP/1.1
Host: api.exemplo.com
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIx...

A palavra Bearer literalmente significa "portador" — o protocolo assume que quem apresenta esse token é quem tem direito a ele, sem prova adicional. Repare no contraste com a lição 2: ali, o navegador reenviava o cookie sozinho, sem nenhuma linha de código pedindo isso. Aqui, se o seu código esquecer de anexar o header Authorization, a requisição simplesmente chega sem identificação nenhuma — o servidor responde 401 Unauthorized, e não há "reenvio automático" nenhum salvando essa situação.

Onde o cliente guarda esse token — e por que isso importa

Diferente do cookie (que o navegador guarda e protege sozinho, respeitando HttpOnly), o bearer token precisa ser guardado em algum lugar que o código do cliente controla e consegue ler de volta pra montar o header a cada chamada. As opções mais comuns são localStorage (persiste entre recarregamentos de página, mas fica acessível a qualquer script) ou só em memória/estado da aplicação (some ao recarregar a página, mas não fica exposto entre abas nem sobrevive um refresh).

anexando o token manualmente
const token = localStorage.getItem("token");

fetch("/pedidos", {
  headers: { Authorization: `Bearer ${token}` },
});

Esse mesmo localStorage.getItem("token") é o ponto fraco: se existir uma falha de XSS em qualquer lugar da aplicação (lição 7), o script injetado consegue rodar exatamente essa mesma linha e roubar o token — sem precisar de nenhum truque adicional, porque não existe equivalente de HttpOnly pra localStorage. É o trade-off central do bearer token guardado no client: ele resolve o problema de CSRF quase de graça (a lição 8 explica o porquê), mas herda uma exposição a XSS que o cookie HttpOnly não tem.

Por que isso é o padrão em mobile e integrações de terceiro

Um app mobile nativo não tem "o navegador" gerenciando cookie de domínio nenhum — ele guarda o token no armazenamento seguro do próprio sistema operacional (Keychain no iOS, Keystore no Android) e o anexa manualmente, exatamente como no exemplo acima. O mesmo vale pra uma API pública consumida por um serviço terceiro: não existe "sessão de navegador" entre dois servidores conversando entre si, então bearer token (ou uma variação com chave de API) é praticamente a única opção que faz sentido.

Exercício

Um front-end guarda o bearer token em localStorage e faz login normalmente. Depois de um deploy, um usuário reporta que, ao abrir duas abas do mesmo site e fazer login em uma delas, a outra também passa a aparecer autenticada sem recarregar. Isso é esperado? E se o token estivesse só em memória (numa variável de estado, não em localStorage), esse comportamento mudaria?

Quiz rápido

Qual a diferença essencial entre como o cookie de sessão (lição 2) e o bearer token chegam em cada requisição seguinte?
Por que guardar um bearer token em localStorage é considerado um risco específico de XSS, diferente de um cookie HttpOnly?