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

# FastAPI

> Follow the steps to set up Civic Auth with a [FastAPI](https://fastapi.tiangolo.com/) backend (a working example is available in the [github repo](https://github.com/civicteam/civic-auth-py/tree/main/examples/fastapi)).

<Info>
  **Prefer AI-assisted setup?** Use our [AI prompts for FastAPI](/ai-prompts/python/fastapi) to automatically integrate Civic Auth using Claude, ChatGPT, or other AI assistants. Includes a step-by-step video tutorial!
</Info>

## Quick Start

<Warning>
  **Important: The SDK Handles Everything**

  The Civic Auth Python SDK abstracts away all token validation complexity. You do **NOT** need to:

  * Implement custom middleware for token validation
  * Parse or validate JWT tokens manually
  * Handle token refresh logic yourself

  Simply use the provided decorators and user access functions - the SDK handles all authentication logic for you.
</Warning>

### 1. Install Dependencies

```bash theme={null}
pip install "civic-auth[fastapi]"
```

Or, if you're using the `uv` package manager:

```bash theme={null}
uv add "civic-auth[fastapi]"
```

### 2. Create Your App with Authentication

Create your FastAPI app with Civic Auth integration:

```python theme={null}
from fastapi import FastAPI, Depends
from civic_auth.integrations.fastapi import create_auth_router, create_auth_dependencies

app = FastAPI()

# Configuration
config = {
    "client_id": "YOUR_CLIENT_ID",  # Get this from auth.civic.com
    "redirect_url": "http://localhost:8000/auth/callback",
    "post_logout_redirect_url": "http://localhost:8000/"
}

# Add authentication routes
app.include_router(create_auth_router(config))

# Create dependencies for protecting routes
civic_auth_dep, get_current_user, require_auth = create_auth_dependencies(config)
```

### 3. Add Basic Routes

```python theme={null}
from fastapi.responses import RedirectResponse

@app.get("/")
async def home():
    return {"message": "Welcome! Go to /auth/login to sign in"}

@app.get("/login")
async def login():
    return RedirectResponse(url="/auth/login")
```

### 4. Add Protected Routes

```python theme={null}
@app.get("/profile")
async def profile(user = Depends(get_current_user)):
    return {
        "message": f"Hello, {user.get('name', 'User')}!",
        "user_info": {
            "id": user.get("id"),
            "email": user.get("email"),
            "name": user.get("name"),
            "picture": user.get("picture")
        }
    }

@app.get("/dashboard", dependencies=[Depends(require_auth)])
async def dashboard(user = Depends(get_current_user)):
    return {
        "message": "Welcome to your dashboard!",
        "user_name": user.get("name", "User")
    }
```

### 5. Run Your App

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

Visit `http://localhost:8000` and click the login link to test authentication.

## How It Works

### Authentication Flow

1. User visits `/auth/login` - starts the login process
2. User authenticates with Civic
3. User gets redirected to `/auth/callback` - completes authentication
4. User can now access protected routes

### Available Routes

* `/auth/login` - Start authentication
* `/auth/callback` - Handle OAuth callback (auto-created)
* `/auth/logout` - Sign out user

### Working with User Data

The `get_current_user` dependency returns a dictionary with user information:

```python theme={null}
@app.get("/user-info")
async def user_info(user = Depends(get_current_user)):
    # Safe way to access user data
    return {
        "id": user.get("id"),
        "email": user.get("email", "No email"),
        "name": user.get("name", "Anonymous"),
        "picture": user.get("picture")
    }
```

### Protecting Routes

Two ways to protect routes:

**Method 1: Using `require_auth` dependency**

```python theme={null}
@app.get("/admin", dependencies=[Depends(require_auth)])
async def admin_page():
    return {"message": "Admin only content"}
```

**Method 2: Using `get_current_user` directly**

```python theme={null}
@app.get("/profile")
async def profile(user = Depends(get_current_user)):
    return {"user": user}
```

## Complete Example

Here's a complete working FastAPI app:

```python theme={null}
from fastapi import FastAPI, Depends, Request
from fastapi.responses import RedirectResponse
from civic_auth.integrations.fastapi import create_auth_router, create_auth_dependencies

app = FastAPI(title="My Civic Auth App")

# Configuration
config = {
    "client_id": "YOUR_CLIENT_ID",  # Replace with your actual client ID
    "redirect_url": "http://localhost:8000/auth/callback",
    "post_logout_redirect_url": "http://localhost:8000/"
}

# Set up authentication
app.include_router(create_auth_router(config))
civic_auth_dep, get_current_user, require_auth = create_auth_dependencies(config)

@app.get("/")
async def home():
    return {
        "message": "Welcome to My App!", 
        "login_url": "/auth/login",
        "protected_routes": ["/profile", "/dashboard"]
    }

@app.get("/profile")
async def profile(user = Depends(get_current_user)):
    return {
        "authenticated": True,
        "user": {
            "id": user.get("id"),
            "name": user.get("name"),
            "email": user.get("email")
        },
        "logout_url": "/auth/logout"
    }

@app.get("/dashboard", dependencies=[Depends(require_auth)])
async def dashboard(user = Depends(get_current_user)):
    return {
        "message": f"Welcome to your dashboard, {user.get('name', 'User')}!",
        "user_id": user.get("id")
    }

@app.get("/public")
async def public():
    return {"message": "This is a public endpoint - no authentication required"}

# Optional: Check authentication status without requiring login
@app.get("/auth-status")
async def auth_status(request: Request):
    try:
        user = await get_current_user.__wrapped__(request)
        return {"authenticated": True, "user_name": user.get("name")}
    except:
        return {"authenticated": False}

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)
```

## Configuration Options

| Field                      | Required | Description                                                             |
| -------------------------- | -------- | ----------------------------------------------------------------------- |
| `client_id`                | Yes      | Your Civic Auth Client ID from [auth.civic.com](https://auth.civic.com) |
| `redirect_url`             | Yes      | Where Civic redirects after authentication (must be absolute URL)       |
| `post_logout_redirect_url` | Yes      | Where users go after logout (must be absolute URL)                      |

## Next Steps

1. **Get your Client ID**: Sign up at [auth.civic.com](https://auth.civic.com)
2. **Replace `YOUR_CLIENT_ID`** with your actual client ID
3. **Update URLs** when deploying to production
4. **Add more protected routes** as needed

## Authentication Flows

Civic Auth supports multiple OAuth 2.0 authentication methods to provide maximum security for different application architectures.

<Info>
  **Need client secret authentication?** Civic Auth supports PKCE-only, client secrets, and hybrid PKCE + client secret approaches. See our [Authentication Flows guide](/overview/authentication-flows) for detailed comparison.
</Info>

The examples above use PKCE authentication, which is handled entirely by the Civic Auth SDK and suitable for most applications.

### Access Tokens

Use the CivicAuth dependency to retrieve tokens (auto-refresh):

```python theme={null}
from fastapi import Depends
from civic_auth.integrations.fastapi import create_auth_dependencies

civic_auth_dep, get_current_user, require_auth = create_auth_dependencies(config)

@app.get("/tokens", dependencies=[Depends(require_auth)])
async def tokens(civic = Depends(civic_auth_dep)):
    return await civic.get_tokens()
```
