Autenticazione
Le API usano una coppia di token: un access token JWT a vita breve per ogni richiesta e un refresh token a vita lunga per rinnovarlo. Se l'account ha la MFA attiva, il login diventa un flusso in due passi.
01Il modello dei token
Ogni chiamata autenticata porta l'access token nell'header
Authorization:
Authorization: Bearer <accessToken>
- Access token: JWT firmato, durata 15 minuti (configurabile). Va rinnovato via
/auth/refresh; è revocabile per sessione. - Refresh token: opaco, conservato hashato lato server. Durata 30 giorni con
remember: true, 4 ore altrimenti. - Sessioni: ogni refresh token è una sessione visibile e revocabile da
GET /api/auth/sessions.
Tutte le risposte usano lo stesso envelope: { "success": true, "data": … }
in caso di successo, { "success": false, "error": { "code", "message" } }
in caso di errore. I dettagli nella pagina Errori e envelope.
02Login
Crea una sessione autenticata. Con credenziali valide restituisce la coppia di token; se l'account ha la MFA attiva restituisce invece una sfida MFA da completare con /auth/mfa/verify-login.
Body| Campo | Tipo | Descrizione | |
|---|---|---|---|
| identifier | string | richiesto | Username o indirizzo email dell'utente. |
| password | string | richiesto | Password in chiaro (solo su HTTPS). |
| remember | boolean | opzionale | Se true il refresh token dura 30 giorni, altrimenti 4 ore. |
curl -X POST https://crm.tuodominio.it/api/auth/login \ -H "Content-Type: application/json" \ -d '{ "identifier": "mario.rossi", "password": "•••••••", "remember": true }'
{ "success": true, "data": { "accessToken": "eyJhbGciOiJIUzI1NiIs…", "accessTokenExpiresAt": "2026-07-07T15:24:00.000Z", "refreshToken": "9f2c1e6a…", "refreshTokenExpiresAt": "2026-08-06T15:09:00.000Z", "user": { "id": 42, "username": "mario.rossi", … } } }
{ "success": true, "data": { "mfaRequired": true, "mfaToken": "eyJhbGciOiJIUzI1NiIs…" } }
| Stato | Codice | Quando |
|---|---|---|
| 401 | UNAUTHORIZED | Credenziali errate. La risposta è identica per utente inesistente e password errata (anti-enumeration). |
| 429 | TOO_MANY_REQUESTS | Account temporaneamente bloccato dopo troppi tentativi falliti, o rate limit di rotta superato. |
| 422 | VALIDATION_ERROR | identifier o password mancanti o fuori misura. |
Al primo accesso (o dopo un reset da amministratore) l'utente può avere il flag di
cambio password obbligatorio: le API rispondono
403 PASSWORD_CHANGE_REQUIRED finché la password non viene cambiata
via POST /api/auth/change-password.
03Verifica MFA
Secondo passo del login quando l'account ha la MFA TOTP attiva. Scambia la sfida ricevuta dal login con la coppia di token definitiva.
Body| Campo | Tipo | Descrizione | |
|---|---|---|---|
| mfaToken | string | richiesto | La sfida ricevuta dalla risposta del login (breve scadenza). |
| code | string | richiesto | Codice TOTP a 6 cifre dall'app authenticator. |
Identica alla risposta di login riuscito: accessToken,
refreshToken, scadenze e profilo utente.
04Rinnovo del token
Scambia un refresh token valido con un nuovo access token. Da chiamare quando l'access token è scaduto (o poco prima). Il refresh token resta lo stesso fino alla sua scadenza o revoca.
Body| Campo | Tipo | Descrizione | |
|---|---|---|---|
| refreshToken | string | richiesto | Il refresh token ottenuto dal login. |
curl -X POST https://crm.tuodominio.it/api/auth/refresh \ -H "Content-Type: application/json" \ -d '{ "refreshToken": "9f2c1e6a…" }'
| Stato | Codice | Quando |
|---|---|---|
| 401 | UNAUTHORIZED | Token scaduto, revocato o sconosciuto: l'utente deve rifare il login. |
05Logout
Revoca il refresh token (chiude la sessione). Gli access token già emessi per quella sessione smettono di essere accettati.
Body| Campo | Tipo | Descrizione | |
|---|---|---|---|
| refreshToken | string | richiesto | Il refresh token della sessione da chiudere. |
06Profilo corrente
Restituisce il profilo dell'utente autenticato: identità, ruoli e team. Utile come "chi sono" dopo il login o al bootstrap del client.
Risposta · 200{ "success": true, "data": { "user": { "id": 42, "username": "mario.rossi", "roles": ["sales"], … } } }
Aggiorna il profilo dell'utente autenticato. Tutti e quattro i campi sono richiesti (è una sostituzione del profilo, non una patch parziale).
Body| Campo | Tipo | Descrizione | |
|---|---|---|---|
| firstName | string | richiesto | 1–120 caratteri. |
| lastName | string | richiesto | 1–120 caratteri. |
| username | string | richiesto | 3–100 caratteri. |
| string | richiesto | Email valida (normalizzata in minuscolo). |
07Gestione password
Cambia la password dell'utente autenticato. È anche l'unica rotta utilizzabile quando è
attivo il flag di cambio password obbligatorio
(403 PASSWORD_CHANGE_REQUIRED sulle altre).
| Campo | Tipo | Descrizione | |
|---|---|---|---|
| currentPassword | string | richiesto | La password attuale (errata → 401). |
| newPassword | string | richiesto | La nuova password (vincoli di robustezza applicati lato server). |
| confirmPassword | string | richiesto | Deve coincidere con newPassword. |
Al cambio password tutte le sessioni vengono revocate (ogni refresh token attivo). Il client deve rifare il login subito dopo.
Avvia il reset self-service: body { "identifier": "username o email" }.
Se l'account esiste viene inviata un'email con un link a token monouso e scadenza; la
risposta 200 è sempre identica, che l'account
esista o no (anti-enumeration). Rate-limited come il login.
Completa il reset col token ricevuto via email: body
{ "token", "newPassword", "confirmPassword" }.
Il token è monouso: riutilizzarlo o usarne uno scaduto → errore.
Verifica se una password compare in data-breach noti (k-anonymity: la password non lascia
il server in chiaro). Body { "password" } → risposta con
isPwned, breachCount e
available (false se il provider
esterno non è raggiungibile: trattala come «non verificabile», non come «sicura»).
08Sessioni e cronologia accessi
Le sessioni attive dell'utente (una per refresh token non revocato e non scaduto).
current: true marca quella da cui stai chiamando.
{ "success": true, "data": { "items": [{ "id": "318", "device": "Chrome · Windows", "ipAddress": "93.44.…", "createdAt": "2026-07-07T09:12:00.000Z", "expiresAt": "2026-08-06T09:12:00.000Z", "current": true }] } }
Revoca una singola sessione (il suo refresh token smette di funzionare e gli access token di quella sessione vengono rifiutati). Sessione inesistente o non tua → 404.
«Disconnetti ovunque tranne qui»: revoca tutte le altre sessioni e risponde con
{ "revokedCount": n }.
Gli ultimi accessi (riusciti e falliti) dell'utente: items di
{ at, status, device, ipAddress }. Query
limit opzionale (default 10, massimo 50).
09Gestione MFA
Attivazione e disattivazione dell'autenticazione a due fattori (TOTP) per l'utente autenticato. La verifica in fase di login è descritta sopra.
| Metodo | Endpoint | Body | Cosa fa |
|---|---|---|---|
| POST | /api/auth/mfa/setup | · | Genera il segreto TOTP: risponde con secret e otpauthUrl (QR per l'app authenticator). La MFA resta disattiva finché non confermi. |
| POST | /api/auth/mfa/enable | { "code" } | Conferma con un codice TOTP valido: attiva la MFA e risponde con i recoveryCodes. |
| POST | /api/auth/mfa/disable | { "code" } | Disattiva la MFA (richiede un codice TOTP o di recupero valido). |
I codici di recupero vengono mostrati una sola volta nella
risposta di enable (il server ne conserva solo l'hash): falli
salvare subito all'utente. Ogni codice è monouso e vale come secondo fattore al login.
Non conservare mai i token nel localStorage di pagine esposte a
contenuti terzi. Le rotte di autenticazione hanno rate limiting dedicato e lockout
per account: gli errori 429 vanno gestiti con backoff, non con retry immediati.