FastAPI
Prefer AI-assisted setup? Use our AI prompts for FastAPI to automatically integrate Civic Auth using Claude, ChatGPT, or other AI assistants. Includes a step-by-step video tutorial!
Quick Start
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.
1. Install Dependencies
pip install "civic-auth[fastapi]"
Or, if you're using the uv package manager:
uv add "civic-auth[fastapi]"
2. Create Your App with Authentication
Create your FastAPI app with Civic Auth integration:
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
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
@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
uvicorn main:app --reload
Visit http://localhost:8000 and click the login link to test authentication.
How It Works
Authentication Flow
- User visits
/auth/login- starts the login process - User authenticates with Civic
- User gets redirected to
/auth/callback- completes authentication - 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:
@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
@app.get("/admin", dependencies=[Depends(require_auth)])
async def admin_page():
return {"message": "Admin only content"}
Method 2: Using get_current_user directly
@app.get("/profile")
async def profile(user = Depends(get_current_user)):
return {"user": user}
Complete Example
Here's a complete working FastAPI app:
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 |
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
- Get your Client ID: Sign up at auth.civic.com
- Replace
YOUR_CLIENT_IDwith your actual client ID - Update URLs when deploying to production
- 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.
Need client secret authentication? Civic Auth supports PKCE-only, client secrets, and hybrid PKCE + client secret approaches. See our Authentication Flows guide for detailed comparison.
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):
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()