Cover do episódio 87: Autenticação vs. autorização: a diferença que eu confundia no começo
#0871 de julho, 20193 min leituraTecnologia sem HypeS3 · 2018–2019

Autenticação vs. autorização: a diferença que eu confundia no começo

Todo sistema tem as duas. A maioria dos bugs de segurança que vi em código júnior era confundir uma com a outra — ou implementar autorização onde precisava de autenticação.

SegurançaAuthBackendJWT

Autenticação e autorização parecem a mesma coisa quando você começa. Não são.

Confundir as duas é a origem de uma classe inteira de bugs de segurança — bugs que não aparecem em teste local mas explodem em produção com dois usuários reais.


A diferença em uma linha

Autenticação: quem é você?

Autorização: o que você pode fazer?

Autenticação → "Esse token é de João"
Autorização  → "João pode acessar /admin/relatorios?"

Autenticação acontece primeiro. Autorização usa o resultado da autenticação para tomar decisão.


O fluxo completo

sequenceDiagram
    participant C as Cliente
    participant A as API
    participant DB as Banco

    C->>A: POST /login (email+senha)
    A->>DB: verifica credenciais
    DB-->>A: usuário encontrado + roles
    A-->>C: JWT token (sub=user_id, roles=[admin])

    C->>A: GET /relatorios (Authorization: Bearer <jwt>)
    A->>A: valida JWT (autenticação)
    A->>A: verifica role=admin (autorização)
    A->>DB: busca relatórios
    DB-->>A: dados
    A-->>C: 200 + dados

Dois checks separados. Dois motivos diferentes para retornar 401 vs 403.


401 vs 403: o que o status code diz

| Status | Significa | O cliente deve | |--------|-----------|----------------| | 401 Unauthorized | Não autenticado | Fazer login | | 403 Forbidden | Autenticado mas sem permissão | Não tentar de novo (ou pedir permissão) |

Bug clássico: retornar 403 quando deveria ser 401. O cliente tenta renovar permissão em vez de renovar token. Loop de confusão.


Onde vi o bug mais comum

Um sistema que tinha endpoint /api/dados-sensiveis.

O middleware de autenticação validava o token corretamente. Mas a verificação de permissão dentro do endpoint era:

# Bug: verifica se tem campo "admin" no body da request
# não verifica o role do usuário autenticado
if request.json.get('admin') == True:
    return dados_sensiveis()

Qualquer um autenticado podia mandar {"admin": true} no body e acessar. A autenticação funcionava. A autorização estava no lugar errado.

Correto:

# Correto: lê do token JWT, não do body
if current_user.role != 'admin':
    return jsonify({'error': 'forbidden'}), 403
return dados_sensiveis()

O corpo da requisição vem do cliente e não é confiável. O token JWT é assinado pelo servidor e é confiável (dentro da validade).


O que aprendi sobre JWT que não estava no tutorial

JWT não é sessão. Não tem revogação por padrão.

Se você emite um JWT com 24h de validade e o usuário faz logout, o token ainda é válido por 24h. A menos que você implemente lista de revogação no servidor — o que elimina parte da vantagem do JWT (stateless).

Para a maioria dos casos de uso, a solução prática é: token de curta duração (15min–1h) + refresh token com revogação. O access token expira rápido. O refresh token fica no banco e pode ser revogado no logout.

Não aprendi isso no começo. Aprendi quando precisei invalidar token de usuário que reportou acesso indevido e não sabia como.


A pergunta que faz diferença

Antes de implementar qualquer verificação de acesso:

"O que estou checando aqui — se o usuário está logado, ou se o usuário tem permissão para esta ação?"

Se for "está logado": autenticação. Verifica o token.

Se for "tem permissão": autorização. Verifica role/escopo/ownership.

São implementações diferentes. São erros de segurança diferentes quando feitas errado.

Essa semana: abre um endpoint do seu projeto que protege dados sensíveis. Rastreia: onde é feita autenticação? Onde é feita autorização? São lugares diferentes no código? Se for o mesmo lugar, pode ser que estejam misturados de um jeito que vai causar problema.