> ## Documentation Index
> Fetch the complete documentation index at: https://translations.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# API Flask

> Ce guide montre comment intégrer Auth0 à n’importe quelle API Python, nouvelle ou existante, développée avec Flask.

export const HowToSchema = () => <script type="application/ld+json">
    {'{"@context":"https://schema.org","@type":"HowTo"}'}
  </script>;

<HowToSchema />

<Note>
  **Prérequis :** Avant de commencer, assurez-vous d’avoir installé les éléments suivants :

  * **Python 3.9** ou version ultérieure
  * Le gestionnaire de paquets **pip** ou Poetry
  * **[jq](https://jqlang.org/)** - Requis pour configurer l’interface de ligne de commande d’Auth0
  * Votre éditeur de code préféré

  **Compatibilité des versions de Flask :** Ce guide de démarrage rapide nécessite **Flask 3.0** ou une version ultérieure pour la prise en charge native d’async.
</Note>

<div id="get-started">
  ## Pour commencer
</div>

Ce guide explique comment intégrer Auth0 à une API Python, nouvelle ou existante, développée avec [Flask](https://flask.palletsprojects.com/).

<Steps>
  <Step title="Créez un nouveau projet Flask" stepNumber={1}>
    Créez un nouveau répertoire pour votre API Flask :

    ```bash theme={null}
    mkdir flask-auth0-api
    cd flask-auth0-api
    ```

    Créez un environnement virtuel et activez-le :

    ```bash theme={null}
    python -m venv venv
    source venv/bin/activate  # Sur Windows : venv\Scripts\activate
    ```
  </Step>

  <Step title="Installer les dépendances" stepNumber={2}>
    Créez un fichier `requirements.txt` contenant les dépendances suivantes :

    ```txt requirements.txt theme={null}
    flask>=3.0
    auth0-api-python
    python-dotenv
    ```

    Installez les dépendances :

    ```bash theme={null}
    pip install -r requirements.txt
    ```
  </Step>

  <Step title="Configurez votre API Auth0" stepNumber={3}>
    Ensuite, vous devez créer une nouvelle API sur votre locataire Auth0 et configurer votre application.

    Vous pouvez le faire automatiquement en exécutant une commande CLI, ou manuellement dans le Dashboard :

    <Tabs>
      <Tab title="Dashboard">
        1. Accédez à [Auth0 Dashboard](https://manage.auth0.com/) → **Applications** → **APIs**
        2. Cliquez sur **Create API**
        3. Saisissez les détails de votre API :
           * **Nom** : `My Flask API`
           * **Identifiant** : `https://my-flask-api` (ce sera votre audience)
           * **Algorithme de signature** : **RS256**
        4. Cliquez sur **Create**
        5. Copiez votre **Domaine** depuis le Dashboard (sous **Applications** → **Applications** → **\[Your App]** → **Settings**)
        6. Copiez l’**Identifiant** que vous venez de créer (il s’agit de votre audience)

        <Info>
          Votre **Domaine** ne doit pas inclure `https://` — utilisez uniquement le nom de domaine (par exemple, `your-tenant.auth0.com`).

          L’**Audience** (identifiant de l’API) est un identifiant unique pour votre API et peut être n’importe quel URI valide.
        </Info>
      </Tab>

      <Tab title="CLI">
        Exécutez la commande shell suivante à la racine de votre projet pour créer une API Auth0 et générer un fichier `.env` :

        <CodeGroup>
          ```shellscript Mac theme={null}
          AUTH0_API_NAME="My Flask API" && AUTH0_API_IDENTIFIER="https://my-flask-api" && brew tap auth0/auth0-cli && brew install auth0 && auth0 login --no-input && auth0 apis create --name "${AUTH0_API_NAME}" --identifier "${AUTH0_API_IDENTIFIER}" --signing-alg RS256 --json > auth0-api-details.json && DOMAIN=$(auth0 tenants list --json | jq -r '.[] | select(.active == true) | .name') && AUDIENCE=$(jq -r '.identifier' auth0-api-details.json) && echo "AUTH0_DOMAIN=${DOMAIN}" > .env && echo "AUTH0_AUDIENCE=${AUDIENCE}" >> .env && rm auth0-api-details.json && echo ".env file created with your Auth0 API details:" && cat .env
          ```

          ```shellscript Windows theme={null}
          $ApiName = "My Flask API"; $ApiIdentifier = "https://my-flask-api"; winget install Auth0.CLI; auth0 login --no-input; auth0 apis create -n "$ApiName" -i "$ApiIdentifier" --signing-alg RS256 --json | Set-Content -Path auth0-api-details.json; $Domain = (auth0 tenants list --json | ConvertFrom-Json | Where-Object { $_.active -eq $true }).name; $Audience = (Get-Content -Raw auth0-api-details.json | ConvertFrom-Json).identifier; Set-Content -Path .env -Value "AUTH0_DOMAIN=$Domain"; Add-Content -Path .env -Value "AUTH0_AUDIENCE=$Audience"; Remove-Item auth0-api-details.json; Write-Output ".env file created with your Auth0 API details:"; Get-Content .env
          ```
        </CodeGroup>
      </Tab>
    </Tabs>
  </Step>

  <Step title="Définir les autorisations de l’API" stepNumber={4}>
    Configurez les autorisations (scopes) de votre API pour contrôler l’accès à des ressources précises :

    1. Dans le [Auth0 Dashboard](https://manage.auth0.com/), accédez à **Applications** → **APIs**
    2. Sélectionnez votre API (`My Flask API`)
    3. Ouvrez l’onglet **Permissions**
    4. Cliquez sur **Add Permission**
    5. Ajoutez l’autorisation suivante :
       * **Permission (Scope)** : `read:messages`
       * **Description** : `Read messages`
    6. Cliquez sur **Add**

    <Info>
      Les autorisations définissent les actions qui peuvent être effectuées sur votre API. Vous pouvez ajouter plusieurs autorisations, comme `write:messages`, `delete:messages`, etc. Le point de terminaison `/api/private-scoped` de ce guide de démarrage rapide nécessite l’autorisation `read:messages`.
    </Info>
  </Step>

  <Step title="Configurer l’application Auth0" stepNumber={5}>
    <Note>
      Si vous avez utilisé la méthode **CLI** à l’étape 3, votre fichier `.env` a été créé automatiquement. Passez directement à la création du fichier `app.py` ci-dessous.
    </Note>

    Si vous avez utilisé la méthode **Dashboard**, créez un fichier `.env` à la racine de votre projet pour y stocker votre configuration Auth0 :

    ```bash .env theme={null}
    AUTH0_DOMAIN=your-tenant.us.auth0.com
    AUTH0_AUDIENCE=https://my-flask-api
    ```

    <Warning>
      Remplacez `your-tenant.us.auth0.com` par votre domaine Auth0 et mettez à jour `API_IDENTIFIER` pour qu’il corresponde à l’identifiant de votre API dans le tableau de bord.
    </Warning>

    Créez un fichier `app.py` et configurez le client API Auth0 :

    ```python app.py theme={null}
    import os
    import asyncio
    from flask import Flask, request, jsonify, g
    from functools import wraps
    from dotenv import load_dotenv
    from auth0_api_python import ApiClient, ApiClientOptions
    from auth0_api_python.errors import BaseAuthError

    # Charger les variables d'environnement
    load_dotenv()

    app = Flask(__name__)

    # Initialiser le client API Auth0 (singleton - créé une seule fois)
    api_client = ApiClient(ApiClientOptions(
        domain=os.getenv("AUTH0_DOMAIN"),
        audience=os.getenv("AUTH0_AUDIENCE")
    ))
    ```
  </Step>

  <Step title="Créer des routes protégées" stepNumber={5}>
    Ajoutez un décorateur pour protéger les routes et créez des points de terminaison publics et privés :

    ```python app.py theme={null}
    # Décorateur d'authentification
    def require_auth(f):
        @wraps(f)
        def decorated_function(*args, **kwargs):
            auth_header = request.headers.get("Authorization", "")
            
            if not auth_header.startswith("Bearer "):
                return jsonify({"error": "Missing or invalid authorization header"}), 401
            
            token = auth_header.split(" ")[1]
            
            try:
                claims = asyncio.run(api_client.verify_access_token(token))
                g.user_claims = claims
                return f(*args, **kwargs)
            except BaseAuthError as e:
                return (
                    jsonify({"error": str(e)}),
                    e.get_status_code(),
                    e.get_headers()
                )
        
        return decorated_function


    # Point de terminaison public - aucune authentification requise
    @app.route("/api/public", methods=["GET"])
    def public():
        return jsonify({"message": "This endpoint is public"})


    # Point de terminaison protégé - authentification requise
    @app.route("/api/private", methods=["GET"])
    @require_auth
    def private():
        return jsonify({
            "message": "This endpoint requires authentication",
            "user": g.user_claims.get("sub")
        })


    # Point de terminaison protégé avec validation des permissions
    @app.route("/api/private-scoped", methods=["GET"])
    @require_auth
    def private_scoped():
        scopes = g.user_claims.get("scope", "").split()
        
        if "read:messages" not in scopes:
            return jsonify({"error": "Insufficient permissions"}), 403
        
        return jsonify({
            "message": "Private scoped endpoint - read:messages permission granted",
            "user": g.user_claims.get("sub")
        })


    if __name__ == "__main__":
        app.run(debug=True, port=5000)
    ```
  </Step>

  <Step title="Lancez votre API" stepNumber={6}>
    Démarrez votre application Flask :

    ```bash theme={null}
    python app.py
    ```

    Votre API est maintenant en cours d’exécution sur `http://localhost:5000`.
  </Step>
</Steps>

<Check>
  **Point de contrôle**

  Vous devriez maintenant avoir une API Flask protégée par Auth0, entièrement fonctionnelle, s’exécutant sur votre localhost, avec trois points de terminaison :

  * `/api/public` - Accessible sans authentification
  * `/api/private` - Nécessite un jeton d’accès Auth0 valide
  * `/api/private-scoped` - Nécessite une authentification et la permission `read:messages`
</Check>

<div id="test-your-api">
  ## Testez votre API
</div>

Pour tester vos points de terminaison protégés, vous avez besoin d’un jeton d’accès.

<div id="get-a-test-token">
  ### Obtenir un jeton de test
</div>

1. Accédez à l’[Auth0 Dashboard](https://manage.auth0.com/)
2. Accédez à **Applications → APIs**
3. Sélectionnez votre API
4. Ouvrez l’onglet **Test**
5. Copiez le jeton d’accès

<div id="make-a-request">
  ### Effectuer une requête
</div>

Testez le point de terminaison public (aucun token requis) :

```bash theme={null}
curl http://localhost:5000/api/public
```

Testez le point de terminaison protégé (jeton requis) :

```bash theme={null}
curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  http://localhost:5000/api/private
```

Remplacez `YOUR_ACCESS_TOKEN` par le jeton que vous avez copié dans l’Auth0 Dashboard.

<div id="advanced-usage">
  ## Utilisation avancée
</div>

<Accordion title="Validation des revendications personnalisées">
  Exigez que certaines revendications soient présentes dans le jeton d’accès :

  ```python theme={null}
  try:
      claims = await api_client.verify_access_token(
          access_token=token,
          required_claims=["email_verified", "org_id"]
      )
  except BaseAuthError as e:
      return jsonify({"error": "Revendications requises manquantes"}), 401
  ```
</Accordion>

<Accordion title="Authentification DPoP">
  Pour renforcer la sécurité, activez DPoP (Demonstrating Proof-of-Possession). DPoP améliore OAuth 2.0 en associant les jetons d’accès à des clés cryptographiques.

  ```python theme={null}
  import asyncio


  # Configurer le client API avec DPoP activé (mode Allowed)
  api_client = ApiClient(ApiClientOptions(
      domain=os.getenv("AUTH0_DOMAIN"),
      audience=os.getenv("AUTH0_AUDIENCE"),
      dpop_enabled=True,   # Par défaut - active la prise en charge de DPoP
      dpop_required=False  # Par défaut - autorise les jetons Bearer et DPoP
  ))

  # Pour le mode Required (DPoP seulement, rejette les jetons Bearer)
  # dpop_required=True

  # Décorateur compatible avec DPoP
  def require_auth_dpop(f):
      @wraps(f)
      def decorated_function(*args, **kwargs):
          headers = {
              "authorization": request.headers.get("Authorization", ""),
              "dpop": request.headers.get("DPoP", "")  # En-tête de preuve DPoP
          }
          
          try:
              # verify_request() détecte automatiquement le schéma Bearer ou DPoP
              claims = asyncio.run(api_client.verify_request(
                  headers=headers,
                  http_method=request.method,
                  http_url=request.url
              ))
              g.user_claims = claims
              return f(*args, **kwargs)
          except BaseAuthError as e:
              return jsonify({"error": str(e)}), e.get_status_code(), e.get_headers()
      
      return decorated_function

  @app.route("/api/dpop-protected")
  @require_auth_dpop
  def dpop_protected():
      return jsonify({
          "message": "Authentification avec DPoP ou Bearer réussie",
          "user": g.user_claims.get("sub")
      })
  ```

  <Info>
    La méthode `verify_request()` détecte automatiquement si la requête utilise l’authentification Bearer ou DPoP. Lorsque DPoP est utilisé, elle valide à la fois le jeton d’accès et la preuve DPoP conformément à la RFC 9449.
  </Info>
</Accordion>

<Accordion title="Autorisation basée sur les scopes">
  Créez un décorateur pour vérifier des scopes précis :

  ```python theme={null}
  def require_scope(required_scope):
      def decorator(f):
          @wraps(f)
          async def wrapper(*args, **kwargs):
              if not hasattr(g, "user_claims"):
                  return jsonify({"error": "Non autorisé"}), 401
              
              scopes = g.user_claims.get("scope", "").split()
              
              if required_scope not in scopes:
                  return jsonify({"error": "Permissions insuffisantes"}), 403
              
              return await f(*args, **kwargs)
          return wrapper
      return decorator


  @app.route("/api/admin")
  @require_auth
  @require_scope("admin:write")
  async def admin_endpoint():
      return jsonify({"message": "Accès administrateur accordé"})
  ```
</Accordion>

<Accordion title="Pratiques exemplaires de gestion des erreurs">
  Implémentez une gestion robuste des erreurs avec des types d’erreur précis :

  ```python theme={null}
  from auth0_api_python.errors import (
      BaseAuthError,
      VerifyAccessTokenError,
      GetTokenByExchangeProfileError,
      ApiError
  )

  @app.errorhandler(BaseAuthError)
  def handle_auth_error(error):
      """Gérer toutes les erreurs d’authentification Auth0"""
      return jsonify({
          "error": error.get_error_code(),
          "error_description": str(error)
      }), error.get_status_code(), error.get_headers()


  @app.errorhandler(VerifyAccessTokenError)
  def handle_token_verification_error(error):
      """Gérer spécifiquement les échecs de validation du jeton"""
      app.logger.warning(f"Token verification failed: {str(error)}")
      return jsonify({
          "error": "invalid_token",
          "error_description": str(error)
      }), 401, error.get_headers()


  @app.errorhandler(ApiError)
  def handle_api_error(error):
      """Gérer les erreurs d’API Auth0 (réseau, limites de débit, etc.)"""
      app.logger.error(f"Auth0 API error: {error.code} - {error.message}")
      return jsonify({
          "error": error.code,
          "error_description": error.message
      }), error.status_code or 500


  @app.errorhandler(Exception)
  def handle_generic_error(error):
      """Intercepter toute erreur inattendue"""
      app.logger.error(f"Unexpected error: {str(error)}", exc_info=True)
      return jsonify({"error": "Internal server error"}), 500
  ```

  <Info>
    Toutes les erreurs d’authentification héritent de `BaseAuthError`, qui fournit des méthodes comme `get_status_code()`, `get_headers()` et `get_error_code()` pour renvoyer des réponses HTTP appropriées avec des en-têtes WWW-Authenticate.
  </Info>
</Accordion>

<Accordion title="Utilisation du middleware before_request">
  Pour les applications où la plupart des points de terminaison exigent une authentification, utilisez `before_request` de Flask pour valider les jetons de façon globale :

  ```python theme={null}
  from flask import g

  PUBLIC_ROUTES = ["/api/public", "/health"]

  @app.before_request
  async def verify_token():
      # Ignorer l’authentification pour les routes publiques
      if request.path in PUBLIC_ROUTES:
          return
      
      auth_header = request.headers.get("Authorization", "")
      
      if not auth_header.startswith("Bearer "):
          return jsonify({"error": "Missing authorization"}), 401
      
      token = auth_header.split(" ")[1]
      
      try:
          claims = await api_client.verify_access_token(token)
          g.user_claims = claims
      except BaseAuthError as e:
          return jsonify({"error": str(e)}), e.get_status_code(), e.get_headers()


  @app.route("/api/protected-data")
  async def protected_data():
      # Claims automatiquement accessibles via g.user_claims
      return jsonify({"user_id": g.user_claims["sub"]})
  ```
</Accordion>

<div id="common-issues">
  ## Problèmes courants
</div>

<AccordionGroup>
  <Accordion title="401 Non autorisé - Audience invalide">
    **Symptôme** : Vous obtenez des erreurs 401 même avec des jetons qui semblent valides

    **Cause** : L’audience de votre jeton ne correspond pas à celle configurée dans votre client API

    **Solution** :

    1. Vérifiez que `AUTH0_AUDIENCE` dans votre fichier `.env` correspond exactement à l’identifiant de l’API Auth0
    2. L’audience est sensible à la casse
    3. Assurez-vous que l’audience est au format URL ou URN (par ex. : `https://my-api` et non `my-api`)
  </Accordion>

  <Accordion title="401 Non autorisé - Émetteur invalide">
    **Symptôme** : La validation du jeton échoue en raison d’une non-correspondance de l’émetteur

    **Cause** : La configuration du Domaine ne correspond pas à l’émetteur du jeton

    **Solution** :

    1. Vérifiez que `AUTH0_DOMAIN` est correct (par ex. : `tenant.us.auth0.com`)
    2. N’incluez pas `https://` dans le domaine
    3. N’ajoutez pas de barre oblique à la fin
  </Accordion>

  <Accordion title="Valeurs de configuration introuvables">
    **Symptôme** : Valeurs `None` ou erreurs liées aux variables d’environnement

    **Cause** : Les variables d’environnement ne sont pas chargées ou le fichier `.env` est introuvable

    **Solution** :

    1. Assurez-vous que le fichier `.env` existe à la racine de votre projet
    2. Vérifiez que `load_dotenv()` est appelé avant d’accéder à `os.getenv()`
    3. Vérifiez que les noms des variables correspondent exactement (respect de la casse)
  </Accordion>

  <Accordion title="Erreurs de prise en charge async dans Flask">
    **Symptôme** : `RuntimeError: This event loop is already running` ou erreurs async semblables

    **Cause** : Utilisation de routes async sans Flask 3.0+ ou mélange inadéquat de sync et d’async

    **Solution** :

    1. Passez à Flask 3.0 ou version ultérieure : `pip install --upgrade flask`
    2. Assurez-vous que tous les gestionnaires de routes qui utilisent `api_client` sont déclarés avec `async def`
    3. N’utilisez pas `asyncio.run()` dans les gestionnaires de routes
  </Accordion>

  <Accordion title="Erreurs de jeton expiré">
    **Symptôme** : `VerifyAccessTokenError: Token is expired`

    **Cause** : Le jeton d’accès a dépassé sa date d’expiration

    **Solution** :

    1. Demandez un nouveau jeton à partir de l’onglet Test dans Auth0 Dashboard
    2. Implémentez le renouvellement du jeton dans votre application cliente
    3. Les jetons du Dashboard sont généralement valides pendant 24 heures
  </Accordion>

  <Accordion title="En-tête Authorization manquant">
    **Symptôme** : Erreur `Missing or invalid authorization header`

    **Cause** : La requête n’inclut pas l’en-tête `Authorization` ou utilise un format incorrect

    **Solution** :

    1. Assurez-vous que l’en-tête s’appelle `Authorization` (A majuscule)
    2. Utilisez le format suivant : `Authorization: Bearer YOUR_TOKEN`
    3. N’ajoutez pas de guillemets autour du jeton
  </Accordion>
</AccordionGroup>

<div id="additional-resources">
  ## Ressources supplémentaires
</div>

<CardGroup cols={3}>
  <Card title="Documentation du SDK" icon="github" href="https://github.com/auth0/auth0-api-python">
    Documentation complète du SDK et référence de l’API
  </Card>

  <Card title="Documentation de Flask" icon="code" href="https://flask.palletsprojects.com/">
    Documentation officielle du framework Flask
  </Card>

  <Card title="Auth0 Dashboard" icon="gauge" href="https://manage.auth0.com/">
    Gérez votre locataire Auth0 et vos API
  </Card>

  <Card title="Guide d’authentification des API" icon="shield" href="https://auth0.com/docs/secure/tokens/access-tokens">
    En savoir plus sur les jetons d’accès et la sécurité des API
  </Card>

  <Card title="Documentation sur DPoP" icon="lock" href="https://auth0.com/docs/secure/sender-constraining/demonstrating-proof-of-possession-dpop">
    En savoir plus sur la sécurité par preuve de possession
  </Card>

  <Card title="Forum communautaire" icon="comments" href="https://community.auth0.com/">
    Obtenez de l’aide auprès de la communauté Auth0
  </Card>
</CardGroup>

<div id="next-steps">
  ## Prochaines étapes
</div>

Consultez le [dépôt d’exemples de l’API Python d’Auth0](https://github.com/auth0-samples/auth0-python-api-samples) pour voir des exemples complets et fonctionnels avec Flask.
