Skip to Content

Rate Limiting

Auris applica rate limit su tutti gli endpoint API per proteggere la piattaforma dagli abusi, prevenire attacchi di credential stuffing e garantire un’allocazione equa delle risorse tra i tenant. Questa guida spiega i livelli di rate limiting, come leggere gli header dei limiti, come gestire le risposte 429 Too Many Requests nella tua applicazione e come configurare i limiti.

Livelli di Rate Limiting

Auris applica rate limit diversi in base alla sensibilità e al costo delle risorse di ciascun endpoint. Ci sono quattro livelli:

Livello Auth (Rigoroso)

Si applica agli endpoint di autenticazione che gestiscono le credenziali:

  • POST /api/auth/login (login email/password)
  • POST /api/auth/signup (registrazione utente)
  • POST /api/auth/token (scambio e refresh token)
  • POST /api/auth/magic-link (avvio magic link)
  • POST /api/auth/passwordless/* (flussi passwordless)
  • POST /api/oauth/authenticate (invio form login ospitato)

Questi endpoint hanno i limiti più restrittivi perché sono il bersaglio principale degli attacchi di credential stuffing e brute-force.

Limiti predefiniti: Poche richieste al minuto per IP, con limiti aggiuntivi per account sugli endpoint di login.

Livello Sensitive (Moderato)

Si applica alle operazioni critiche per la sicurezza che non dovrebbero essere chiamate frequentemente:

  • POST /api/user/2fa/* (iscrizione e verifica 2FA)
  • POST /api/auth/forgot-password (avvio reset password)
  • POST /api/auth/change-password (cambio password)
  • POST /api/user/phone/* (verifica numero di telefono)

Limiti predefiniti: Richieste moderate al minuto per IP e per utente.

Livello API (Standard)

Si applica agli endpoint API autenticati generali:

  • GET/POST/PATCH/DELETE /api/users/*
  • GET/POST/PATCH/DELETE /api/roles/*
  • GET/POST/PATCH/DELETE /api/organizations/*
  • GET/POST/PATCH/DELETE /api/applications/*
  • Tutti gli altri endpoint CRUD autenticati

Limiti predefiniti: Richieste standard al minuto per utente autenticato.

Livello Public (Rilassato)

Si applica agli endpoint aperti che non richiedono autenticazione:

  • GET /.well-known/openid-configuration (OIDC Discovery)
  • GET /.well-known/jwks.json (JWKS)
  • GET /api/public/* (pagine di stato pubbliche, pagine di verifica)
  • POST /api/scim/v2/* (provisioning SCIM con bearer token)

Limiti predefiniti: Limiti generosi, solo basati su IP.

Lettura degli Header dei Rate Limit

Ogni risposta da un endpoint con rate limit include header standard che indicano lo stato corrente della finestra di rate limit:

HeaderTipoDescrizione
X-RateLimit-LimitInteroNumero massimo di richieste consentite nella finestra corrente
X-RateLimit-RemainingInteroNumero di richieste rimanenti prima di raggiungere il limite
X-RateLimit-ResetUnix timestampQuando si resetta la finestra corrente (secondi dall’epoch)
Retry-AfterInteroSecondi prima di poter riprovare (presente solo nelle risposte 429)

Esempio di header di risposta su una richiesta riuscita:

HTTP/1.1 200 OK X-RateLimit-Limit: 100 X-RateLimit-Remaining: 87 X-RateLimit-Reset: 1737014400 Content-Type: application/json

Esempio di header quando il rate limit è raggiunto:

HTTP/1.1 429 Too Many Requests X-RateLimit-Limit: 100 X-RateLimit-Remaining: 0 X-RateLimit-Reset: 1737014400 Retry-After: 47 Content-Type: application/json { "ok": false, "error": { "code": "RATE_LIMIT_EXCEEDED", "message": "Troppe richieste. Riprova tra 47 secondi." } }

Gestione delle Risposte 429

Quando la tua applicazione riceve una risposta 429 Too Many Requests, dovrebbe fare backoff e riprovare dopo il ritardo specificato nell’header Retry-After.

Retry di Base con Backoff

async function callAurisApi( url: string, options: RequestInit, maxRetries = 3 ): Promise<Response> { for (let attempt = 0; attempt <= maxRetries; attempt++) { const response = await fetch(url, options) if (response.status !== 429) { return response } // Leggi l'header Retry-After const retryAfter = parseInt(response.headers.get('Retry-After') || '60', 10) if (attempt === maxRetries) { throw new Error( `Rate limited dopo ${maxRetries} tentativi. Riprova tra ${retryAfter}s.` ) } console.warn( `Rate limited (tentativo ${attempt + 1}/${maxRetries}). ` + `Riprovo tra ${retryAfter} secondi...` ) await new Promise((resolve) => setTimeout(resolve, retryAfter * 1000)) } throw new Error('Inatteso: loop di retry esaurito') }

Backoff Esponenziale con Jitter

Per sistemi di produzione ad alto traffico, usa il backoff esponenziale con jitter per evitare problemi di “thundering herd” quando molti client raggiungono i limiti contemporaneamente:

async function callWithExponentialBackoff( url: string, options: RequestInit, maxRetries = 5 ): Promise<Response> { for (let attempt = 0; attempt <= maxRetries; attempt++) { const response = await fetch(url, options) if (response.status !== 429) { return response } if (attempt === maxRetries) { throw new Error('Rate limit superato: tentativi massimi raggiunti') } const retryAfter = response.headers.get('Retry-After') let delay: number if (retryAfter) { delay = parseInt(retryAfter, 10) * 1000 } else { // Backoff esponenziale: 1s, 2s, 4s, 8s, 16s const baseDelay = Math.pow(2, attempt) * 1000 const jitter = Math.random() * baseDelay * 0.5 delay = baseDelay + jitter } await new Promise((resolve) => setTimeout(resolve, delay)) } throw new Error('Inatteso: loop di retry esaurito') }

Pattern Circuit Breaker

Per applicazioni che effettuano molte chiamate API, implementa un circuit breaker per smettere del tutto di inviare richieste quando i rate limit vengono colpiti consistentemente:

class AurisCircuitBreaker { private failureCount = 0 private lastFailure = 0 private state: 'closed' | 'open' | 'half-open' = 'closed' private readonly threshold = 5 private readonly resetTimeout = 60000 // 1 minuto async call(fn: () => Promise<Response>): Promise<Response> { if (this.state === 'open') { if (Date.now() - this.lastFailure > this.resetTimeout) { this.state = 'half-open' } else { throw new Error('Circuit breaker aperto. Richieste in pausa.') } } const response = await fn() if (response.status === 429) { this.failureCount++ this.lastFailure = Date.now() if (this.failureCount >= this.threshold) { this.state = 'open' console.error( `Circuit breaker aperto dopo ${this.threshold} rate limit colpiti. ` + `Pausa richieste per ${this.resetTimeout / 1000}s.` ) } throw new Error('Rate limited') } // Successo — resetta il breaker this.failureCount = 0 this.state = 'closed' return response } }

Limiti Per Account sugli Endpoint Auth

In aggiunta ai rate limit basati su IP, gli endpoint di autenticazione applicano limiti per account che funzionano in combinazione con il sistema di protezione brute-force:

SogliaAzione
Login falliti consecutivi nella finestra di osservazioneContatore incrementato
Il contatore raggiunge la soglia di lockout (default: 5)Account bloccato per durata crescente
1° lockout5 minuti
2° lockout30 minuti
3° lockout24 ore

Questi limiti sono per account utente e persistono tra indirizzi IP. Un attacco distribuito da più IP contro lo stesso account attiva comunque il lockout.

Il lockout per account è separato dal rate limiting basato su IP. Un singolo IP può essere rate-limited mentre l’account target rimane sbloccato (se il contatore fallimenti non ha raggiunto la soglia), e viceversa.

Vedi la guida Protezione dagli Attacchi per i dettagli completi sulla configurazione della protezione brute-force.

Comportamento di Retry Automatico dell’SDK

L’SDK @auris/js include gestione integrata dei rate limit per le operazioni sui token:

  • Refresh token: Se una richiesta di refresh token riceve un 429, l’SDK attende la durata Retry-After e riprova una volta automaticamente
  • Redirect di login: Il flusso di login ospitato è server-rendered e non soggetto ai rate limit lato client
  • Chiamate API tramite client Management: Il client Management non riprova automaticamente — la tua applicazione dovrebbe implementare la logica di retry
import { AurisClient } from '@auris/js' const auris = new AurisClient({ domain: 'auth.tuazienda.com', clientId: 'tuo-client-id', autoRefresh: true, // L'SDK gestisce il refresh con retry integrato }) // Il retry del refresh token è automatico const token = await auris.getAccessToken()

Per il client Management (M2M), implementa la tua logica di retry:

import { AurisClient } from '@auris/js' const management = new AurisClient.Management({ domain: 'auth.tuazienda.com', clientId: 'm2m-client-id', clientSecret: 'm2m-client-secret', }) // Le chiamate al client Management dovrebbero usare il tuo wrapper di retry const users = await callWithExponentialBackoff( 'https://auth.tuazienda.com/api/users', { headers: { Authorization: `Bearer ${await management.getToken()}`, 'x-tenant': 'tuo-tenant-id', }, } )

Configurazione nella Console

Le impostazioni di rate limiting sono visualizzabili nella Console Auris sotto Impostazioni poi Rate Limiting. La Console mostra la configurazione corrente per ciascun livello in sola lettura.

Le impostazioni mostrate includono:

  • Limiti per livello — Richieste per finestra per ciascun livello (auth, sensitive, api, public)
  • Durata della finestra — La dimensione della sliding window per ciascun livello
  • Stato corrente — Se il rate limiting è attivo

I valori dei rate limit sono configurati a livello infrastrutturale e sono mostrati nella Console per riferimento. Per richiedere modifiche alle soglie di rate limit per il tuo tenant, contatta il tuo amministratore Auris o modifica la configurazione dell’ambiente.

Monitoraggio Proattivo dei Rate Limit

Invece di aspettare le risposte 429, monitora proattivamente l’header X-RateLimit-Remaining per limitare il tuo tasso di richieste prima di raggiungere i limiti:

class RateLimitAwareClient { private remaining = Infinity private resetAt = 0 async request(url: string, options: RequestInit): Promise<Response> { // Se sappiamo di essere al limite, attendi in modo proattivo if (this.remaining <= 1 && Date.now() / 1000 < this.resetAt) { const waitMs = (this.resetAt - Date.now() / 1000) * 1000 console.log(`Attesa proattiva di ${waitMs}ms per evitare il rate limit`) await new Promise((resolve) => setTimeout(resolve, waitMs)) } const response = await fetch(url, options) // Aggiorna lo stato del rate limit dagli header della risposta const limit = response.headers.get('X-RateLimit-Remaining') const reset = response.headers.get('X-RateLimit-Reset') if (limit !== null) this.remaining = parseInt(limit, 10) if (reset !== null) this.resetAt = parseInt(reset, 10) return response } }

Best Practice

Rispetta sempre Retry-After. Quando ricevi un 429, l’header Retry-After ti dice esattamente quanto tempo aspettare. Non riprovare prima di questo periodo.

Usa il backoff esponenziale con jitter. Per operazioni bulk o scenari ad alto throughput, il retry lineare semplice può causare picchi di traffico quando più client riprovano nello stesso momento. Il jitter distribuisce i retry nel tempo.

Implementa circuit breaker per i percorsi critici. Se la tua applicazione dipende dalle chiamate API Auris nel percorso delle richieste (es. controlli dei permessi), usa un circuit breaker per fallire in modo elegante invece di accodare le richieste mentre è in rate limiting.

Cache le risposte dove possibile. Riduci le chiamate API memorizzando nella cache i profili utente, le liste di ruoli e i controlli dei permessi. L’SDK @auris/react usa TanStack Query internamente con uno staleTime predefinito che riduce le chiamate API ridondanti.

Usa operazioni batch quando disponibili. Usa endpoint bulk (es. operazioni bulk SCIM, scritture bulk tuple FGA) invece di chiamate API individuali per svolgere lo stesso lavoro con meno richieste.

Monitora gli header di rate limit in produzione. Registra il valore X-RateLimit-Remaining e imposta alert quando scende sotto una soglia. Questo ti dà un avviso anticipato prima che gli utenti inizino a vedere errori 429.

Guide Correlate