Appearance
Area riservata multi-persona (esempio completo)
Questa guida mostra, passo per passo, come creare un'area di login in cui un utente accede con una sola credenziale e ottiene più aree (personas) contemporaneamente — es. Cliente + Agente + utente CRM — ciascuna con i propri permessi sui moduli decisi dall'admin.
Concetti: una credenziale = una identità; l'identità porta N grant (persona + risorsa + moduli). Vedi Accessi e Autenticazione.
Scenario d'esempio: Mario Rossi (mario.rossi@example.com) sul tenant ID_TENANT deve essere:
- CLIENTE (risorsa
C456) → può leggere la bolletta, gestire i pagamenti - AGENTE (risorsa
A123) → gestisce contratti e vede la fatturazione - CRM-USER (ruolo
operatore) → gestisce clienti e contratti nel back-office
Passo 1 — L'admin crea l'identità e assegna le aree
Le chiamate /v1/admin/* richiedono un token di un utente CRM-USER con ruolo admin del tenant.
1a. Crea l'identità
bash
curl -X POST https://api.base9.app/v1/admin/users \
-H "Authorization: Bearer $ADMIN_ID_TOKEN" -H "Content-Type: application/json" \
-d '{"email":"mario.rossi@example.com"}'
# → { "data": { "sub": "e4f1...", "email": "mario.rossi@example.com" } }Annota il sub restituito: identifica l'identità.
1b. Assegna le tre personas con i rispettivi moduli
bash
SUB="e4f1..." # dal passo 1a
# Area CLIENTE
curl -X PUT ".../v1/admin/users/$SUB/grants/CLIENTE" -H "Authorization: Bearer $ADMIN_ID_TOKEN" \
-d '{"resource_id":"C456","modules":{"bolletta":"r","pagamenti":"rw"}}'
# Area AGENTE
curl -X PUT ".../v1/admin/users/$SUB/grants/AGENTE" -H "Authorization: Bearer $ADMIN_ID_TOKEN" \
-d '{"resource_id":"A123","modules":{"contratti":"rw","fatturazione":"r"}}'
# Area CRM (ruolo operatore + moduli back-office)
curl -X PUT ".../v1/admin/users/$SUB/grants/CRM-USER" -H "Authorization: Bearer $ADMIN_ID_TOKEN" \
-d '{"role":"operatore","modules":{"clienti":"rw","contratti":"rw"}}'1c. Consegna le credenziali — imposta/comunica una password iniziale all'utente (l'utente la cambierà al primo accesso). Da questo momento Mario ha una identità con tre aree.
Passo 2 — L'utente accede (area login)
Il login avviene su POST /v1/auth/login. Puoi costruire una pagina custom (vedi §5) oppure usare la demo pronta scaricabile (vedi §6).
bash
curl -X POST https://api.base9.app/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"mario.rossi@example.com","password":"<password>"}'
# → { "data": {
# "tokens": { "id_token":"eyJ...", "refresh_token":"...", ... },
# "tenants": [ { "tenant_id":"ID_TENANT", "personas":["CLIENTE","AGENTE","CRM-USER"] } ]
# } }Il campo tenant nel body è opzionale: la risposta elenca comunque i tenant accessibili (utile per un accesso unico multi-ambiente). Per entrare in un tenant scelto dall'utente, ri-scopa il token con /v1/auth/refresh passando tenant. Al primo accesso puoi ricevere il challenge NEW_PASSWORD_REQUIRED (→ POST /v1/auth/new-password) e, se il tenant lo richiede per CRM/AGENTE, l'attivazione MFA TOTP. Dettagli: Autenticazione.
Passo 3 — Il frontend scopre le aree disponibili
Con l'id_token, il frontend chiama /v1/me/context: è qui che scopre quali box mostrare e cosa è abilitato (i moduli non sono nel token).
bash
curl -H "Authorization: Bearer $ID_TOKEN" https://api.base9.app/v1/me/contextjson
{ "data": {
"tenant": "ID_TENANT",
"personas": ["CLIENTE","AGENTE","CRM-USER"],
"agente_id": "A123", "cliente_id": "C456", "crm_role": "operatore",
"modules_per_persona": {
"CLIENTE": { "bolletta": "r", "pagamenti": "rw" },
"AGENTE": { "contratti": "rw", "fatturazione": "r" },
"CRM-USER": { "clienti": "rw", "contratti": "rw" }
},
"tenants_disponibili": [ { "tenant_id": "ID_TENANT", "personas": ["CLIENTE","AGENTE","CRM-USER"] } ]
} }Passo 4 — Cosa autorizza ciascuna area
| Area | Risorsa | Modulo | Livello | Cosa può fare Mario |
|---|---|---|---|---|
| CLIENTE | C456 | bolletta | r | vede le proprie bollette (sola lettura) |
pagamenti | rw | registra/gestisce i propri pagamenti | ||
| AGENTE | A123 | contratti | rw | crea e modifica i contratti del proprio portafoglio |
fatturazione | r | consulta lo stato fatture dei propri contratti | ||
| CRM-USER | — (tenant) | clienti | rw | gestisce l'anagrafica clienti del tenant |
contratti | rw | gestisce i contratti nel back-office |
Regole chiave:
- Isolamento: in area CLIENTE/AGENTE, il
resource_idè preso dal token → Mario vede solo i propri dati (C456 / A123), mai quelli di altri. rvsrw:r= sola lettura;rw= lettura + scrittura. Una scrittura con modulo inr→403.- Persona per route: l'area è implicita dall'endpoint —
/v1/me/agente/*(AGENTE),/v1/me/cliente/*(CLIENTE), back-office CRM sugli endpoint/v1/*.
5. Pagina di login custom (esempio minimale)
Login + salvataggio token, poi redirect all'hub che disegna le aree.
html
<!-- login: email/password → /v1/auth/login (tenant OPZIONALE); poi scelta ambiente se più di uno -->
<script>
const API = "https://api.base9.app";
async function api(path, body) {
const r = await fetch(`${API}${path}`, { method:"POST", headers:{"Content-Type":"application/json"}, body: JSON.stringify(body) });
const { data, error } = await r.json();
if (error) throw new Error(error.message);
return data;
}
async function login(email, password) {
const data = await api("/v1/auth/login", { email, password }); // niente tenant: CRM ad accesso unico
if (!data.tokens) return; /* gestisci challenge: NEW_PASSWORD_REQUIRED | SOFTWARE_TOKEN_MFA */
sessionStorage.setItem("tokens", JSON.stringify(data.tokens));
const tenants = data.tenants || [];
if (tenants.length > 1) return mostraSelettoreTenant(tenants); // l'utente sceglie l'ambiente
location.href = "./hub.html";
}
// scelta ambiente → ri-scopa il token sul tenant scelto, poi entra
async function entra(tenant) {
const t = JSON.parse(sessionStorage.getItem("tokens"));
const data = await api("/v1/auth/refresh", { refresh_token: t.refresh_token, tenant });
const nt = data.tokens; nt.refresh_token = nt.refresh_token || t.refresh_token;
sessionStorage.setItem("tokens", JSON.stringify(nt));
location.href = "./hub.html";
}
</script>html
<!-- hub: legge /v1/me/context e mostra un box per ogni area -->
<div id="aree"></div>
<script>
const API = "https://api.base9.app";
const AREE = {
"CLIENTE": { titolo: "Area Cliente", vai: "/cliente" },
"AGENTE": { titolo: "Area Agenti", vai: "/agente" },
"CRM-USER": { titolo: "CRM", vai: "/crm" },
};
(async () => {
const t = JSON.parse(sessionStorage.getItem("tokens") || "null");
if (!t) return location.href = "./login.html";
const r = await fetch(`${API}/v1/me/context`, { headers: { Authorization: "Bearer " + t.id_token } });
if (r.status === 401) return location.href = "./login.html";
const { data } = await r.json();
document.getElementById("aree").innerHTML = data.personas.map(p => {
const a = AREE[p]; if (!a) return "";
const moduli = Object.entries(data.modules_per_persona[p] || {})
.map(([m, l]) => `${m}:${l}`).join(", ");
return `<a href="${a.vai}"><h3>${a.titolo}</h3><small>${moduli}</small></a>`;
}).join("");
})();
</script>Versione completa e brandizzabile pronta all'uso: scarica la demo (vedi §6) — login + area riservata con MFA, nuova password, reset e selettore ambiente.
6. Provalo
Demo scaricabile (web app pronta): base9-portal-demo.zip — login + area riservata multi-area, si aggancia a un tenant impostato nel config. Serve solo un web server locale:
bash
unzip base9-portal-demo.zip && cd demo-portale
# apri config.js → imposta TENANT: "ID_TENANT" (o lascialo "" per scegliere l'ambiente dopo il login)
python3 -m http.server 5173
# poi apri http://localhost:5173 e accedi con un utente provisionato sul tenantTest da terminale (login → /v1/me/context → area riservata):
bash
./scripts/test-auth-e2e.sh <email> '<password>' <ID_TENANT>Vedi anche la guida sviluppatori.

