Quotas et Rate Limiting Auth0 : éviter les 429 en production

Auth0 impose des quotas stricts sur les APIs et les logins. Comment les anticiper, les monitorer et les gérer en production sans erreurs 429.

Par Auth0.Expert · 2025-02-12 · 10 min de lecture

Rate Limiting Quotas Production

Quotas et Rate Limiting Auth0

TL;DR

Auth0 impose des limites strictes sur le nombre de requêtes par seconde, par utilisateur et par tenant. Ce guide présente tous les quotas importants et les stratégies pour ne jamais dépasser les limites.

---

Quotas Authentication API

Ce tableau récapitule les limitations d'usage pour chaque endpoint critique de l'API d'authentification Auth0.

| Endpoint | Limite | Fenêtre | |----------|--------|---------| | POST /oauth/token | 30/s par IP | Seconde | | GET /authorize | 300/s par tenant | Seconde | | POST /passwordless/start | 10/s par IP | Seconde | | POST /dbconnections/signup | 20/s par IP | Seconde | | POST /dbconnections/change_password | 5/m par IP | Minute | | GET /userinfo | 50/s par token | Seconde |

---

Quotas Management API v2

Voici les quotas d’appels pour chaque endpoint principal de la Management API v2 d’Auth0.

| Endpoint | Limite | Fenêtre | |----------|--------|---------| | GET /api/v2/users | 20/s | Seconde | | POST /api/v2/users | 10/s | Seconde | | PATCH /api/v2/users/{id} | 20/s | Seconde | | GET /api/v2/logs | 5/s | Seconde | | GET /api/v2/clients | 5/s | Seconde |

---

Gestion des 429 : stratégie de retry avec backoff

Le code ci-dessous montre comment gérer automatiquement les erreurs HTTP 429 (“Too Many Requests”) en mettant en œuvre un système de retry avec temporisation progressive (exponential backoff). Cela permet d’éviter de bloquer votre intégration en cas de dépassement de quota ponctuel.

import asyncio
import httpx
import time
from typing import Optional

class Auth0ApiClient:
    def __init__(self, domain: str, token: str):
        self.base_url = f"https://{domain}/api/v2"
        self.headers = {"Authorization": f"Bearer {token}"}
        self.client = httpx.AsyncClient(timeout=30)

    async def request_with_retry(
        self,
        method: str,
        path: str,
        max_retries: int = 3,
        **kwargs
    ) -> httpx.Response:
        for attempt in range(max_retries):
            resp = await self.client.request(
                method,
                f"{self.base_url}{path}",
                headers=self.headers,
                **kwargs
            )

            if resp.status_code != 429:
                return resp

            # Lire le header de rate limit reset
            rate_limit_reset = resp.headers.get("x-ratelimit-reset")
            if rate_limit_reset:
                wait_until = float(rate_limit_reset)
                wait_seconds = max(wait_until - time.time() + 0.1, 0.1)
            else:
                wait_seconds = 2 ** attempt  # Exponential backoff

            if attempt < max_retries - 1:
                print(f"Rate limited. Waiting {wait_seconds:.1f}s before retry {attempt + 1}")
                await asyncio.sleep(wait_seconds)

        raise Exception(f"Rate limit dépassé après {max_retries} tentatives")

Ce bloc gère automatiquement les limitations de taux en réessayant les appels selon la politique conseillée par Auth0.

---

Batch processing : importer en masse sans 429

Pour importer un grand volume d’utilisateurs dans Auth0 sans déclencher les quotas, ce code organise l'import en lots et utilise l’API Jobs recommandée, garantissant un débit contrôlé et la supervision de chaque opération.

# Stratégie pour importer 50 000 utilisateurs sans dépasser les quotas

import asyncio
from typing import List

async def batch_import_users(users: List[dict], mgmt_token: str, domain: str):
    """Import par lots avec contrôle du débit."""
    client = Auth0ApiClient(domain, mgmt_token)

    # Auth0 recommande l'API Jobs pour les imports massifs
    # Max 5000 utilisateurs par job
    BATCH_SIZE = 5000
    DELAY_BETWEEN_BATCHES = 2  # secondes

    for i in range(0, len(users), BATCH_SIZE):
        batch = users[i:i + BATCH_SIZE]
        print(f"Importing batch {i//BATCH_SIZE + 1}: {len(batch)} users")

        # Créer un job d'import
        job_response = await client.request_with_retry(
            "POST",
            "/jobs/users-imports",
            content=create_multipart_body(batch, connection_id="..."),
        )
        job_id = job_response.json()["id"]

        # Attendre la fin du job
        await wait_for_job(client, job_id)

        if i + BATCH_SIZE < len(users):
            await asyncio.sleep(DELAY_BETWEEN_BATCHES)

async def wait_for_job(client, job_id: str, timeout: int = 300):
    """Attend la complétion d'un job Auth0."""
    start = time.time()
    while time.time() - start < timeout:
        resp = await client.request_with_retry("GET", f"/jobs/{job_id}")
        job = resp.json()

        if job["status"] == "completed":
            return job
        elif job["status"] == "failed":
            raise Exception(f"Job {job_id} failed: {job.get('summary')}")

        await asyncio.sleep(5)
    raise TimeoutError(f"Job {job_id} non terminé après {timeout}s")

Ce script divise vos imports d’utilisateurs en lots raisonnables pour éviter toute erreur de quota ou surcharge.

---

Quotas par plan Auth0

Ce tableau détaille les quotas en fonction du plan Auth0 choisi, afin de bien dimensionner votre solution selon vos besoins métiers.

| Quota | Free | Developer | Enterprise | |-------|------|-----------|------------| | MAU | 7 500 | 10 000 | Négocié | | M2M tokens/mois | 1 000 | 1 000 | Négocié | | Logs rétention | 3j | 7j | 30j | | Actions | 5 | 5 | Illimité | | Connexions actives | 2 | 2 | Illimité | | Emails/jour | 500 | 500 | Négocié |

---

Monitorer vos quotas

La surveillance proactive de vos quotas est essentielle pour anticiper tout risque de blocage ou dépassement.

# Vérifier vos quotas via l'API
curl "https://YOUR_DOMAIN.auth0.com/api/v2/quotas"   -H "Authorization: Bearer $MGMT_TOKEN"

# Headers de rate limit sur chaque réponse
X-RateLimit-Limit: 20
X-RateLimit-Remaining: 15
X-RateLimit-Reset: 1735700000  # Unix timestamp
# Parser les headers de rate limit
def parse_rate_limit_headers(headers: dict) -> dict:
    return {
        "limit": int(headers.get("x-ratelimit-limit", 0)),
        "remaining": int(headers.get("x-ratelimit-remaining", 0)),
        "reset": int(headers.get("x-ratelimit-reset", 0)),
        "reset_in": max(0, int(headers.get("x-ratelimit-reset", 0)) - int(time.time())),
    }

Ce parsing des headers vous aide à piloter votre consommation d’API Auth0 en temps réel.

---

File de travaux (Queue) pour les actions différées

Pour les traitements lourds liés à une Action Auth0, utilisez une file asynchrone et évitez d’appeler directement la Management API dans votre logique métier. Ce schéma réduit le risque de blocage lié aux quotas et améliore la scalabilité.

// Ne jamais appeler la Management API directement depuis une Action
// → utiliser une file de travaux asynchrone

exports.onExecutePostUserRegistration = async (event, api) => {
  // Envoyer un message dans une file (SQS, Redis, etc.)
  // Le traitement se fait asynchronement, hors du flux Auth0
  await fetch(`${event.secrets.QUEUE_ENDPOINT}/enqueue`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-Queue-Token': event.secrets.QUEUE_TOKEN,
    },
    body: JSON.stringify({
      type: 'user_registered',
      user_id: event.user.user_id,
      email: event.user.email,
      timestamp: new Date().toISOString(),
    }),
  });
  // Auth0 n'est pas bloqué — le traitement lourd se fait en arrière-plan
};

---

> ⚡ Optimisation quotas Auth0 : nos experts analysent votre utilisation des APIs Auth0 et optimisent votre architecture pour éviter tout dépassement de quota.

📞 +33 1 23 45 67 89 · 📧 [email protected]


Autres articles