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 credentials
The system creates a default superuser on first run:
Username: admin
Password: admin123
WARNING: CHANGE THIS PASSWORD IMMEDIATELY IN PRODUCTION!
Google OAuth Setup (Optional)
The plugin supports Google OAuth for easier user authentication and registration.
1. Create Google OAuth Credentials
- Go to Google Cloud Console
- Create a new project or select an existing one
- Enable the Google+ API (People API)
- Go to Credentials → Create Credentials → OAuth 2.0 Client ID
- Configure the OAuth consent screen
- For Application type, select Web application
- 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)
- 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):
- Direct users to
GET /api/auth/google/login - They'll be redirected to Google for authentication
- After approval, Google redirects to
/api/auth/google/callback - 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
- Client calls
/auth/google/device/initiateto get a unique state and auth URL - Client opens the auth URL in the user's browser
- User authenticates with Google, which redirects to the backend
- Backend stores JWT tokens associated with the state
- Client polls
/auth/google/device/pollwith the state until tokens are ready - 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: boolis_superuser: boolgoogle_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: datetimeupdated_at: datetimeroles: list[Role] (many-to-many)
Role Model
id: int (primary key)name: str (unique)description: strpermissions: 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: strroles: 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:deleteroles: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
- Always use HTTPS in production
- Change default admin password immediately
- Use strong, randomly generated SECRET_KEY
- Set appropriate CORS policies
- Implement rate limiting (consider using
slowapi) - Use environment variables for sensitive data
- Regularly update dependencies
- Enable PostgreSQL SSL in production
- 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:
-
Publie : python -m build twine check dist/* twine upload dist/*
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file fastapi_auth_plugin-0.1.4.tar.gz.
File metadata
- Download URL: fastapi_auth_plugin-0.1.4.tar.gz
- Upload date:
- Size: 39.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
24623d9c1914cd4f9ac441f709e3d89d3d1c12b8ace6a890174f2f5313d077ed
|
|
| MD5 |
cd4582830944db2b68f2e1d63d736533
|
|
| BLAKE2b-256 |
ae080b2bfb649daa562c2324fd211f26ee583516cb709973c90fa19e1ee95249
|
File details
Details for the file fastapi_auth_plugin-0.1.4-py3-none-any.whl.
File metadata
- Download URL: fastapi_auth_plugin-0.1.4-py3-none-any.whl
- Upload date:
- Size: 26.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
27907df74899143acd8d62a316cfc6a7abd58bbff884a769b33c099620ccd59d
|
|
| MD5 |
ae592a790ac353ab4b6a20830b17e5a0
|
|
| BLAKE2b-256 |
bbd7f9b164c57a93e6d945c9021d3e901016d37fb418c3d255ed5faf7aefe06d
|