Ir para o conteúdo

MundiX - API de Autenticação

Task: MX-2026-000123
Implementado: 2026-02-03


Endpoints

POST /auth/register

Registrar novo usuário.

Request:

{
  "username": "johndoe",
  "email": "john@example.com",
  "password": "SecurePass123!",
  "is_admin": false
}

Response (201):

{
  "id": 1,
  "username": "johndoe",
  "email": "john@example.com",
  "is_active": true,
  "is_admin": false,
  "created_at": "2026-02-03T17:30:00Z"
}


POST /auth/login

Login e receber tokens.

Request (OAuth2 form):

username=johndoe
password=SecurePass123!

Response (200):

{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "refresh_token": "a1b2c3d4e5f6...",
  "token_type": "bearer",
  "expires_in": 900
}

  • access_token: JWT válido por 15 minutos
  • refresh_token: Opaque token válido por 7 dias

POST /auth/refresh

Renovar access token usando refresh token.

Request:

{
  "refresh_token": "a1b2c3d4e5f6..."
}

Response (200):

{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "refresh_token": "z9y8x7w6v5u4...",
  "token_type": "bearer",
  "expires_in": 900
}

Importante: - Refresh token antigo é revogado automaticamente - Usar refresh token revogado retorna 401


POST /auth/logout

Logout (revoga refresh token).

Request:

{
  "refresh_token": "a1b2c3d4e5f6..."
}

Response (204 No Content)


GET /auth/me

Obter informações do usuário autenticado.

Headers:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Response (200):

{
  "id": 1,
  "username": "johndoe",
  "email": "john@example.com",
  "is_active": true,
  "is_admin": false,
  "created_at": "2026-02-03T17:30:00Z"
}


Protegendo Endpoints

Use a dependency get_current_user para proteger endpoints:

from fastapi import Depends
from api.dependencies import get_current_user
from common.models import User

@app.get("/protected")
async def protected_endpoint(current_user: User = Depends(get_current_user)):
    return {"message": f"Hello {current_user.username}!"}

Verificar Admin

from api.dependencies import get_current_admin_user

@app.post("/admin/action")
async def admin_action(current_user: User = Depends(get_current_admin_user)):
    # Only admins can access
    return {"message": "Admin action completed"}

Fluxo de Autenticação

┌─────────────┐
│   Client    │
└──────┬──────┘
       │ 1. POST /auth/login
       │    {username, password}
┌────────────────────────────┐
│  API: /auth/login          │
│  - Valida credenciais      │
│  - Gera access_token (JWT) │
│  - Gera refresh_token      │
│  - Salva refresh no DB     │
└──────┬─────────────────────┘
       │ 2. Response
       │    {access_token, refresh_token}
┌─────────────┐
│   Client    │
│  (armazena) │
└──────┬──────┘
       │ 3. GET /agents
       │    Authorization: Bearer <access_token>
┌────────────────────────────┐
│  Middleware: verify_token  │
│  - Valida JWT              │
│  - Extrai user_id          │
│  - Injeta current_user     │
└──────┬─────────────────────┘
       │ 4. Response {agents: [...]}
┌─────────────┐
│   Client    │
└──────┬──────┘
       │ (após 15 min, access_token expira)
       │ 5. POST /auth/refresh
       │    {refresh_token}
┌────────────────────────────┐
│  API: /auth/refresh        │
│  - Valida refresh_token    │
│  - Revoga token antigo     │
│  - Gera novos tokens       │
└──────┬─────────────────────┘
       │ 6. Response
       │    {access_token (novo), refresh_token (novo)}
┌─────────────┐
│   Client    │
└─────────────┘

Exemplo de Uso (cURL)

1. Registrar usuário

curl -X POST http://localhost:8001/auth/register \
  -H "Content-Type: application/json" \
  -d '{
    "username": "testuser",
    "email": "test@example.com",
    "password": "TestPass123!"
  }'

2. Login

curl -X POST http://localhost:8001/auth/login \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "username=testuser&password=TestPass123!"

Resposta:

{
  "access_token": "eyJ...",
  "refresh_token": "abc...",
  "token_type": "bearer",
  "expires_in": 900
}

3. Acessar endpoint protegido

export TOKEN="eyJ..."  # Access token do login

curl http://localhost:8001/agents \
  -H "Authorization: Bearer $TOKEN"

4. Refresh token

export REFRESH="abc..."  # Refresh token do login

curl -X POST http://localhost:8001/auth/refresh \
  -H "Content-Type: application/json" \
  -d '{"refresh_token": "'$REFRESH'"}'

5. Logout

curl -X POST http://localhost:8001/auth/logout \
  -H "Content-Type: application/json" \
  -d '{"refresh_token": "'$REFRESH'"}'

Exemplo Python Client

import requests

BASE_URL = "http://localhost:8001"

# 1. Login
response = requests.post(
    f"{BASE_URL}/auth/login",
    data={"username": "testuser", "password": "TestPass123!"}
)
tokens = response.json()

access_token = tokens["access_token"]
refresh_token = tokens["refresh_token"]

# 2. Acessar API protegida
headers = {"Authorization": f"Bearer {access_token}"}

agents = requests.get(f"{BASE_URL}/agents", headers=headers).json()
print(agents)

# 3. Refresh quando access token expirar
response = requests.post(
    f"{BASE_URL}/auth/refresh",
    json={"refresh_token": refresh_token}
)
new_tokens = response.json()

access_token = new_tokens["access_token"]
refresh_token = new_tokens["refresh_token"]

# 4. Logout
requests.post(
    f"{BASE_URL}/auth/logout",
    json={"refresh_token": refresh_token}
)

Testes

Ver tests/test_auth.py (MX-2026-000123-C).


Security Review

Ver docs/SECURITY_REVIEW_MX-2026-000123.md (MX-2026-000123-D).


Arquivos Implementados

  • common/auth.py - Crypto utils (JWT, bcrypt, SHA256)
  • common/models.py - Models User + RefreshToken
  • api/auth.py - Endpoints /auth/*
  • api/dependencies.py - Middlewares get_current_user
  • api/main.py - Registrar auth router
  • docs/auth.md - Este documento
  • docs/ADR-001-auth.md - Architecture Decision Record

Status: ✅ Implementação completa
Próxima etapa: Testes (MX-2026-000123-C)