Blu Pantheon
Référence API

Autenticazione

JWT di sessione, chiavi API e firma HMAC servizio-a-servizio: formati, scadenze, rotazione e revoca.

Blu Pantheon supporta tre metodi di autenticazione, pensati per contesti diversi. Tutte le richieste devono viaggiare su HTTPS: le chiamate in chiaro vengono rifiutate a livello di edge.

MetodoQuando usarloScadenzaRevocaDove conservarlo
Bearer JWTApplicazioni con login utente, Console, app mobile15 minuti (access), 30 giorni (refresh)Logout o revoca sessioneMemoria del processo o cookie HttpOnly
Chiave APIIntegrazioni server-to-server, script, ETLNessuna, opzionalmente a termineRevoca immediata dalla ConsoleSecret manager o variabile ambiente del backend
HMAC-SHA256Comunicazione tra servizi interni e partner certificatiFirma valida 5 minutiRotazione del segreto condivisoSecret manager, mai nel codice

Regola non negoziabile

Nessuna credenziale deve finire in codice frontend, bundle JavaScript, repository Git, log applicativi o URL. Una chiave bp_live_... committata in Git va considerata compromessa e revocata immediatamente, anche se il commit viene rimosso dalla history.

1. Bearer JWT (sessioni utente)

Usa questo metodo quando l'azione è compiuta per conto di un utente e devi ereditarne ruoli e permessi.

Login

POST/identity/v1/auth/loginPubblico

Autentica un utente con email e password e restituisce la coppia access token / refresh token.

Richiesta
{
  "email": "mario.rossi@acme.it",
  "password": "•••••••••••",
  "tenantSlug": "acme"
}
200 OK
{
  "type": "success",
  "accessToken": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c3JfNGE3YjFlOTAi...",
  "refreshToken": "rt_8c1d4f7a2b9e0563a1d8c47f2e9b0355",
  "tokenType": "Bearer",
  "expiresIn": 900,
  "user": {
    "id": "usr_4a7b1e90",
    "email": "mario.rossi@acme.it",
    "roles": ["tenant_admin"]
  }
}

Il campo tenantSlug è obbligatorio solo se l'utente appartiene a più tenant. In sua assenza, quando esistono più appartenenze, la risposta è 409 con codice TENANT_SELECTION_REQUIRED e l'elenco dei tenant disponibili in details.

Uso dell'access token

curl https://api.blupantheon.com/console/v1/sessions \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."

Claim contenuti nel token

L'access token è un JWT firmato con RSA (RS256). La chiave pubblica è pubblicata su https://api.blupantheon.com/identity/v1/.well-known/jwks.json e va usata per la verifica lato tuo.

Claim principali

ParametroTipoObblig.DefaultDescrizione
substringSì—Identificativo utente, ad esempio usr_4a7b1e90.
tidstringSì—Identificativo del tenant attivo per la sessione.
tslugstringSì—Slug leggibile del tenant, utile per il routing multi-tenant.
rolesstring[]Sì—Ruoli assegnati all’utente nel tenant attivo.
scopestringNo—Permessi effettivi separati da spazio, nel formato servizio:risorsa:azione.
expnumberSì—Timestamp Unix di scadenza. Access token: 900 secondi dall’emissione.
iatnumberSì—Timestamp Unix di emissione.
jtistringSì—Identificativo univoco del token, usato per la revoca puntuale.
issstringSì—Emittente, sempre https://api.blupantheon.com/identity.

Payload decodificato di esempio:

Payload JWT
{
  "sub": "usr_4a7b1e90",
  "tid": "tnt_2b8e4f11",
  "tslug": "acme",
  "roles": ["tenant_admin"],
  "scope": "identity:users:read identity:users:write console:sessions:read",
  "iss": "https://api.blupantheon.com/identity",
  "iat": 1788515535,
  "exp": 1788516435,
  "jti": "jti_5d0a9b3c"
}

Verifica sempre firma e scadenza

Non usare i claim senza validare la firma con le chiavi JWKS e senza controllare exp e iss. Le chiavi ruotano periodicamente: memorizza il JWKS in cache per un massimo di 10 minuti e rileggilo quando incontri un kid sconosciuto.

Refresh

POST/identity/v1/auth/refreshPubblico

Scambia un refresh token valido con una nuova coppia di token. Il refresh token usato viene invalidato (rotazione).

Richiesta
{
  "refreshToken": "rt_8c1d4f7a2b9e0563a1d8c47f2e9b0355"
}
200 OK
{
  "accessToken": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
  "refreshToken": "rt_1f6b2e94d7c3a08516ba9e2f7c4d1088",
  "tokenType": "Bearer",
  "expiresIn": 900
}

Il refresh token è a uso singolo. Se lo stesso refresh token viene presentato due volte, l'intera famiglia di token viene revocata e la risposta è 401 con codice REFRESH_TOKEN_REUSED: è il segnale di un possibile furto di credenziali e richiede un nuovo login.

Logout

POST/identity/v1/auth/logoutBearer JWT

Revoca la sessione corrente. Con allSessions a true revoca tutte le sessioni attive dell'utente.

Richiesta
{
  "refreshToken": "rt_1f6b2e94d7c3a08516ba9e2f7c4d1088",
  "allSessions": false
}
204 No Content
{}

Flusso MFA

Se l'utente ha l'autenticazione a più fattori attiva, il login non restituisce token ma una sfida.

Login iniziale

POST /identity/v1/auth/login risponde 200 con un payload di tipo mfa_required:

200 OK
{
  "type": "mfa_required",
  "mfaToken": "mfa_3e7c9a15b2d84f06",
  "methods": ["totp", "email"],
  "expiresIn": 300
}

Invio del codice

Per i metodi che richiedono l'invio di un codice (email, SMS) chiama POST /identity/v1/auth/mfa/challenge con mfaToken e method. Per TOTP questo passaggio non serve.

Richiesta
{
  "mfaToken": "mfa_3e7c9a15b2d84f06",
  "method": "email"
}

Completamento

POST /identity/v1/auth/mfa/verify scambia il codice con i token definitivi.

Richiesta
{
  "mfaToken": "mfa_3e7c9a15b2d84f06",
  "code": "418206"
}
200 OK
{
  "type": "success",
  "accessToken": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
  "refreshToken": "rt_9b0e4d7a1c62f358",
  "tokenType": "Bearer",
  "expiresIn": 900
}

Il mfaToken scade dopo 5 minuti (MFA_TOKEN_EXPIRED). Dopo 5 codici errati l'account viene bloccato temporaneamente e la risposta è 423 con codice ACCOUNT_LOCKED. I codici di recupero monouso possono essere usati al posto del codice, sullo stesso endpoint, nel campo code.

Per la configurazione lato prodotto vedi Autenticazione e MFA.

2. Chiavi API

Le chiavi API identificano un'applicazione, non una persona. Non scadono per impostazione predefinita e non richiedono refresh: sono la scelta corretta per job schedulati, integrazioni ERP e servizi backend.

Creazione

ConsoleAmministrazioneChiavi APINuova chiave

Definisci nome e ambiente

Usa un nome che identifichi il consumatore, non la persona che la crea: erp-sync-produzione è utile, chiave-mario no.

Seleziona i permessi

Assegna solo gli scope necessari, nel formato servizio:risorsa:azione. Una chiave che deve solo esportare conversazioni richiede console:sessions:read e nulla di più.

Copia il segreto

Il valore completo viene mostrato una sola volta. Salvalo subito nel secret manager.

Chiave API

bp_live_••••••••••••••••

Visibile solo alla creazione. Non recuperabile in seguito.

Formato e prefissi

PrefissoAmbienteNote
bp_live_ProduzioneOpera su dati reali
bp_stg_StagingDati anonimizzati
bp_test_SandboxDati sintetici, nessun effetto reale

La chiave è composta da prefisso e da un segreto casuale. Nel database Blu Pantheon conserva solo l'hash SHA-256 del segreto e i primi caratteri in chiaro, usati per identificare la chiave nella Console e nei log di audit. Per questo motivo il valore completo non è recuperabile dopo la creazione.

Uso

curl https://api.blupantheon.com/console/v1/clients?limit=50 \
  -H "Authorization: Bearer bp_live_xxxxxxxxxxxxxxxx"

Mai in query string

Non passare la chiave come parametro di query (?apiKey=...). Le query string finiscono nei log dei proxy, nella cronologia del browser e negli header Referer. L'unico canale supportato è l'header Authorization.

Scope e permessi

Una chiave non può avere più permessi dell'utente che l'ha creata al momento della creazione. Se i permessi dell'utente vengono ridotti in seguito, la chiave mantiene gli scope assegnati fino alla revisione esplicita: rivedi le chiavi attive a ogni cambio di ruolo rilevante.

Quando una chiave chiama un endpoint fuori dai propri scope la risposta è 403 con codice INSUFFICIENT_PERMISSIONS e l'elenco degli scope mancanti in details.

Rotazione

Crea la nuova chiave

Genera una seconda chiave con gli stessi scope, con un nome che indichi la data (erp-sync-2026-09).

Distribuisci e verifica

Aggiorna il secret manager e riavvia i consumatori. Verifica nella Console che la nuova chiave registri traffico e che le chiamate risultino andate a buon fine.

Revoca la vecchia

Solo dopo aver confermato che la chiave precedente non registra più utilizzi da almeno 24 ore, revocala. La revoca è immediata e non reversibile.

Consigliamo una rotazione almeno semestrale e una rotazione immediata dopo ogni sospetto di esposizione o dopo l'uscita di una persona con accesso al secret manager.

Revoca

DELETE/identity/v1/api-keys/{keyId}Bearer JWT

Revoca immediatamente una chiave API. Le richieste in corso non vengono interrotte, le successive falliscono con 401.

200 OK
{
  "id": "key_6d3f0a82",
  "name": "erp-sync-produzione",
  "status": "revoked",
  "revokedAt": "2026-09-04T10:32:15.482Z"
}

Dopo la revoca ogni chiamata con quella chiave riceve 401 con codice API_KEY_REVOKED.

3. HMAC servizio-a-servizio

Usato per la comunicazione tra servizi interni e per i partner che richiedono garanzie di integrità oltre alla riservatezza del canale TLS. Ogni consumatore riceve un keyId pubblico e un segreto condiviso.

Header richiesti

Header di firma

ParametroTipoObblig.DefaultDescrizione
X-BP-Key-IdstringSì—Identificativo pubblico della coppia di chiavi, ad esempio svc_billing_01.
X-BP-TimestampnumberSì—Timestamp Unix in secondi al momento della firma. Tolleranza massima 300 secondi.
X-BP-NoncestringSì—Valore casuale univoco per richiesta, usato per prevenire replay.
X-BP-SignaturestringSì—Firma nel formato t=<unix>,v1=<hex>, dove la parte v1 è l’HMAC-SHA256 in esadecimale minuscolo.

Stringa da firmare

Gli elementi vengono concatenati con il carattere di ritorno a capo \n, nell'ordine seguente:

Stringa canonica
<METODO>\n
<PATH_CON_QUERY>\n
<X-BP-TIMESTAMP>\n
<X-BP-NONCE>\n
<SHA256_HEX_DEL_BODY>

Esempio concreto per POST /billing/v1/usage con body {"tenantId":"tnt_2b8e4f11","units":42}:

Esempio
POST
/billing/v1/usage
1788515535
n_7c2a94f0e13b
3f8a1c9e2b7d0546a83f1c9b0e7d2a45f8c31b9e0d7a24f6c8b135e0a97d4f26

Implementazione in Node.js:

hmac.ts
import { createHash, createHmac, randomBytes } from 'node:crypto';

export function signRequest(
  method: string,
  pathWithQuery: string,
  body: string,
  keyId: string,
  secret: string,
): Record<string, string> {
  const timestamp = Math.floor(Date.now() / 1000).toString();
  const nonce = `n_${randomBytes(6).toString('hex')}`;
  const bodyHash = createHash('sha256').update(body, 'utf8').digest('hex');

  const canonical = [method.toUpperCase(), pathWithQuery, timestamp, nonce, bodyHash].join('\n');
  const signature = createHmac('sha256', secret).update(canonical, 'utf8').digest('hex');

  return {
    'X-BP-Key-Id': keyId,
    'X-BP-Timestamp': timestamp,
    'X-BP-Nonce': nonce,
    'X-BP-Signature': `t=${timestamp},v1=${signature}`,
    'Content-Type': 'application/json',
  };
}

Il body va firmato byte per byte esattamente come viene trasmesso: non riserializzare il JSON dopo la firma, perché un diverso ordinamento delle chiavi o una spaziatura differente invalidano l'hash.

Lo stesso schema di firma è usato in direzione opposta per i webhook in uscita: vedi Riferimento webhook e Firma HMAC.

Errori di autenticazione più frequenti

Il catalogo completo è in Errori.

Sur cette page