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.
Metadata
Release files for pyallauth 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pyallauth-0.1.0.tar.gz | 43.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pyallauth-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 102.8 kB
Release files / pyallauth-0.1.0.tar.gz
| Download URL | pyallauth-0.1.0.tar.gz |
|---|---|
| Size | 43.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f57fd4ee8e8d896a0a5ffe5902e11de58fc3ef11dd4d27c84afcd39c925b59b3
|
|
BLAKE2b-256 checksum How to use checksums |
124aae8e9e6e2cb6026de16f1b54180e7891c213050558132dbc1d0fde131b26
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/2.1.2 CPython/3.12.9 Darwin/25.3.0
|
Release files / pyallauth-0.1.0-py3-none-any.whl
| Download URL | pyallauth-0.1.0-py3-none-any.whl |
|---|---|
| Size | 58.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
afae453558565f20bcd69c60a18756783c29a87236cc0f52d54414967653d3cf
|
|
BLAKE2b-256 checksum How to use checksums |
6e07236acc88c1a138ff7425cc1f8464b7e1f71657b185d2417e0f960430cc46
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/2.1.2 CPython/3.12.9 Darwin/25.3.0
|