obsidian-vault/ligbox-ops-platform/specs/003-desk-auth-rbac/contracts/auth-api.md
2026-06-19 17:26:42 +00:00

172 lines
3.3 KiB
Markdown

# API Contract: Desk Auth & RBAC
**Service**: Ligbox Ops Platform API (VM122)
**Base URL (LAN)**: `http://10.10.10.122:8080`
**Base URL (público)**: `https://api.ops.ligbox.com.br`
**Human Auth**: `Authorization: Bearer <JWT>`
**Machine Auth**: `X-Webhook-Secret` (webhooks only)
**Internal Auth**: `X-Ops-Internal-Token` (worker audit cycle)
---
## POST /api/v1/auth/login
Público. Não requer JWT.
```http
POST /api/v1/auth/login HTTP/1.1
Content-Type: application/json
```
### Response 200
```json
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "bearer",
"expires_in": 28800,
"username": "root",
"role": "super_admin",
"display_name": "Roger"
}
```
### Response 401
```json
{ "detail": "invalid credentials" }
```
### Response 429
```json
{ "detail": "too many login attempts" }
```
---
## GET /api/v1/auth/me
```http
GET /api/v1/auth/me HTTP/1.1
Authorization: Bearer <token>
```
### Response 200
```json
{
"username": "mini",
"role": "technician",
"display_name": "Suporte",
"active": true,
"last_login_at": "2026-06-10T12:00:00+00:00"
}
```
---
## GET /api/v1/desk/tickets (protegido)
```http
GET /api/v1/desk/tickets HTTP/1.1
Authorization: Bearer <token>
```
### Sem token → 401
```json
{ "detail": "not authenticated" }
```
### noc → 200 com dados mascarados
`company_profile.tax_id` e morada omitidos/mascarados.
---
## PATCH /api/v1/desk/tickets/{id}
```http
PATCH /api/v1/desk/tickets/11 HTTP/1.1
Authorization: Bearer <token>
Content-Type: application/json
```
| Role | Resultado |
|------|-----------|
| super_admin, ops_lead | 200 |
| technician (assigned ou unassigned) | 200 |
| technician (assigned to other) | 403 |
| noc | 403 |
---
## Webhook (inalterado — sem JWT)
```http
POST /api/v1/webhooks/onboard HTTP/1.1
Content-Type: application/json
X-Webhook-Secret: <WEBHOOK_SECRET>
```
JWT no lugar do secret → **401** (webhooks não aceitam Bearer).
---
## Health (público)
```http
GET /health HTTP/1.1
```
Sempre 200 sem auth (Traefik healthcheck).
---
## Role test matrix (curl)
```bash
API="http://10.10.10.122:8080"
TOKEN_ROOT=$(curl -sf -X POST "$API/api/v1/auth/login" \
-H "Content-Type: application/json" \
-d '{"username":"root","password":"805353"}' | python3 -c "import sys,json; print(json.load(sys.stdin)['access_token'])")
# Deve falhar sem token
curl -sf "$API/api/v1/desk/tickets" && echo UNEXPECTED || echo "401 OK"
# Deve funcionar com token
curl -sf -H "Authorization: Bearer $TOKEN_ROOT" "$API/api/v1/desk/tickets" | head -c 80
TOKEN_NOC=$(curl -sf -X POST "$API/api/v1/auth/login" \
-H "Content-Type: application/json" \
-d '{"username":"noc","password":"805353"}' | python3 -c "import sys,json; print(json.load(sys.stdin)['access_token'])")
# noc não pode fechar ticket
curl -sf -X PATCH -H "Authorization: Bearer $TOKEN_NOC" \
-H "Content-Type: application/json" \
-d '{"status":"closed"}' \
"$API/api/v1/desk/tickets/1" && echo UNEXPECTED || echo "403 OK"
```
---
## Error codes
| HTTP | Significado |
|------|-------------|
| 401 | Sem token, token inválido/expirado, credenciais login erradas |
| 403 | Token válido mas role insuficiente |
| 429 | Rate limit login |