Autenticação e Autorização
Aula 3 de 7
Autenticação vs Autorização
Autenticação (AuthN): quem é você?
├── Login, JWT, OAuth, API Keys
├── HTTP headers: Authorization: Bearer <token>
Autorização (AuthZ): o que você pode fazer?
├── Permissões, roles, scopes
├── Baseada em: RBAC, ABAC, Claims
JWT — JSON Web Token
Header: {"alg": "HS256", "typ": "JWT"}
Payload: {"sub": "123", "name": "João", "iat": 1710000000, "exp": 1710086400}
Signature: HMACSHA256(base64(header) + "." + base64(payload), secret)
Token completo: header.payload.signature
Formato: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjMifQ.xXxXxXxX
# Geração de JWT (Python)
import jwt
import datetime
payload = {
"sub": "user_123",
"name": "João Silva",
"roles": ["admin", "operator"],
"iat": datetime.datetime.utcnow(),
"exp": datetime.datetime.utcnow() + datetime.timedelta(hours=1)
}
token = jwt.encode(payload, "secret-key", algorithm="HS256")
Validação no Servidor
def verify_token(request):
auth = request.headers.get("Authorization")
if not auth or not auth.startswith("Bearer "):
return 401
token = auth.removeprefix("Bearer ")
try:
payload = jwt.decode(token, "secret-key", algorithms=["HS256"])
request.user = payload
except jwt.ExpiredSignatureError:
return 401
except jwt.InvalidTokenError:
return 401
OAuth 2.0 — Delegação de Acesso
┌────────────┐ ┌────────────┐ ┌────────────┐
│ Cliente │────▶│ Auth Server│────▶│ Resource │
│ (App) │◀────│ (Keycloak) │◀────│ (API) │
└────────────┘ └────────────┘ └────────────┘
│ │
│ 1. Authorization │
│ 2. Code │
│ 3. Code+Secret │
│ 4. Access Token │
│ 5. Token → API │
# Authorization Code Flow (recomendado)
# 1. Redirect usuário para auth server
https://auth.empresa.com/auth?response_type=code&client_id=app&redirect_uri=https://app.com/callback
# 2. Receber code
GET /callback?code=abc123
# 3. Trocar code por token
curl -X POST https://auth.empresa.com/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code&code=abc123&redirect_uri=https://app.com/callback&client_id=app&client_secret=secret"
# Response
{
"access_token": "eyJhbG...",
"refresh_token": "def456...",
"expires_in": 3600,
"token_type": "Bearer"
}
API Keys
# Para machine-to-machine (M2M)
GET /api/v1/data
X-API-Key: abc-def-ghi-123
# Geração
import secrets
api_key = secrets.token_urlsafe(32) # 43 chars
# Storage: hash da chave (bcrypt), não plaintext
# Rate limit por API Key
Rate Limiting
Headers de Rate Limit:
X-RateLimit-Limit: 100 ← max requests
X-RateLimit-Remaining: 87 ← remaining
X-RateLimit-Reset: 1710086400 ← reset timestamp
429 Too Many Requests
Retry-After: 30 ← segundos para esperar
# Rate limiting com Redis
import redis
import time
r = redis.Redis()
def check_rate_limit(client_id: str, max_requests: int = 100, window: int = 60):
key = f"rate:{client_id}:{int(time.time() / window)}"
count = r.incr(key)
if count == 1:
r.expire(key, window)
return count <= max_requests
Boas Práticas
✅ Segurança:
- JWT com exp curta (15 min), refresh token longa (7 dias)
- Sempre valide signature e exp
- Armazene tokens em httpOnly cookies (não localStorage)
- CSRF tokens para state-changing endpoints
- Rate limit por IP, API Key e User
✅ Senhas (se aplicável):
- Hash com bcrypt/argon2
- NUNCA armazene plaintext
- Mínimo 8 chars, sem limites absurdos
- Rate limit no login (5 tentativas/15 min)
JWT é stateless (não precisa de sessão no servidor). OAuth 2.0 é o padrão para delegação de acesso. Rate limiting protege contra abuso. Sempre use refresh tokens — não faça JWT com exp de dias.