1. Chiave publishable: identifica il negozio
- Cosa fa: dice all’API quale negozio. Come le chiavi pubbliche di Stripe, può stare nel client (web/mobile).
- Cosa NON fa: non autentica un utente e sugli endpoint
/admin/*viene rifiutata (403api_key.admin_route_forbidden). Il raggio d’azione di una chiave trapelata è limitato allo storefront. - Formato:
cx_pk_<live|test>_<slug>_<random>. Usatestsolo in sviluppo. - Può avere restrizioni di origin e può essere ruotata o revocata dal gestore. Chiave
errata o revocata: 401
api_key.invalid; origin non ammessa: 403api_key.origin_not_allowed.
2. Sessione cliente: account dello shopper
Per le aree account (ordini, indirizzi, wishlist, abbonamenti) il cliente fa login e ottiene una coppia di token:
Registrazione e login:
POST /auth/register, POST /auth/login (con 2FA se attiva),
POST /auth/refresh, POST /auth/logout, login social Google e Apple quando il negozio li ha
attivati (GET /auth/social-providers). Vedi la API Reference.
Gli account cliente appartengono a un negozio: la stessa email può avere un account in
negozi diversi. Registrazione e login vanno quindi fatti nel contesto del negozio, cioè dal
suo dominio oppure con l’header
X-Vellaro-Key.Refresh a rotazione
Ogni login apre una sessione. A ogniPOST /auth/refresh il refresh token presentato
viene superato e la risposta ne porta uno nuovo: salvalo sempre al posto del vecchio,
insieme al nuovo access token.
I refresh token emessi prima del rilascio del 10 ottobre 2026 valgono una volta: al primo
uso aprono una sessione nuova e passano al nuovo schema, quindi nessuno viene disconnesso dal
rilascio. Ogni account conserva al massimo 20 sessioni: oltre, la più vecchia si chiude.
Nel client:
- Su un 401 di una chiamata qualsiasi, chiama
POST /auth/refresh, salva la coppia nuova e ripeti la richiesta. - Fai un solo refresh alla volta: le richieste che ricevono 401 nello stesso momento aspettano lo stesso rinnovo.
- Su 401 da
/auth/refresh(auth.session_revoked,auth.refresh_token_reused,auth.refresh_token_invalid) o su 403auth.tenant_unavailable, cancella i token e porta l’utente al login. - Su errori di rete o 5xx non buttare la sessione: riprova più tardi.
Logout
POST /auth/logoutcon{"refresh_token": "..."}nel corpo chiude questa sessione: da quel momento quel refresh token risponde 401auth.session_revoked. È idempotente e non richiede l’access token. L’access token vale fino alla sua scadenza: buttalo nel client.POST /auth/logout?all=truechiude tutte le sessioni dell’account, su ogni dispositivo («esci da tutti i dispositivi»). Serve una credenziale valida: l’headerAuthorization: Bearer <access_token>, oppure il refresh token nel corpo se l’access token è già scaduto. Senza: 401auth.not_authenticated.
auth.session_revoked: si torna al
login. Revocano le sessioni anche il reset della password, il cambio password (vedi la nota
qui sotto), l’attivazione e la disattivazione della 2FA e la disattivazione dell’account da
parte del negozio.
Le chiamate che revocano le sessioni dal dispositivo dell’utente restituiscono i token nuovi
per quel dispositivo: adottali subito, altrimenti la chiamata successiva riceve 401
auth.session_revoked. Vale per POST /auth/change-password (revoca sempre), per
POST /auth/2fa/verify alla prima attivazione e per POST /auth/2fa/disable.
POST /users/me/change-password revoca e restituisce i token solo se mandi l’header
X-Session-Rotation: 1; senza, risponde come sempre e non chiude nessuna sessione.Verifica in due passaggi (2FA)
- Attivazione:
POST /auth/2fa/setupcon{"current_password": "..."}restituiscesecreteqr_urida mostrare come QR code. PoiPOST /auth/2fa/verifycon{"code": "123456", "current_password": "..."}attiva la 2FA, chiude le altre sessioni e risponde con i token nuovi più 10 codici di recupero (recovery_codes). - Codici di recupero: hanno la forma
xxxxx-xxxxx, valgono una volta e vanno mostrati all’utente una sola volta, alla risposta di attivazione. Ognuno sostituisce il codice dell’app al login e per disattivare la 2FA. - Login: con la 2FA attiva il primo
POST /auth/loginrisponde 401auth.totp_required. Ripeti la stessa chiamata contotp_code, che accetta il codice dell’app oppure un codice di recupero. Ogni codice TOTP vale una volta sola: lo stesso codice ripresentato dà 401auth.totp_invalid. - Rigenerazione:
POST /auth/2fa/recovery-codescon{"current_password": "..."}restituisce 10 codici nuovi; i vecchi smettono di valere.GET /auth/meesponerecovery_codes_remaining(nullcon la 2FA spenta): quando scende vicino a 0, invita l’utente a rigenerarli. - Disattivazione:
POST /auth/2fa/disablecon{"code": "..."}(codice dell’app o di recupero). Chiude le altre sessioni, azzera i codici di recupero e restituisce i token nuovi.
GET /auth/2fa/setup è deprecata: non crea più un segreto. Errori tipici della 2FA:
400 auth.current_password_wrong, auth.no_password_set (account solo social),
auth.totp_already_enabled, auth.totp_not_enabled, auth.totp_invalid.
Negozio eliminato
Se il negozio dell’account non esiste più:POST /auth/login(con la password giusta) ePOST /auth/refreshrispondono 403auth.tenant_unavailable;- ogni altra chiamata autenticata con un token di quel negozio risponde 401
auth.tenant_unavailable.
3. Token staff: Admin API
Gli endpoint/admin/* richiedono un account staff (JWT) con i permessi giusti
(catalog, sales, customers, marketing, content, reviews, reports, tax, shipping, system,
users).
- Il login è lo stesso
POST /auth/login, con le credenziali di un utente staff. Valgono le stesse regole di rotazione, con la regola stretta sul riuso descritta sopra. - Il token porta il claim
tenant_id: ogni sessione è vincolata al suo negozio (isolamento multi-tenant a prova di leak). - Per automazioni e agenti che lavorano a lungo c’è il token API: si usa come Bearer, senza login né refresh, con una scadenza obbligatoria. Vedi Gestisci il negozio via API.
- Le mutazioni admin sono audit-loggate.
- Le chiavi publishable non danno mai accesso qui.
Codici di errore auth comuni
Gli endpoint
/auth/* hanno limiti per IP (login 10 al minuto, refresh 30 al minuto, 2FA e
cambio password 5 o 10 al minuto). Oltre il limite la risposta è 429, senza la busta
standard: {"detail": "Rate limit exceeded: ..."}.