Plug-and-play authentication library for FastAPI — local + social OAuth2, JWT sessions, email verification, and more.
Project description
pyallauth
Plug-and-play authentication for FastAPI. One import, one mount, full auth.
What is pyallauth?
pyallauth is a batteries-included authentication library for FastAPI. If you've ever copy-pasted JWT boilerplate between projects, stood up a Django-allauth equivalent for FastAPI, or spent a weekend wiring together email verification, OAuth, and token refresh — this library is for you.
Mount it once and you get:
- Local auth — register, login, logout, token refresh
- Social OAuth2 — Google, GitHub, Facebook, Twitter/X
- Email verification — mandatory, optional, or disabled
- Password reset — single-use token flow with email
- Account management — profile, change email, change password, delete
- Secure JWT sessions — short-lived access + long-lived refresh with blacklisting
- Async-first — every DB call, email send, and OAuth exchange is awaitable
Features
- Single router mount — full auth in < 5 lines
- Pluggable user model — extend the base or bring your own
- Adapter pattern — SQLAlchemy async out of the box; Tortoise-ORM ready
- Pydantic v2 schemas throughout
- bcrypt password hashing with passlib CryptContext
- PKCE support for Twitter/X OAuth2
- Email backend abstraction — SMTP or console (for development)
- Refresh token rotation and blacklisting
- Single-use tokens with UTC-aware expiry
-
85% test coverage
Installation
# pip
pip install pyallauth
# With PostgreSQL support (asyncpg driver)
pip install "pyallauth[postgres]"
# Poetry
poetry add pyallauth
Requirements: Python 3.11+, FastAPI ≥ 0.110, SQLAlchemy ≥ 2.0.
Quickstart
from fastapi import FastAPI
from pyallauth import PyAllAuth
app = FastAPI()
auth = PyAllAuth(
secret_key="your-secret-key", # Required
database_url="sqlite+aiosqlite:///./app.db", # SQLite for dev
email_verification="mandatory",
email_backend="console", # Prints to terminal
)
auth.register_exception_handlers(app)
app.include_router(auth.router, prefix="/auth")
That's it. Open http://localhost:8000/docs to see all 16 auth endpoints.
Create database tables
from pyallauth.models.sqlalchemy import create_tables, make_engine
@app.on_event("startup")
async def startup():
engine = make_engine("sqlite+aiosqlite:///./app.db")
await create_tables(engine)
await engine.dispose()
In production, use Alembic migrations instead.
Protecting your own endpoints
from fastapi import Depends
@app.get("/dashboard")
async def dashboard(current_user = Depends(auth._get_current_user)):
return {"email": current_user.email}
Configuration Reference
All settings can be passed as constructor arguments to PyAllAuth or as
environment variables with the PYALLAUTH_ prefix.
| Setting | Type | Default | Description |
|---|---|---|---|
secret_key |
str |
required | JWT signing secret |
algorithm |
str |
"HS256" |
JWT algorithm |
access_token_expire |
int |
15 |
Access token lifetime (minutes) |
refresh_token_expire |
int |
7 |
Refresh token lifetime (days) |
email_verification |
str |
"mandatory" |
"mandatory", "optional", "none" |
email_backend |
str |
"console" |
"console" or "smtp" |
smtp_host |
str |
"localhost" |
SMTP server hostname |
smtp_port |
int |
587 |
SMTP server port |
smtp_user |
str |
"" |
SMTP username |
smtp_password |
str |
"" |
SMTP password |
smtp_from_email |
str |
"noreply@example.com" |
From address |
smtp_tls |
bool |
True |
Use STARTTLS |
frontend_url |
str |
"http://localhost:3000" |
Base URL for email links |
social_providers |
list[str] |
[] |
Enabled providers |
google_client_id |
str|None |
None |
Google OAuth2 client ID |
google_client_secret |
str|None |
None |
Google OAuth2 client secret |
github_client_id |
str|None |
None |
GitHub OAuth2 client ID |
github_client_secret |
str|None |
None |
GitHub OAuth2 client secret |
facebook_client_id |
str|None |
None |
Facebook app ID |
facebook_client_secret |
str|None |
None |
Facebook app secret |
twitter_client_id |
str|None |
None |
Twitter/X client ID |
twitter_client_secret |
str|None |
None |
Twitter/X client secret |
API Reference
All endpoints are mounted at the prefix you choose (/auth recommended).
Local Authentication
| Method | Path | Auth | Description |
|---|---|---|---|
POST |
/auth/register |
— | Register new account |
POST |
/auth/login |
— | Login, receive JWT pair |
POST |
/auth/logout |
— | Blacklist refresh token |
POST |
/auth/token/refresh |
— | Exchange refresh for new access token |
Register POST /auth/register
{
"email": "user@example.com",
"password": "StrongPass1!",
"full_name": "Jane Doe"
}
Login POST /auth/login
{
"email": "user@example.com",
"password": "StrongPass1!"
}
Response:
{
"access_token": "eyJ...",
"refresh_token": "eyJ...",
"token_type": "bearer",
"expires_in": 900
}
Email Verification
| Method | Path | Auth | Description |
|---|---|---|---|
GET |
/auth/email/verify/{token} |
— | Verify email with token |
POST |
/auth/email/resend |
Bearer | Resend verification email |
Password Reset
| Method | Path | Auth | Description |
|---|---|---|---|
POST |
/auth/password/reset |
— | Send reset email |
POST |
/auth/password/reset/confirm |
— | Set new password with token |
Reset request POST /auth/password/reset
{"email": "user@example.com"}
Reset confirm POST /auth/password/reset/confirm
{"token": "abc123...", "new_password": "NewStrongPass1!"}
Account Management
All endpoints require Authorization: Bearer <access_token>.
| Method | Path | Description |
|---|---|---|
GET |
/auth/account/me |
Get profile |
PATCH |
/auth/account/me |
Update profile |
POST |
/auth/account/change-password |
Change password |
POST |
/auth/account/change-email |
Change email |
DELETE |
/auth/account/me |
Delete account |
Social OAuth2
| Method | Path | Auth | Description |
|---|---|---|---|
GET |
/auth/social/{provider}/login |
— | Get authorisation URL |
GET |
/auth/social/{provider}/callback |
— | Handle callback, return JWT |
GET |
/auth/social/accounts |
Bearer | List linked accounts |
DELETE |
/auth/social/accounts/{id} |
Bearer | Disconnect account |
Supported {provider} values: google, github, facebook, twitter.
Custom User Model
pyallauth's user table (pyallauth_users) covers the required fields.
To add custom fields, subclass UserModel:
# myapp/models.py
from pyallauth.models.sqlalchemy import UserModel
from sqlalchemy.orm import Mapped, mapped_column
from sqlalchemy import String
class User(UserModel):
__tablename__ = "users" # Override table name
phone_number: Mapped[str | None] = mapped_column(String(20))
avatar_url: Mapped[str | None] = mapped_column(String(512))
Then create tables using Alembic with User in the metadata.
Custom Adapter Guide
To use a different ORM (Tortoise, Beanie, etc.):
from pyallauth.models.base import AbstractUserAdapter, UserRecord
class MyAdapter(AbstractUserAdapter):
async def get_user_by_email(self, email: str) -> UserRecord | None:
... # implement all abstract methods
# ... implement remaining 14 methods
# Pass to PyAllAuth
auth = PyAllAuth(
secret_key="...",
adapter=MyAdapter(),
)
See pyallauth/models/base.py for the full interface.
Social Provider Setup
- Google Cloud Console → Credentials → OAuth 2.0 Client ID
- Add
https://yourapp.com/auth/social/google/callbackto Authorised redirect URIs - Set
PYALLAUTH_GOOGLE_CLIENT_IDandPYALLAUTH_GOOGLE_CLIENT_SECRET
auth = PyAllAuth(
secret_key="...",
database_url="...",
social_providers=["google"],
google_client_id="your-client-id",
google_client_secret="your-client-secret",
)
GitHub
- GitHub Developer Settings → New OAuth App
- Set Authorization callback URL to
https://yourapp.com/auth/social/github/callback - Set
PYALLAUTH_GITHUB_CLIENT_IDandPYALLAUTH_GITHUB_CLIENT_SECRET
How This Was Built
Read the full step-by-step implementation journal in DEVLOG.md.
It covers every architectural decision, from the adapter pattern to token expiry
handling to why we use hmac.compare_digest for token comparisons.
Roadmap
- Tortoise-ORM adapter
- Microsoft/Azure AD provider
- LinkedIn provider
- Apple Sign In provider
- Magic link (passwordless) authentication
- WebAuthn / passkey support
- Redis-based refresh token store (for high-throughput scenarios)
- Alembic migration scripts shipped with the package
- Pre-built Jinja2 email templates
- Rate limiting on auth endpoints
Contributing
We welcome contributions of all sizes — bug fixes, new providers, new ORM adapters, documentation improvements. See CONTRIBUTING.md for the local setup guide, branch naming convention, and PR checklist.
License
MIT © 2026 officialalkenes. See LICENSE for details.
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 pyallauth-0.1.0.tar.gz.
File metadata
- Download URL: pyallauth-0.1.0.tar.gz
- Upload date:
- Size: 43.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.1.2 CPython/3.12.9 Darwin/25.3.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f57fd4ee8e8d896a0a5ffe5902e11de58fc3ef11dd4d27c84afcd39c925b59b3
|
|
| MD5 |
7cfeab5d5211ca951e31c0040dc8a990
|
|
| BLAKE2b-256 |
124aae8e9e6e2cb6026de16f1b54180e7891c213050558132dbc1d0fde131b26
|
File details
Details for the file pyallauth-0.1.0-py3-none-any.whl.
File metadata
- Download URL: pyallauth-0.1.0-py3-none-any.whl
- Upload date:
- Size: 58.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.1.2 CPython/3.12.9 Darwin/25.3.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
afae453558565f20bcd69c60a18756783c29a87236cc0f52d54414967653d3cf
|
|
| MD5 |
faa03f4b0772bc89f847d81227b65bc0
|
|
| BLAKE2b-256 |
6e07236acc88c1a138ff7425cc1f8464b7e1f71657b185d2417e0f960430cc46
|