Skip to main content

AI Prompt

Using AI to integrate Auth0? Add this prompt to Cursor, Windsurf, Copilot, Claude Code or your favourite AI-powered IDE to speed up development.
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
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 to follow along.
This guide demonstrates how to integrate Auth0 with a FastAPI API to add authentication and protect your endpoints.
1

Create a new FastAPI project

Create a new directory for your FastAPI project and set up a virtual environment.
mkdir my-fastapi-api
cd my-fastapi-api
python3 -m venv venv
source venv/bin/activate  # Windows: venv\Scripts\activate
2

Install dependencies

Create a requirements.txt file with the following dependencies:
requirements.txt
fastapi>=0.115.0
uvicorn[standard]>=0.34.0
auth0-fastapi-api>=1.0.0b5
python-dotenv>=1.0.0
Install the dependencies:
pip install -r requirements.txt
3

Setup your Auth0 API

You’ll need to create an Auth0 API to represent your FastAPI application.
  1. Navigate to Applications > 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
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.
Make note of the Domain and Identifier (Audience) values. You’ll need these in the next step.
4

Define API permissions

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.
5

Configure the Auth0 client

Create a .env file in your project root to store your Auth0 configuration:
.env
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.
Never commit your .env file to version control. Add it to your .gitignore file to keep your credentials secure.
Now create an app.py file and initialize your FastAPI application with Auth0:
app.py
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")
)
6

Create protected routes

Add the following routes to your app.py file. These routes demonstrate different levels of access control:
app.py
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.
7

Run your API

Start your FastAPI application:
uvicorn app:app --reload
Your API is now running on http://localhost:8000.
Visit http://localhost:8000/api/public in your browser. You should see the public message without needing authentication.

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 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:
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:
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

You can access custom claims that have been added to the access token through Auth0 Actions.Access custom claims in your route handler:
@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:
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 || []);
  }
};
  1. Click Deploy and add the action to your Login flow
Custom claims must use a namespaced format (e.g., https://myapp.example.com/claim_name) to avoid conflicts with standard claims.
If you need to protect an endpoint but don’t need to access the claims, you can use the dependencies parameter:
@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.
DPoP (Demonstrating Proof-of-Possession) is currently in Early Access. Contact Auth0 support to enable it for your tenant.
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:
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:
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:
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.
Only enable trust_proxy when your application is behind a trusted reverse proxy. Never enable this for applications directly exposed to the internet.
If your application runs behind a reverse proxy (nginx, AWS ALB, etc.), you need to enable proxy trust for DPoP validation to work correctly:
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:
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.
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:
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)

Common Issues

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:
    AUTH0_AUDIENCE=https://your-exact-api-identifier
    
  5. Restart your application
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:
AUTH0_DOMAIN=dev-abc123.us.auth0.com
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 to verify it contains the scope claim with the required values
Problem: Python cannot find the Auth0 FastAPI SDK.Solution: Ensure the SDK is installed in your active virtual environment.
# 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
Problem: Application cannot fetch signing keys from Auth0.Solution: Check your network connectivity and domain configuration.
  1. Verify your domain is accessible:
    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
Problem: DPoP authentication returns errors about URL or proof validation.Solution:
  1. If behind a reverse proxy, enable proxy trust:
    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

Next Steps