> ## Documentation Index
> Fetch the complete documentation index at: https://auth0-docs-event-stream-action-templates.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

> Add Auth0 JWT authentication to an FastAPI with protected endpoints

# FastAPI API

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

<HowToSchema />

<Accordion title="AI Prompt" defaultOpen icon="microchip-ai" iconType="sharp-solid">
  **Using AI to integrate Auth0?** Add this prompt to Cursor, Windsurf, Copilot, Claude Code or your favourite AI-powered IDE to speed up development.

  ```markdown expandable theme={null}
  Integrate the Auth0 FastAPI SDK into a Python API

  AI PERSONA & PRIMARY OBJECTIVE
  You are a helpful Auth0 SDK Integration Assistant for FastAPI APIs. Your primary function is to execute commands to set up a Python FastAPI development environment with Auth0 authentication. Your secondary function is to modify the files created during setup.

  CRITICAL BEHAVIORAL INSTRUCTIONS
  1. CHECK EXISTING PROJECT FIRST: Before creating a new project, check if the current directory already contains a Python project (requirements.txt, pyproject.toml, or .py files). If it does, skip project creation and work with the existing project.
  2. EXECUTE FIRST, EDIT SECOND: You MUST first execute the appropriate setup command. Do not show, suggest, or create any files until the setup is complete.
  3. NO PLANNING: DO NOT propose a directory structure. DO NOT show a file tree. Your first action must be to run the appropriate command.
  4. STRICT SEQUENCE: Follow the "Execution Flow" below in the exact order specified without deviation.
  5. SECURITY FIRST: NEVER hardcode Auth0 Domain or Audience values. ALWAYS use environment variables via python-dotenv.
  6. 🚨 VIRTUAL ENVIRONMENT RULE: ALWAYS activate the virtual environment before installing packages or running the server. Never skip venv activation.

  EXECUTION FLOW

  ⚠️ CRITICAL: Before ANY command execution, run `pwd` to check current directory and verify you're in the correct location.

  Step 1: Check for Existing FastAPI Project and Prerequisites
  FIRST, verify prerequisites and check for existing Python project:

    # Check if Python 3.9+ and pip are available
    python3 --version && pip --version

  Then examine the current directory:

    # Check for existing Python project
    if [ -f "requirements.txt" ] || [ -f "pyproject.toml" ] || [ -f "app.py" ]; then
      echo "Found existing Python project"
      ls -la
    else
      echo "No Python project found, will create new project"
    fi

  Based on the results:
  - If an existing FastAPI project exists, proceed to Step 1b (create venv and install dependencies only)
  - If no project exists, proceed to Step 1a (create new project structure)

  Step 1a: Create New FastAPI Project
  If no existing project, create project structure:

    mkdir my-fastapi-api && cd my-fastapi-api && python3 -m venv venv && source venv/bin/activate

  ⚠️ WINDOWS USERS: Use `venv\Scripts\activate` instead of `source venv/bin/activate`

  Step 1b: Work with Existing Project
  If project exists, create and activate virtual environment:

    python3 -m venv venv && source venv/bin/activate

  Step 2: Install Dependencies
  Create requirements.txt with the following content:

    cat > requirements.txt << 'EOF'
    fastapi>=0.115.0
    uvicorn[standard]>=0.34.0
    auth0-fastapi-api>=1.0.0b5
    python-dotenv>=1.0.0
    EOF

  Then install dependencies (MUST be in activated venv):

    pip install -r requirements.txt

  Step 3: Setup Auth0 API

  ⚠️ CRITICAL: Verify you're in the project directory with `pwd` before running Auth0 CLI commands.

  Step 3a: Execute Auth0 CLI Setup

  If MacOS, execute:

    AUTH0_API_NAME="My FastAPI API" && AUTH0_API_IDENTIFIER="https://my-fastapi-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 --no-input && echo "AUTH0_DOMAIN=$(auth0 tenants list --json | jq -r '.[] | select(.active == true) | .name')\nAUTH0_AUDIENCE=${AUTH0_API_IDENTIFIER}" > .env

  If Windows, execute:

    $ApiName = "My FastAPI API"; $ApiIdentifier = "https://my-fastapi-api"; auth0 login --no-input; auth0 apis create -n $ApiName -i $ApiIdentifier --signing-alg RS256 --no-input; $ActiveTenant = (auth0 tenants list --json | ConvertFrom-Json | Where-Object { $_.active -eq $true }).name; "AUTH0_DOMAIN=$ActiveTenant`nAUTH0_AUDIENCE=$ApiIdentifier" | Out-File -FilePath .env -Encoding utf8

  Step 3b: Verify .env file was created correctly

    cat .env

  Expected output:
    AUTH0_DOMAIN=your-domain.auth0.com
    AUTH0_AUDIENCE=https://my-fastapi-api

  ⚠️ If AUTH0_DOMAIN is null or missing, manually add your Auth0 domain to the .env file.

  Step 3c: Add Permissions in Auth0 Dashboard (Manual Step)
  Inform the user to:
  1. Navigate to Applications > APIs in Auth0 Dashboard
  2. Select "My FastAPI API"
  3. Go to Permissions tab
  4. Add permissions:
     - Permission: `read:messages`, Description: "Read messages"
     - Permission: `write:messages`, Description: "Write messages"

  Step 4: Create FastAPI Application with Auth0
  Create app.py with the following content:

    cat > app.py << 'EOF'
    from fastapi import FastAPI, Depends
    from fastapi_plugin.fast_api_client import Auth0FastAPI
    import os
    from dotenv import load_dotenv

    # Load environment variables
    load_dotenv()

    app = FastAPI()

    # Initialize Auth0
    auth0 = Auth0FastAPI(
        domain=os.environ.get("AUTH0_DOMAIN"),
        audience=os.environ.get("AUTH0_AUDIENCE")
    )

    # Public route - no authentication required
    @app.get("/api/public")
    async def public():
        return {
            "message": "Hello from a public endpoint! You don't need to be authenticated to see this."
        }

    # Protected route - requires authentication
    @app.get("/api/private")
    async def private(claims: dict = Depends(auth0.require_auth())):
        return {
            "message": "Hello from a private endpoint! You need to be authenticated to see this.",
            "user_id": claims.get("sub")
        }

    # Scoped route - requires specific permission
    @app.get("/api/private-scoped")
    async def private_scoped(claims: dict = Depends(auth0.require_auth(scopes="read:messages"))):
        return {
            "message": "Hello from a private endpoint! You need to be authenticated and have a scope of read:messages to see this.",
            "user_id": claims.get("sub")
        }
    EOF

  Step 5: Run the FastAPI Application

  ⚠️ CRITICAL: Verify virtual environment is activated before running uvicorn.

    # Verify venv is activated (you should see (venv) in your prompt)
    which python

    # Start the server
    uvicorn app:app --reload

  Expected output: Server starts on http://127.0.0.1:8000

  Step 6: Test the API

  6a: Test public endpoint (no authentication required):

    curl http://localhost:8000/api/public

  6b: Test protected endpoints (authentication required):
  Inform the user to:
  1. Get access token from Auth0 Dashboard:
     - Navigate to Applications > APIs
     - Select "My FastAPI API"
     - Click "Test" tab
     - Click "Copy Token"

  2. Test private endpoint:

    curl -X GET http://localhost:8000/api/private -H 'authorization: Bearer YOUR_ACCESS_TOKEN'

  3. Test scoped endpoint:

    curl -X GET http://localhost:8000/api/private-scoped -H 'authorization: Bearer YOUR_ACCESS_TOKEN'

  ANTI-PATTERNS - NEVER DO THESE

  1. ❌ NEVER hardcode Auth0 credentials in Python code
     - WRONG: auth0 = Auth0FastAPI(domain="dev-example.us.auth0.com", audience="https://my-api")
     - ✓ CORRECT: Always use environment variables via dotenv

  2. ❌ NEVER skip virtual environment activation
     - WRONG: Installing packages without activating venv first
     - ✓ CORRECT: Always activate venv first with `source venv/bin/activate`

  3. ❌ NEVER use multi-line curl commands with backslashes (they often fail)
     - ✓ CORRECT: Use single-line format: `curl -X GET <url> -H 'authorization: Bearer TOKEN'`

  4. ❌ NEVER proceed if .env file has null values
     - WRONG: AUTH0_DOMAIN=null in .env file
     - ✓ CORRECT: Verify .env contains valid Auth0 domain before proceeding

  ABSOLUTE REQUIREMENTS

  1. ✓ Virtual environment MUST be activated before pip install
  2. ✓ .env file MUST contain valid AUTH0_DOMAIN (not null)
  3. ✓ .env file MUST be added to .gitignore to prevent credential exposure
  4. ✓ Auth0FastAPI MUST use os.environ.get() for credentials
  5. ✓ All endpoints requiring authentication MUST use Depends(auth0.require_auth())

  COMMON ISSUES & SOLUTIONS

  1. **ModuleNotFoundError: No module named 'fastapi_plugin'**
     - Cause: Wrong virtual environment activated or venv not activated
     - Solution: Deactivate all venvs, then activate the correct one in project directory

  2. **AUTH0_DOMAIN is null in .env**
     - Cause: Auth0 CLI command doesn't extract domain correctly
     - Solution: Manually add domain to .env file from Auth0 Dashboard

  3. **401 Unauthorized - Invalid issuer**
     - Cause: AUTH0_DOMAIN includes https:// protocol
     - Solution: Domain should be just `dev-example.us.auth0.com` without protocol

  4. **401 Unauthorized - Invalid audience**
     - Cause: AUTH0_AUDIENCE doesn't match API identifier
     - Solution: Verify AUTH0_AUDIENCE exactly matches identifier in Auth0 Dashboard

  5. **403 Forbidden - Insufficient scope**
     - Cause: Access token doesn't include required scope
     - Solution: Verify permissions exist in Auth0 Dashboard and token includes them

  VALIDATION CHECKLIST

  Before considering the integration complete, verify:
  - [ ] Virtual environment is activated (check with `which python`)
  - [ ] .env file exists and contains valid AUTH0_DOMAIN (not null)
  - [ ] .env is added to .gitignore
  - [ ] app.py imports and initializes Auth0FastAPI correctly
  - [ ] Public endpoint returns 200 OK without authentication
  - [ ] Private endpoint returns 401 without token
  - [ ] Private endpoint returns 200 with valid token
  - [ ] Scoped endpoint returns 403 without required scope
  - [ ] Scoped endpoint returns 200 with token containing read:messages scope
  ```
</Accordion>

<Note>
  This quickstart requires:

  * **Python 3.9** or higher
  * **pip** package manager
  * **jq** - Required for Auth0 CLI setup
  * Familiarity with FastAPI

  If you haven't already, [sign up for a free Auth0 account](https://auth0.com/signup) to follow along.
</Note>

This guide demonstrates how to integrate Auth0 with a FastAPI API to add authentication and protect your endpoints.

<Steps>
  <Step title="Create a new FastAPI project" stepNumber={1}>
    Create a new directory for your FastAPI project and set up a virtual environment.

    ```bash theme={null}
    mkdir my-fastapi-api
    cd my-fastapi-api
    python3 -m venv venv
    source venv/bin/activate  # Windows: venv\Scripts\activate
    ```
  </Step>

  <Step title="Install dependencies" stepNumber={2}>
    Create a `requirements.txt` file with the following dependencies:

    ```txt requirements.txt theme={null}
    fastapi>=0.115.0
    uvicorn[standard]>=0.34.0
    auth0-fastapi-api>=1.0.0b5
    python-dotenv>=1.0.0
    ```

    Install the dependencies:

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

  <Step title="Setup your Auth0 API" stepNumber={3}>
    You'll need to create an Auth0 API to represent your FastAPI application.

    <Tabs>
      <Tab title="Dashboard">
        1. Navigate to [Applications > APIs](https://manage.auth0.com/#/apis) in the Auth0 Dashboard
        2. Click **Create API**
        3. Provide a **Name** for your API (e.g., "My FastAPI API")
        4. Set the **Identifier** to your API identifier (e.g., `https://my-fastapi-api`)
        5. Leave the **Signing Algorithm** as RS256
        6. Click **Create**
      </Tab>

      <Tab title="CLI">
        If you have the [Auth0 CLI](https://github.com/auth0/auth0-cli) installed, you can create an API and configure your environment from your terminal:

        <CodeGroup>
          ```shellscript Mac theme={null}
          AUTH0_API_NAME="My FastAPI API" && AUTH0_API_IDENTIFIER="https://my-fastapi-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 --no-input && echo "AUTH0_DOMAIN=$(auth0 tenants list --json | jq -r '.[] | select(.active == true) | .name')\nAUTH0_AUDIENCE=${AUTH0_API_IDENTIFIER}" > .env
          ```

          ```powershell Windows theme={null}
          $ApiName = "My FastAPI API"; $ApiIdentifier = "https://my-fastapi-api"; auth0 login --no-input; auth0 apis create -n $ApiName -i $ApiIdentifier --signing-alg RS256 --no-input; $ActiveTenant = (auth0 tenants list --json | ConvertFrom-Json | Where-Object { $_.active -eq $true }).name; "AUTH0_DOMAIN=$ActiveTenant`nAUTH0_AUDIENCE=$ApiIdentifier" | Out-File -FilePath .env -Encoding utf8
          ```
        </CodeGroup>

        This will create your API and automatically generate a `.env` file with your Auth0 configuration.
      </Tab>
    </Tabs>

    <Info>
      The **Identifier** is a unique identifier for your API. It's recommended to use a URL, but it doesn't have to be a publicly accessible URL—Auth0 won't call it. This value cannot be modified afterwards.
    </Info>

    Make note of the **Domain** and **Identifier** (Audience) values. You'll need these in the next step.
  </Step>

  <Step title="Define API permissions" stepNumber={4}>
    Permissions (also known as scopes) allow you to define how your API can be accessed. You can create permissions for your API in the Auth0 Dashboard.

    1. In the Auth0 Dashboard, navigate to your API's **Permissions** tab
    2. Add the following permissions:
       * `read:messages` with description "Read messages"
       * `write:messages` with description "Write messages"

    These permissions will be used to control access to specific endpoints in your API.
  </Step>

  <Step title="Configure the Auth0 client" stepNumber={5}>
    Create a `.env` file in your project root to store your Auth0 configuration:

    ```txt .env theme={null}
    AUTH0_DOMAIN=YOUR_AUTH0_DOMAIN
    AUTH0_AUDIENCE=YOUR_API_IDENTIFIER
    ```

    Replace `YOUR_AUTH0_DOMAIN` with your Auth0 domain (e.g., `dev-abc123.us.auth0.com`) and `YOUR_API_IDENTIFIER` with the identifier you set when creating your API.

    <Warning>
      Never commit your `.env` file to version control. Add it to your `.gitignore` file to keep your credentials secure.
    </Warning>

    Now create an `app.py` file and initialize your FastAPI application with Auth0:

    ```python app.py theme={null}
    from fastapi import FastAPI, Depends
    from fastapi_plugin.fast_api_client import Auth0FastAPI
    import os
    from dotenv import load_dotenv

    # Load environment variables
    load_dotenv()

    app = FastAPI()

    # Initialize Auth0
    auth0 = Auth0FastAPI(
        domain=os.environ.get("AUTH0_DOMAIN"),
        audience=os.environ.get("AUTH0_AUDIENCE")
    )
    ```
  </Step>

  <Step title="Create protected routes" stepNumber={6}>
    Add the following routes to your `app.py` file. These routes demonstrate different levels of access control:

    ```python app.py theme={null}
    from fastapi import FastAPI, Depends
    from fastapi_plugin.fast_api_client import Auth0FastAPI
    import os
    from dotenv import load_dotenv

    load_dotenv()

    app = FastAPI()

    auth0 = Auth0FastAPI(
        domain=os.environ.get("AUTH0_DOMAIN"),
        audience=os.environ.get("AUTH0_AUDIENCE")
    )

    # Public route - no authentication required
    @app.get("/api/public")
    async def public():
        return {
            "message": "Hello from a public endpoint! You don't need to be authenticated to see this."
        }

    # Protected route - requires authentication
    @app.get("/api/private")
    async def private(claims: dict = Depends(auth0.require_auth())):
        return {
            "message": "Hello from a private endpoint! You need to be authenticated to see this.",
            "user_id": claims.get("sub")
        }

    # Scoped route - requires specific permission
    @app.get("/api/private-scoped")
    async def private_scoped(claims: dict = Depends(auth0.require_auth(scopes="read:messages"))):
        return {
            "message": "Hello from a private endpoint! You need to be authenticated and have a scope of read:messages to see this.",
            "user_id": claims.get("sub")
        }
    ```

    The `require_auth()` method validates the access token sent in the Authorization header. When called with a `scopes` parameter, it also verifies that the token contains the specified permission.
  </Step>

  <Step title="Run your API" stepNumber={7}>
    Start your FastAPI application:

    ```bash theme={null}
    uvicorn app:app --reload
    ```

    Your API is now running on `http://localhost:8000`.

    <Check>
      Visit `http://localhost:8000/api/public` in your browser. You should see the public message without needing authentication.
    </Check>
  </Step>
</Steps>

***

## Test your API

To test the protected endpoints, you'll need to obtain an access token from Auth0.

### Get an access token

The easiest way to get an access token for testing is through the Auth0 Dashboard:

1. Navigate to [Applications > APIs](https://manage.auth0.com/#/apis) in the Auth0 Dashboard
2. Select your API
3. Click the **Test** tab
4. Click **Copy Token** in the **Asking Auth0 for tokens from my application** section

### Call your API

Use the access token to call your protected endpoint:

```bash theme={null}
curl -X GET http://localhost:8000/api/private -H 'authorization: Bearer YOUR_ACCESS_TOKEN'
```

You should receive a response with the private message and your user ID.

To test the scoped endpoint, make sure your token includes the `read:messages` scope:

```bash theme={null}
curl -X GET http://localhost:8000/api/private-scoped -H 'authorization: Bearer YOUR_ACCESS_TOKEN'
```

If your token doesn't have the required scope, you'll receive a 403 Forbidden response.

***

## Advanced Usage

<Accordion title="Validate custom claims">
  You can access custom claims that have been added to the access token through [Auth0 Actions](https://auth0.com/docs/customize/actions).

  Access custom claims in your route handler:

  ```python theme={null}
  @app.get("/api/profile")
  async def profile(claims: dict = Depends(auth0.require_auth())):
      return {
          "user_id": claims.get("sub"),
          "email": claims.get("email"),
          "permissions": claims.get("permissions", []),
          "custom_claim": claims.get("https://myapp.example.com/custom_claim")
      }
  ```

  To add custom claims to your access tokens, create an Auth0 Action:

  1. Navigate to **Actions > Library** in the Auth0 Dashboard
  2. Click **Create Action**
  3. Select **Build from scratch**
  4. Name your action and select the **Login / Post Login** trigger
  5. Add your custom claims:

  ```javascript theme={null}
  exports.onExecutePostLogin = async (event, api) => {
    const namespace = 'https://myapp.example.com';

    if (event.authorization) {
      // Add custom claim to access token
      api.accessToken.setCustomClaim(`${namespace}/roles`, event.user.app_metadata.roles || []);
    }
  };
  ```

  6. Click **Deploy** and add the action to your Login flow

  <Info>
    Custom claims must use a namespaced format (e.g., `https://myapp.example.com/claim_name`) to avoid conflicts with standard claims.
  </Info>
</Accordion>

<Accordion title="Protect endpoints without using claims">
  If you need to protect an endpoint but don't need to access the claims, you can use the `dependencies` parameter:

  ```python theme={null}
  @app.get("/api/protected", dependencies=[Depends(auth0.require_auth())])
  async def protected():
      return {"message": "This endpoint is protected"}
  ```

  This validates the access token but doesn't inject the claims into your function.
</Accordion>

<Accordion title="DPoP support">
  <Info>
    DPoP (Demonstrating Proof-of-Possession) is currently in [Early Access](https://auth0.com/docs/troubleshoot/product-lifecycle/product-release-stages). Contact [Auth0 support](https://support.auth0.com/) to enable it for your tenant.
  </Info>

  DPoP provides enhanced security by cryptographically binding access tokens to the client that requested them. This prevents token theft and replay attacks.

  The SDK enables DPoP support by default. You can configure DPoP behavior:

  ```python theme={null}
  auth0 = Auth0FastAPI(
      domain=os.environ.get("AUTH0_DOMAIN"),
      audience=os.environ.get("AUTH0_AUDIENCE"),
      dpop_enabled=True,      # Enable DPoP (default: True)
      dpop_required=False     # Require DPoP (default: False)
  )
  ```

  **Mixed mode** (default) accepts both Bearer and DPoP tokens:

  ```python theme={null}
  auth0 = Auth0FastAPI(
      domain=os.environ.get("AUTH0_DOMAIN"),
      audience=os.environ.get("AUTH0_AUDIENCE"),
      dpop_enabled=True,
      dpop_required=False
  )
  ```

  **DPoP-only mode** rejects Bearer tokens:

  ```python theme={null}
  auth0 = Auth0FastAPI(
      domain=os.environ.get("AUTH0_DOMAIN"),
      audience=os.environ.get("AUTH0_AUDIENCE"),
      dpop_required=True
  )
  ```

  When using DPoP, clients must include both the `Authorization: DPoP <token>` and `DPoP: <proof>` headers. The SDK automatically validates the DPoP proof and binds it to the access token.
</Accordion>

<Accordion title="Configure for reverse proxy">
  <Warning>
    Only enable `trust_proxy` when your application is behind a trusted reverse proxy. Never enable this for applications directly exposed to the internet.
  </Warning>

  If your application runs behind a reverse proxy (nginx, AWS ALB, etc.), you need to enable proxy trust for DPoP validation to work correctly:

  ```python theme={null}
  from fastapi import FastAPI

  app = FastAPI()

  # Enable proxy trust
  app.state.trust_proxy = True

  auth0 = Auth0FastAPI(
      domain=os.environ.get("AUTH0_DOMAIN"),
      audience=os.environ.get("AUTH0_AUDIENCE")
  )
  ```

  Configure your reverse proxy to forward the necessary headers:

  ```nginx theme={null}
  location /api {
      proxy_pass http://localhost:8000;
      proxy_set_header X-Forwarded-Proto $scheme;
      proxy_set_header X-Forwarded-Host $host;
      proxy_set_header X-Forwarded-Prefix /api;
  }
  ```

  This is essential for DPoP validation because the SDK needs to match the exact URL the client used. Without proxy trust, your application sees internal URLs while DPoP proofs reference external URLs, causing validation failures.
</Accordion>

<Accordion title="Error handling">
  The SDK raises `HTTPException` for authentication errors. FastAPI handles these automatically, returning appropriate HTTP responses to the client.

  You can implement custom error handling if needed:

  ```python theme={null}
  from fastapi import Request
  from fastapi.responses import JSONResponse
  from fastapi.exceptions import HTTPException

  @app.exception_handler(HTTPException)
  async def custom_http_exception_handler(request: Request, exc: HTTPException):
      if exc.status_code in [401, 403]:
          return JSONResponse(
              status_code=exc.status_code,
              content={
                  "error": "authentication_failed",
                  "message": "You must be authenticated to access this resource",
                  "details": exc.detail
              }
          )
      return JSONResponse(
          status_code=exc.status_code,
          content={"detail": exc.detail}
      )
  ```

  Authentication errors include:

  * **401 Unauthorized**: Missing, invalid, or expired access token
  * **403 Forbidden**: Valid token but insufficient permissions (scopes)
</Accordion>

***

## Common Issues

<AccordionGroup>
  <Accordion title="401 Unauthorized - Invalid audience">
    **Problem**: Token validation fails with "Invalid audience" error.

    **Solution**: Verify that the `AUTH0_AUDIENCE` in your `.env` file exactly matches the **Identifier** you configured for your API in the Auth0 Dashboard.

    1. Open the Auth0 Dashboard and navigate to **Applications > APIs**
    2. Select your API
    3. Check the **Identifier** value in the Settings tab
    4. Update your `.env` file:
       ```txt theme={null}
       AUTH0_AUDIENCE=https://your-exact-api-identifier
       ```
    5. Restart your application
  </Accordion>

  <Accordion title="401 Unauthorized - Invalid issuer">
    **Problem**: Token validation fails with "Invalid issuer" error.

    **Solution**: Verify that your `AUTH0_DOMAIN` is correct and does not include the `https://` protocol.

    Your domain should look like `dev-abc123.us.auth0.com`, not `https://dev-abc123.us.auth0.com`.

    Update your `.env` file:

    ```txt theme={null}
    AUTH0_DOMAIN=dev-abc123.us.auth0.com
    ```
  </Accordion>

  <Accordion title="403 Forbidden - Insufficient scope">
    **Problem**: Protected endpoint returns 403 even with a valid access token.

    **Solution**: The access token doesn't include the required scope.

    1. Check what scopes your endpoint requires
    2. When requesting a token, ensure you include the required scopes
    3. Verify the scope exists in your API's Permissions tab in the Auth0 Dashboard
    4. Decode your token at [jwt.io](https://jwt.io) to verify it contains the `scope` claim with the required values
  </Accordion>

  <Accordion title="ModuleNotFoundError: No module named 'fastapi_plugin'">
    **Problem**: Python cannot find the Auth0 FastAPI SDK.

    **Solution**: Ensure the SDK is installed in your active virtual environment.

    ```bash theme={null}
    # Activate your virtual environment
    source venv/bin/activate  # Windows: venv\Scripts\activate

    # Install the SDK
    pip install auth0-fastapi-api

    # Verify installation
    pip show auth0-fastapi-api
    ```
  </Accordion>

  <Accordion title="Cannot connect to Auth0 (JWKS fetch failed)">
    **Problem**: Application cannot fetch signing keys from Auth0.

    **Solution**: Check your network connectivity and domain configuration.

    1. Verify your domain is accessible:
       ```bash theme={null}
       curl https://YOUR_DOMAIN/.well-known/openid-configuration
       ```

    2. Check that your firewall allows outbound HTTPS (port 443) connections to `*.auth0.com`

    3. If behind a corporate proxy, configure the `HTTP_PROXY` and `HTTPS_PROXY` environment variables
  </Accordion>

  <Accordion title="DPoP validation fails">
    **Problem**: DPoP authentication returns errors about URL or proof validation.

    **Solution**:

    1. If behind a reverse proxy, enable proxy trust:
       ```python theme={null}
       app.state.trust_proxy = True
       ```

    2. Verify your proxy forwards these headers:
       * `X-Forwarded-Proto`
       * `X-Forwarded-Host`
       * `X-Forwarded-Prefix`

    3. Ensure DPoP is enabled for your tenant (contact Auth0 support)

    4. Verify the DPoP proof `htu` claim matches your request URL exactly
  </Accordion>
</AccordionGroup>

***

## Next Steps

<CardGroup cols={3}>
  <Card title="SDK Documentation" icon="github" href="https://github.com/auth0/auth0-fastapi-api">
    Explore the Auth0 FastAPI SDK on GitHub for advanced configuration and examples
  </Card>

  <Card title="Scopes and Permissions" icon="lock" href="https://auth0.com/docs/get-started/apis/scopes">
    Learn how to define and use scopes for fine-grained access control
  </Card>

  <Card title="Auth0 Actions" icon="bolt" href="https://auth0.com/docs/customize/actions">
    Customize your authentication flow and add custom claims to tokens
  </Card>

  <Card title="FastAPI Documentation" icon="book" href="https://fastapi.tiangolo.com/">
    Learn more about FastAPI features, async patterns, and best practices
  </Card>

  <Card title="API Authorization" icon="shield-check" href="https://auth0.com/docs/authorization">
    Implement role-based access control (RBAC) for your API
  </Card>

  <Card title="Deploy to Production" icon="server" href="https://auth0.com/docs/deploy">
    Best practices for deploying FastAPI applications with Auth0
  </Card>
</CardGroup>
