← Developers

03.1 — Autenticazione, ruoli e scope

Spec riferita a SPEC-DX-01 / api v1

L’Invariante

Una credenziale, un confine. Una credenziale emessa per una superficie non funziona mai silenziosamente su un’altra: le key edge guidano il canale sync, le sessioni PIN guidano le azioni kernel, le sessioni portale guidano l’API tenant, le sessioni admin guidano le operations. Il least privilege è strutturale — un token bridge fisicamente non può aprire un lotto.

Il Contratto

Credenziale Emessa da Valida su Scope
Sessione PIN operatore POST /api/v1/auth/login (edge) /api/v1/actions/*, /api/v1/auth/*, /api/v1/audit/verify role-scoped (permissions del manifest)
Edge API key (bootstrap claim) POST /api/v1/bootstrap/claim /api/v1/sync/* sync (default) / full
Sessione portale POST /api/v1/portal/login o claim invito pi_* /api/v1/tenant/*, /api/v1/portal/* owner / member
Sessione admin POST /api/v1/admin/login /api/v1/admin/* solo ops, ogni mutazione audit-loggata

Registro ruoli (manifest production-line): MAGAZZINIERE (trigger di recezione + letture), OPERATORE (trigger di lavorazione), QUALITA (trigger di collaudo), ADMIN (wildcard). I ruoli vivono nel rbac_engine del manifest — ogni verticale dichiara i propri.

Il Flusso

edge:  PIN → /auth/login → sessione (TTL 12h, ax_sessions, revocabile)
            PIN condiviso? → 409 PIN_AMBIGUOUS {candidates:[{operatorId,name}]}
            → rimanda con operatorId
cloud: email+password → /portal/login → sessione (12h)
            email su >1 tenant? → 401 TENANT_AMBIGUOUS → passa tenant_id
sync:  token bt_* monouso → /bootstrap/claim → {tenant_id, api_key}
            il re-claim RUOTA la key — la vecchia muore all'istante

Esempio di Payload

# Sessione operatore edge
curl -s http://edge:8291/api/v1/auth/login -H 'content-type: application/json' \
  -d '{"tenantId":"<uuid>","deviceCode":"IPC-01","pin":"1234"}'
# → {"token":"…","expiresInHours":12,"context":{"tenantId":"…","operatorId":"…","role":"MAGAZZINIERE","deviceId":"IPC-01"}}

# Sessione portale cloud
curl -s https://cp.axiom-trace.eu/api/v1/portal/login -H 'content-type: application/json' \
  -d '{"email":"qa@customer.com","password":"…"}'
# → {"token":"…","tenant_id":"…","role":"owner","display_name":"…"}

I Fallimenti Noti

Sintomo Causa → fix
409 PIN_AMBIGUOUS PIN condiviso → rimanda con operatorId dai candidates
401 TENANT_AMBIGUOUS Email su più tenant → passa tenant_id esplicito
401 su /tenant/* con ak_* Scope della key è sync → la superficie portale vuole una sessione portale o key full
403 con login valido Binding origine (portal_origin) o tetto di ruolo (member vs rotta owner-only)
Login ok, azioni 401 TTL sessione 12h — rifai login; mai cachare token oltre il TTL