A simple and robust OTP (One-Time Password) authentication library for FastAPI, backed by Redis and Email.
Project description
FastAPI OTP Auth
A simple and robust OTP (One-Time Password) authentication library for FastAPI, backed by Redis and Email.
Why OTP?
Passwords are a pain. Users forget them, reuse them, and they are a prime target for attackers. Storing them securely is a liability.
FastAPI OTP Auth solves this by eliminating passwords entirely:
- 🧠 No Memory Required: Users don't need to remember complex passwords.
- 💾 Zero Password Storage: You don't have to worry about hashing, salting, or leaking passwords.
- 🔄 Simplified Flows: No more "Forgot Password" or "Reset Password" complexity.
- 🛡️ Enhanced Security: OTPs are short-lived and one-time use, mitigating credential stuffing and replay attacks.
Features
- 🔐 Secure OTP Generation: Cryptographically secure 6-digit codes.
- 🎫 JWT Support: Auto-generates Access and Refresh tokens upon verification.
- 🍪 HttpOnly Cookies: Securely stores refresh tokens in HttpOnly cookies.
- ⚡ Redis-Backed: Fast and reliable storage for OTPs with automatic expiration.
- 📧 Email Delivery: Integrated email sending using
fastapi-mail. - 🔌 Easy Integration: Drop-in
APIRouterfor quick setup. - ⚙️ Configurable: Fully customizable via environment variables.
- 🚫 Token Blacklisting: Secure logout and immediate token revocation.
Installation
pip install fastapi-otp-auth
Or using uv:
uv add fastapi-otp-auth
Configuration
The library is configured using environment variables. The prefix for all variables is FASTAPI_OTP_AUTH_.
| Variable | Description | Default |
|---|---|---|
FASTAPI_OTP_AUTH_REDIS_URL |
Connection string for Redis | redis://localhost:6379/0 |
FASTAPI_OTP_AUTH_SMTP_SERVER |
SMTP server hostname | 127.0.0.1 |
FASTAPI_OTP_AUTH_SMTP_PORT |
SMTP server port | 1025 |
FASTAPI_OTP_AUTH_SMTP_USERNAME |
SMTP username | user@example.com |
FASTAPI_OTP_AUTH_SMTP_PASSWORD |
SMTP password | password |
FASTAPI_OTP_AUTH_MAIL_FROM_NAME |
Sender name for emails | FastAPI App |
FASTAPI_OTP_AUTH_OTP_EXPIRY_SECONDS |
OTP validity duration in seconds | 300 (5 minutes) |
FASTAPI_OTP_AUTH_OTP_KEY_PREFIX |
Prefix for Redis keys | otp_ |
FASTAPI_OTP_AUTH_JWT_SECRET |
Secret key for signing JWTs | change-me-in-production |
FASTAPI_OTP_AUTH_JWT_ALGORITHM |
Algorithm for JWTs | HS256 |
FASTAPI_OTP_AUTH_ACCESS_TOKEN_EXPIRE_MINUTES |
Access token lifetime | 60 (1 hour) |
FASTAPI_OTP_AUTH_REFRESH_TOKEN_EXPIRE_DAYS |
Refresh token lifetime | 7 (7 days) |
FASTAPI_OTP_AUTH_BLACKLIST_KEY_PREFIX |
Prefix for blacklisted tokens in Redis | blacklist_ |
FASTAPI_OTP_AUTH_DISABLE_LOCAL_AUTH |
Enable "Magic OTP" flow (skips email, accepts 000000) |
False |
Local Development (Magic OTP)
To simplify local development and testing, you can enable the "Magic OTP" flow. This allows you to log in as any user using the fixed OTP code 000000, without sending actual emails with the OTP.
- Set
FASTAPI_OTP_AUTH_DISABLE_LOCAL_AUTH=truein your local.envfile or environment. - Request an OTP for any email (e.g.,
test@example.com). - Verify using the code
000000.
[!WARNING] Security Risk: Ensure this environment variable is NEVER set to
truein production environments.
Usage
Import the auth_router and include it in your FastAPI application:
from fastapi import FastAPI
from fastapi_otp_auth.auth_router import router as auth_router
app = FastAPI()
# Include the router
app.include_router(auth_router, prefix="/auth", tags=["Authentication"])
# The following endpoints will be available:
# POST /auth/request-otp - Request a new OTP
# POST /auth/verify-otp - Verify a received OTP
# POST /auth/logout - Logout and blacklist tokens
Requesting an OTP
Send a POST request to /auth/request-otp:
{
"email": "user@example.com"
}
Verifying an OTP
Send a POST request to /auth/verify-otp:
{
"email": "user@example.com",
"otp": "123456"
}
On success, the response will contain the access token, and the refresh token will be set as an HttpOnly cookie:
{
"message": "OTP verified successfully!",
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "bearer"
}
Protecting Routes
Use the get_current_user dependency to protect routes. This will verify the access token and return the user's email.
from fastapi import Depends
from fastapi_otp_auth.dependencies import get_current_user
@app.get("/protected")
async def protected_route(user: str = Depends(get_current_user)):
return {"message": f"Hello, {user}!"}
Refreshing Tokens
To get a new access token using the HttpOnly refresh token cookie, send a POST request to /auth/refresh. The browser will automatically include the cookie.
POST /auth/refresh
Response:
{
"access_token": "new_access_token_here",
"token_type": "bearer"
}
### Logging Out
To logout, send a POST request to `/auth/logout`. This will blacklist both the access token (provided in the Authorization header) and the refresh token (provided in the cookie).
```bash
POST /auth/logout
Authorization: Bearer <access_token>
Cookie: refresh_token=<refresh_token>
Response:
{
"message": "Successfully logged out"
}
Development
To run tests locally using Docker (no local environment needed):
make test
This will spin up a Redis container and run the test suite in an isolated environment.
Running Checks
To run linting checks (ruff) using Docker:
docker-compose -f docker-compose.test.yml run --rm app-test uv run ruff check .
Pre-commit Hooks
To automatically run checks before every commit, install the pre-commit hooks:
uv run pre-commit install
You can also run the hooks manually against all files:
uv run pre-commit run --all-files
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
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_otp_auth-0.1.4.tar.gz.
File metadata
- Download URL: fastapi_otp_auth-0.1.4.tar.gz
- Upload date:
- Size: 85.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.13 {"installer":{"name":"uv","version":"0.9.13"},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
87a159092e9d438892ecde3893b97d29530ece57c7f6c8efa13cc5569fefafe5
|
|
| MD5 |
ee61162cd192582ab6b9d4e1e8642a09
|
|
| BLAKE2b-256 |
8c51c2444e2b750dbecc505b6d5ec5a6d1f769d843ee0c63ffa1e3d769b18617
|
File details
Details for the file fastapi_otp_auth-0.1.4-py3-none-any.whl.
File metadata
- Download URL: fastapi_otp_auth-0.1.4-py3-none-any.whl
- Upload date:
- Size: 10.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.13 {"installer":{"name":"uv","version":"0.9.13"},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
76023de95e5d8a93d217c5d0fb11e16a933c0047b3d84512c4525b6fe3c4212f
|
|
| MD5 |
74e60e4f9984ae5650a85d877a598400
|
|
| BLAKE2b-256 |
287fe2d254238300d834f6abd1c8dec95c1d01cb65f4bb7a96c02794a281b3f2
|