Skip to main content

A complete OAuth2 authentication plugin for FastAPI with user management, roles, and permissions

Project description

FastAPI Auth Plugin

A production-ready, plug-and-play authentication system for FastAPI applications with OAuth2 Password Flow, JWT tokens, role-based access control (RBAC), and PostgreSQL backend.

Features

  • OAuth2 Password Flow with JWT access and refresh tokens
  • Google OAuth Integration - Sign in with Google (optional)
  • User Management - Registration, login, profile management
  • Role-Based Access Control (RBAC) - Flexible roles and permissions system
  • PostgreSQL Backend with SQLAlchemy ORM
  • Secure Password Hashing using Bcrypt
  • FastAPI Dependencies for easy route protection
  • Granular Permissions with resource:action pattern
  • Production Ready with comprehensive error handling
  • Fully Typed with Pydantic models
  • Extensible - Easy to customize and extend

Installation

pip install fastapi-auth-plugin

Or install from source:

cd fastapi-auth-plugin
pip install -e .

Quick Start

1. Set up environment variables

Create a .env file:

DATABASE_URL=postgresql://postgres:password@localhost:5432/your_db
SECRET_KEY=your-secret-key-here-change-in-production

Generate a secure secret key:

python -c "import secrets; print(secrets.token_urlsafe(32))"

2. Integrate into your FastAPI app

from fastapi import FastAPI, Depends
from fastapi_auth_plugin import auth_router, get_current_user, init_db, models

app = FastAPI()

# Initialize database on startup
@app.on_event("startup")
async def startup():
    init_db()

# Include authentication routes
app.include_router(auth_router, prefix="/api")

# Protected route example
@app.get("/protected")
def protected_route(user: models.User = Depends(get_current_user)):
    return {"message": f"Hello {user.username}!"}

3. Run your application

uvicorn main:app --reload

Visit http://localhost:8000/docs for interactive API documentation.

4. Default superuser password

On every application startup, init_db() ensures the admin superuser exists and generates a new random password.

The generated password is printed to the console at startup.

Username: admin
Password: <random-generated-at-startup>

WARNING: this password rotates on each restart, so store it securely if you need it.

Google OAuth Setup (Optional)

The plugin supports Google OAuth for easier user authentication and registration.

1. Create Google OAuth Credentials

  1. Go to Google Cloud Console
  2. Create a new project or select an existing one
  3. Enable the Google+ API (People API)
  4. Go to CredentialsCreate CredentialsOAuth 2.0 Client ID
  5. Configure the OAuth consent screen
  6. For Application type, select Web application
  7. Add authorized redirect URIs:
    • http://localhost:8000/api/auth/google/callback (for web/API usage)
    • http://localhost:9999/callback (for Qt desktop client - automated flow)
    • https://yourdomain.com/api/auth/google/callback (production)
  8. Copy your Client ID and Client Secret

2. Configure Environment Variables

Add to your .env file:

GOOGLE_CLIENT_ID=your-google-client-id.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=your-google-client-secret
GOOGLE_REDIRECT_URI=http://localhost:8000/api/auth/google/callback

3. Register OAuth Providers

Update your FastAPI app to register OAuth providers on startup:

from fastapi import FastAPI
from fastapi_auth_plugin import auth_router, init_db, register_oauth_providers

app = FastAPI()

@app.on_event("startup")
async def startup():
    init_db()
    register_oauth_providers()  # Register Google OAuth

app.include_router(auth_router, prefix="/api")

4. Use Google Login

Via API (Web Flow):

  1. Direct users to GET /api/auth/google/login
  2. They'll be redirected to Google for authentication
  3. After approval, Google redirects to /api/auth/google/callback
  4. The callback returns JWT tokens in JSON format

Via Qt Client (Device Flow - Recommended):

  • Click the "🔐 Login with Google" button
  • Authenticate in your browser
  • The tokens are automatically retrieved via polling
  • No manual copy/paste required!

This uses a modern backend-mediated OAuth flow similar to VS Code, GitHub CLI, and other desktop applications.

How Device Flow Works

  1. Client calls /auth/google/device/initiate to get a unique state and auth URL
  2. Client opens the auth URL in the user's browser
  3. User authenticates with Google, which redirects to the backend
  4. Backend stores JWT tokens associated with the state
  5. Client polls /auth/google/device/poll with the state until tokens are ready
  6. Client receives tokens automatically

This approach eliminates the need for local HTTP servers or redirect URI registration on arbitrary ports.

Google OAuth Features

  • No password required - Users authenticate with their Google account
  • Auto account creation - New accounts are created automatically
  • Account linking - Existing users can link their Google account
  • Profile sync - User email and profile picture from Google
  • Same JWT tokens - Works seamlessly with existing authentication flow
  • Desktop-friendly - Modern device flow for desktop/CLI applications

Google OAuth API Endpoints

Method Endpoint Description
GET /auth/google/login Initiate Google OAuth flow (web)
GET /auth/google/callback Handle Google OAuth callback
GET /auth/google/device/initiate Initiate device/desktop OAuth flow
GET /auth/google/device/poll Poll for OAuth tokens (device flow)
POST /auth/google/exchange Exchange OAuth code for tokens (legacy)

Usage Examples

Protect Routes with Authentication

from fastapi import Depends
from fastapi_auth_plugin import get_current_user, models

@app.get("/profile")
def get_profile(user: models.User = Depends(get_current_user)):
    return {
        "username": user.username,
        "email": user.email,
        "roles": [role.name for role in user.roles]
    }

Require Specific Roles

from fastapi_auth_plugin import require_role

@app.get("/admin/dashboard")
def admin_dashboard(user = Depends(require_role("admin", "superuser"))):
    return {"message": "Admin access granted"}

Require Specific Permissions

from fastapi_auth_plugin import require_permission

@app.delete("/posts/{post_id}")
def delete_post(
    post_id: int,
    user = Depends(require_permission("posts", "delete"))
):
    return {"message": f"Post {post_id} deleted"}

Optional Authentication

from fastapi_auth_plugin import optional_user

@app.get("/posts")
def list_posts(user = Depends(optional_user)):
    if user:
        # Show personalized content
        return {"posts": [...], "user": user.username}
    else:
        # Show public content
        return {"posts": [...]}

API Endpoints

Authentication

Method Endpoint Description Auth Required
POST /auth/register Register new user No
POST /auth/login Login (OAuth2) No
POST /auth/refresh Refresh access token No
POST /auth/logout Logout Yes
GET /auth/me Get current user profile Yes
PUT /auth/me Update current user Yes

User Management (Admin)

Method Endpoint Description Permission
GET /auth/users List all users users:read
GET /auth/users/{id} Get user by ID users:read
PUT /auth/users/{id} Update user users:write
DELETE /auth/users/{id} Delete user users:delete
POST /auth/users/{id}/roles Assign roles users:write

Role Management

Method Endpoint Description Permission
GET /auth/roles List all roles roles:read
POST /auth/roles Create role Superuser
PUT /auth/roles/{id} Update role Superuser
DELETE /auth/roles/{id} Delete role Superuser

Permissions

Method Endpoint Description Permission
GET /auth/permissions List all permissions permissions:read
POST /auth/permissions Create permission Superuser

Configuration

All settings can be configured via environment variables:

from fastapi_auth_plugin import AuthSettings

# Custom configuration
settings = AuthSettings(
    DATABASE_URL="postgresql://user:pass@localhost/db",
    SECRET_KEY="your-secret-key",
    ACCESS_TOKEN_EXPIRE_MINUTES=30,
    REFRESH_TOKEN_EXPIRE_DAYS=7,
    ALGORITHM="HS256"
)

Available Settings

Variable Default Description
DATABASE_URL postgresql://... PostgreSQL connection URL
SECRET_KEY (required) Secret key for JWT signing
ALGORITHM HS256 JWT algorithm
ACCESS_TOKEN_EXPIRE_MINUTES 30 Access token lifetime
REFRESH_TOKEN_EXPIRE_DAYS 7 Refresh token lifetime
TOKEN_URL /auth/login OAuth2 token endpoint
GOOGLE_CLIENT_ID None Google OAuth client ID (optional)
GOOGLE_CLIENT_SECRET None Google OAuth client secret (optional)
GOOGLE_REDIRECT_URI http://localhost:8000/api/auth/google/callback Google OAuth redirect URI

Database Schema

User Model

  • id: int (primary key)
  • email: str (unique)
  • username: str (unique)
  • hashed_password: str (nullable for OAuth users)
  • is_active: bool
  • is_superuser: bool
  • google_id: str (nullable, unique - Google OAuth user ID)
  • google_picture: str (nullable - Google profile picture URL)
  • oauth_provider: str (nullable - 'google', 'github', etc.)
  • created_at: datetime
  • updated_at: datetime
  • roles: list[Role] (many-to-many)

Role Model

  • id: int (primary key)
  • name: str (unique)
  • description: str
  • permissions: list[Permission] (many-to-many)
  • users: list[User] (many-to-many)

Permission Model

  • id: int (primary key)
  • name: str (unique, e.g., "users:read")
  • resource: str (e.g., "users")
  • action: str (e.g., "read")
  • description: str
  • roles: list[Role] (many-to-many)

Default Roles & Permissions

The system creates three default roles on initialization:

Superuser

  • All permissions
  • Full system access

Admin

  • users:read, users:write, users:delete
  • roles:read

User (default)

  • users:read (own profile only)

Running Tests

# Install dev dependencies
pip install -e ".[dev]"

# Run tests
pytest

# With coverage
pytest --cov=fastapi_auth_plugin --cov-report=html

Security Best Practices

  1. Always use HTTPS in production
  2. Store the startup-generated admin password securely (it rotates each restart)
  3. Use strong, randomly generated SECRET_KEY
  4. Set appropriate CORS policies
  5. Implement rate limiting (consider using slowapi)
  6. Use environment variables for sensitive data
  7. Regularly update dependencies
  8. Enable PostgreSQL SSL in production
  9. Monitor and log authentication attempts

Example Application

See examples/simple_app.py for a complete working example showing:

  • Database initialization
  • Protected routes
  • Role-based endpoints
  • Permission-based endpoints
  • Public and private content

Run the example:

cd examples
uvicorn simple_app:app --reload

License

MIT License - see LICENSE file for details

Changelog

0.1.0 (2024-01-06)

  • Initial release
  • OAuth2 Password Flow
  • JWT authentication
  • Role-based access control
  • PostgreSQL backend
  • Comprehensive test suite

Credits

Built with:

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fastapi_auth_plugin-0.1.5.tar.gz (39.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fastapi_auth_plugin-0.1.5-py3-none-any.whl (26.2 kB view details)

Uploaded Python 3

File details

Details for the file fastapi_auth_plugin-0.1.5.tar.gz.

File metadata

  • Download URL: fastapi_auth_plugin-0.1.5.tar.gz
  • Upload date:
  • Size: 39.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.12

File hashes

Hashes for fastapi_auth_plugin-0.1.5.tar.gz
Algorithm Hash digest
SHA256 bde80b30bb524871d8106b9825326393c047559a585f99a915795926a05b11fc
MD5 ab85e0290860f05727f8bfebff1a09ea
BLAKE2b-256 aeec1af7e56a9649a07578992a63c3010293641623f52af6c4dd8b84a64d2f0f

See more details on using hashes here.

File details

Details for the file fastapi_auth_plugin-0.1.5-py3-none-any.whl.

File metadata

File hashes

Hashes for fastapi_auth_plugin-0.1.5-py3-none-any.whl
Algorithm Hash digest
SHA256 117457bdbc7ebbcf824e3deae9d1f6661deadccd2b08cf2af95e1364da49a64e
MD5 0af48ef9c8aeb58c8129d68e49f18adb
BLAKE2b-256 c87fd3b2dd3fb4c43aef12d225040e40dfdfa3a4ed39b8cea6e665503c292f91

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page