# BASE9 — Autenticazione & Identità (guida sviluppatori)

Modello di identità unificato **multi-persona**. Una credenziale (email + password) = una **identità**; l'identità può assumere più **personas** (CLIENTE, AGENTE, CRM-USER) su uno o più tenant, ognuna con i propri moduli e la propria risorsa. Tutto il flusso è **headless** (API): puoi costruire una login page custom.

- Base URL: `https://api.base9.app`
- Autenticazione utente: **JWT** (`Authorization: Bearer <id_token>`)
- Integrazione server-to-server: **API key** `dmk_...` (separata, vedi in fondo)
- Spec macchina: [`openapi.json`](https://www.base9.app/api-reference/openapi.json) · UI: [/api-reference/](https://www.base9.app/api-reference/)

---

## Concetti

| Termine | Significato |
|---|---|
| **Identità** | il login: email + password [+ 2FA TOTP] |
| **Persona** | tipo di accesso/area: `CLIENTE`, `AGENTE`, `CRM-USER` (assegnate dall'admin del tenant) |
| **Grant** | persona + tenant + risorsa (`agente_id`/`cliente_id`) + moduli (`r`/`rw`) |
| **Token tenant-scoped** | il JWT vale per **un tenant attivo**; per cambiare tenant si fa refresh con l'hint |

Il JWT (id_token) contiene: `sub`, `email`, `tenant_id`, `personas` (CSV), `agente_id`, `cliente_id`, `crm_role`. I **moduli non sono nel token**: si leggono da `GET /v1/me/context`.

---

## 1. Login

```bash
curl -X POST https://api.base9.app/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"mario@x.it","password":"..."}'
```
Il campo **`tenant` è opzionale**: la risposta include comunque l'**elenco dei tenant accessibili** (CRM ad accesso unico → login unico, poi scelta ambiente). Passa `tenant` solo se vuoi già scoped su un ambiente (es. pagina brandizzata).

**Risposta — successo:**
```json
{ "data": {
  "tokens": { "access_token":"...", "id_token":"...", "refresh_token":"...", "expires_in":3600, "token_type":"Bearer" },
  "tenants": [ { "tenant_id":"ID_TENANT", "personas":["AGENTE","CLIENTE"] } ]
} }
```
Il token è scoped su un tenant (quello in `tenant`, o il primo). Per entrare in un tenant scelto dall'utente, ri-scopa con `/v1/auth/refresh` passando `tenant` (§4).
**Risposta — challenge (MFA o nuova password):**
```json
{ "data": { "challenge": "SOFTWARE_TOKEN_MFA", "session": "..." } }
```

Usa **`id_token`** come Bearer per chiamare le API.

---

## 2. MFA (TOTP) — 2° fattore complementare

Enrollment (utente autenticato, serve `access_token`):
```bash
curl -X POST .../v1/auth/mfa/setup       -d '{"access_token":"...","email":"mario@x.it"}'
# -> { "data": { "secret":"...", "otpauth_uri":"otpauth://totp/BASE9:mario@x.it?secret=..." } }
curl -X POST .../v1/auth/mfa/verify-setup -d '{"access_token":"...","code":"123456"}'
```
Se al login arriva il challenge `SOFTWARE_TOKEN_MFA`:
```bash
curl -X POST .../v1/auth/mfa/verify -d '{"email":"mario@x.it","session":"...","code":"123456","tenant":"ID_TENANT"}'
```

## 3. Prima password (onboarding/migrazione)
Se il login torna il challenge `NEW_PASSWORD_REQUIRED`:
```bash
curl -X POST .../v1/auth/new-password -d '{"email":"...","session":"...","new_password":"...","tenant":"..."}'
```

## 4. Refresh & cambio tenant
```bash
curl -X POST .../v1/auth/refresh -d '{"refresh_token":"...","tenant":"altro-tenant"}'
```
Passando un `tenant` diverso (dove l'identità ha un grant) ottieni un token scoped su quel tenant → **switch area/tenant** senza re-login.

## 5. Password: reset & change
```bash
curl -X POST .../v1/auth/password/forgot  -d '{"email":"..."}'                     # invia codice (via email)
curl -X POST .../v1/auth/password/reset   -d '{"email":"...","code":"...","new_password":"..."}'
curl -X POST .../v1/auth/password/change  -d '{"access_token":"...","old_password":"...","new_password":"..."}'
```

## 6. Logout
```bash
curl -X POST .../v1/auth/logout -d '{"access_token":"..."}'
```

---

## 7. Contesto utente & aree — `GET /v1/me/context`

Il frontend, dopo il login, chiama questo endpoint per sapere **quali aree mostrare** e **quali moduli** sono abilitati (i moduli NON sono nel token):
```bash
curl -H "Authorization: Bearer $ID_TOKEN" https://api.base9.app/v1/me/context
```
```json
{ "data": {
  "tenant": "ID_TENANT",
  "personas": ["CLIENTE","AGENTE"],
  "agente_id": "A123", "cliente_id": "C456", "crm_role": null,
  "modules_per_persona": { "CLIENTE": {"bolletta":"r","pagamenti":"rw"}, "AGENTE": {"contratti":"rw","fatturazione":"r"} },
  "tenants_disponibili": [ {"tenant_id":"ID_TENANT","personas":["CLIENTE","AGENTE"]} ]
} }
```

## 8. Aree self-service — `/v1/me/*`
La persona con cui agisci è **implicita dalla route**; il `resource_id` è preso SEMPRE dal token (isolamento garantito).
- **AGENTE**: `GET /v1/me/agente`, `/v1/me/agente/contratti`, `/v1/me/agente/contratti/{id}`, `/v1/me/agente/andamento`, `/v1/me/agente/superiori`
- **CLIENTE**: `GET /v1/me/cliente`, `/v1/me/cliente/contatti`

## 9. Amministrazione RBAC (admin del tenant)
Scope-gated (`users:*`/`roles:*`), con header **`X-Tenant-Id`** per il tenant attivo. Guida completa: [RBAC — ruoli, scope e permessi](https://www.base9.app/manuale/guide/rbac).
```bash
GET    /v1/scopes                               # catalogo scope
GET/POST/PUT/DELETE /v1/roles[/{id}]            # tipi-utenza (insiemi di scope)
GET/POST /v1/users                              # elenco / crea identità
GET/DELETE /v1/users/{sub}                       # dettaglio / rimuovi dal tenant
POST   /v1/users/{sub}/disable|enable           # sospendi / riattiva
PUT    /v1/users/{sub}/grants/{persona}  {"roles":["clienti_rw"],"resource_id":"A...","scopes_extra":[...]}
DELETE /v1/users/{sub}/grants/{persona}          # revoca area
```
**Enforcement**: ogni endpoint dati richiede uno scope `risorsa:azione` (es. `clienti:write`); senza → `403`. Admin del tenant bypassa; API key usa il suo scope r/rw. *(`/v1/admin/users*` resta come alias.)*

---

## 10. Errori
Formato uniforme:
```json
{ "error": { "type":"authentication_error", "code":"not_authorized", "message":"Credenziali non valide" } }
```
Codici comuni: `not_authorized` (401), `code_mismatch`/`invalid_password` (400), `rate_limited` (429), `route_not_found` (404).

## 11. API key (integrazione server-to-server)
Per integrazioni backend che NON sono login utente, usa una **API key personale** `dmk_...`:
```
Authorization: Bearer dmk_xxxxxxxx
```
Legata a un singolo tenant, scope `r`/`rw`. Chiedila all'admin del tenant.

---

## Provalo subito
- **Web app demo**: scarica [base9-portal-demo.zip](https://www.base9.app/developers/base9-portal-demo.zip), imposta il tenant in `config.js`, poi `python3 -m http.server 5173` e apri `http://localhost:5173`.
- **Da terminale**: `scripts/test-auth-e2e.sh <email> '<password>' <ID_TENANT>` (login → `/v1/me/context` → area riservata).
