### Run SQLAlchemy Example Application (Bash) Source: https://github.com/gronnmann/fastapi-otp-authentication/blob/master/README.md Execute the basic SQLAlchemy usage example for FastAPI OTP Authentication. This command starts a development server to run the example application, typically for testing or demonstration purposes. ```bash uv run python examples/basic_usage.py ``` -------------------------------- ### Run MongoDB Example Application (Bash) Source: https://github.com/gronnmann/fastapi-otp-authentication/blob/master/README.md Start the MongoDB example application for FastAPI OTP Authentication. This involves first ensuring MongoDB is running (e.g., via Docker) and then executing the Python script using `uv run`. ```bash # Start MongoDB (if using Docker) docker run -d -p 27017:27017 mongo # Run the example uv run python examples/mongodb_usage.py ``` -------------------------------- ### Install FastAPI OTP Authentication with Extras Source: https://github.com/gronnmann/fastapi-otp-authentication/blob/master/README.md Instructions for installing the base package and optional extras for SQLAlchemy or MongoDB support using 'uv' or 'pip'. It also includes commands to install necessary database drivers. ```bash # Install base package uv add fastapi-otp-authentication # or pip install if using pip # Install with SQLAlchemy support uv add "fastapi-otp-authentication[sqlalchemy] @ git+https://github.com/gronnmann/fastapi-otp-authentication.git" # Install with MongoDB support uv add "fastapi-otp-authentication[mongodb] @ git+https://github.com/gronnmann/fastapi-otp-authentication.git" # Install both (if needed) uv add "fastapi-otp-authentication[all] @ git+https://github.com/gronnmann/fastapi-otp-authentication.git" # Then install your database driver uv add asyncpg # PostgreSQL with SQLAlchemy uv add aiomysql # MySQL with SQLAlchemy uv add aiosqlite # SQLite with SQLAlchemy # MongoDB driver (motor) is included with [mongodb] extra ``` -------------------------------- ### Direct MongoDB Adapter Usage Example Source: https://context7.com/gronnmann/fastapi-otp-authentication/llms.txt Demonstrates direct usage of the MongoDBAdapter for user operations such as getting users by email or ID, creating new users, and updating/verifying OTP. This adapter interacts with a MongoDB database for user data persistence. ```python async def example_operations(): db = MongoDBAdapter(database, "users", "token_blacklist", User) # Get user by email user = await db.get_by_email("user@example.com") # Get user by ID (string ObjectId) user = await db.get_by_id("507f1f77bcf86cd799439011") # Create new user (returns Pydantic model) user = await db.create_user( email="new@example.com", username="newuser", full_name="New User" ) # All other operations same as SQLAlchemyAdapter await db.update_otp(user, "123456") await db.verify_user(user) ``` -------------------------------- ### SQLAlchemy Database Setup and Adapter Dependency Source: https://github.com/gronnmann/fastapi-otp-authentication/blob/master/README.md Configures an asynchronous SQLAlchemy engine and session maker, then defines dependencies for obtaining an async session and the SQLAlchemyAdapter. This prepares the database connection and adapter for use with the authentication system. ```python from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine from fastapi_otp_authentication import SQLAlchemyAdapter # Database setup engine = create_async_engine("sqlite+aiosqlite://./app.db") async_session_maker = async_sessionmaker(engine, expire_on_commit=False) async def get_async_session(): async with async_session_maker() as session: yield session async def get_otp_db(session: AsyncSession = Depends(get_async_session)): yield SQLAlchemyAdapter(session, User, Blacklist) ``` -------------------------------- ### FastAPI OTP Authentication with SQLAlchemy Source: https://context7.com/gronnmann/fastapi-otp-authentication/llms.txt A full FastAPI application example demonstrating OTP authentication using SQLAlchemy and SQLite. It includes database setup, user model definition, OTP configuration, and API endpoints for authentication and protected routes. Dependencies for current user and verified user are also shown. ```python import asyncio from datetime import timedelta from typing import Any, AsyncGenerator from fastapi import Depends, FastAPI, HTTPException from sqlalchemy import Integer, String from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column from fastapi_otp_authentication import ( BaseOTPUserTable, OTPAuthConfig, SQLAlchemyAdapter, TokenBlacklist, get_auth_router, get_current_user_dependency, get_verified_user_dependency, get_custom_claims_dependency, ) # Database setup DATABASE_URL = "sqlite+aiosqlite:///./app.db" engine = create_async_engine(DATABASE_URL, echo=True) async_session_maker = async_sessionmaker(engine, expire_on_commit=False) class Base(DeclarativeBase): pass class User(BaseOTPUserTable[int], Base): __tablename__ = "users" id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) username: Mapped[str] = mapped_column(String(50), unique=True, nullable=False) role: Mapped[str] = mapped_column(String(20), default="user", nullable=False) class Blacklist(TokenBlacklist, Base): pass async def get_async_session() -> AsyncGenerator[AsyncSession, None]: async with async_session_maker() as session: yield session async def get_otp_db(session: AsyncSession = Depends(get_async_session)): yield SQLAlchemyAdapter(session, User, Blacklist) class MyOTPConfig(OTPAuthConfig): secret_key = "your-super-secret-key-at-least-32-characters" developer_mode = True # Use False in production access_token_lifetime = timedelta(hours=1) refresh_token_lifetime = timedelta(days=7) otp_length = 6 otp_expiry = timedelta(minutes=10) max_otp_attempts = 5 async def send_otp(self, email: str, code: str) -> None: print(f"OTP for {email}: {code}") # Replace with email service def get_additional_claims(self, user: User) -> dict[str, Any]: return {"username": user.username, "role": user.role} app = FastAPI(title="OTP Auth API") config = MyOTPConfig() # Mount auth router auth_router = get_auth_router(get_otp_db, config) app.include_router(auth_router, prefix="/auth", tags=["auth"]) # Dependencies current_user = Depends(get_current_user_dependency(get_otp_db, config)) verified_user = Depends(get_verified_user_dependency(get_otp_db, config)) claims = Depends(get_custom_claims_dependency(config)) @app.on_event("startup") async def startup(): async with engine.begin() as conn: await conn.run_sync(Base.metadata.create_all) @app.get("/me") async def get_me(user: User = current_user): return {"id": user.id, "email": user.email, "username": user.username} @app.get("/admin") async def admin_only(user: User = verified_user, token_claims: dict = claims): if token_claims.get("role") != "admin": raise HTTPException(403, "Admin access required") return {"message": "Welcome admin", "user": user.username} if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=8000) ``` -------------------------------- ### MongoDB Setup and User/Token Models for FastAPI OTP Auth Source: https://context7.com/gronnmann/fastapi-otp-authentication/llms.txt This snippet demonstrates the setup for MongoDB integration within a FastAPI OTP authentication system. It includes initializing the MongoDB client, defining User and Blacklist models inheriting from provided base classes, and creating a database adapter function. The adapter `get_otp_db` is crucial for connecting the authentication logic to the MongoDB collections. ```python from motor.motor_asyncio import AsyncIOMotorClient, AsyncIOMotorDatabase from fastapi_otp.documents import BaseOTPUserDocument, TokenBlacklistDocument from fastapi_otp.adapters.mongo import MongoDBAdapter from pydantic import Field # MongoDB setup client: AsyncIOMotorClient = AsyncIOMotorClient("mongodb://localhost:27017") database: AsyncIOMotorDatabase = client["myapp"] class User(BaseOTPUserDocument): username: str = Field(..., max_length=50) role: str = Field(default="user", max_length=20) class Blacklist(TokenBlacklistDocument): pass async def get_otp_db() -> MongoDBAdapter[User]: return MongoDBAdapter( database=database, user_collection_name="users", blacklist_collection_name="token_blacklist", user_model_class=User, ) ``` -------------------------------- ### Request OTP Endpoint Example (curl) Source: https://context7.com/gronnmann/fastapi-otp-authentication/llms.txt Demonstrates how to request an OTP code using `curl`. This endpoint sends an OTP to the user's email and can automatically create a user if configured. It includes examples of successful responses and common error scenarios like user not found or rate limiting. ```bash # Request OTP for existing or new user curl -X POST "http://localhost:8000/auth/request-otp" \ -H "Content-Type: application/json" \ -d '{"email": "user@example.com"}' # Response (200 OK) { "message": "OTP code has been sent to your email" } # Response in developer mode { "message": "Developer mode: OTP code is 000000" } # Error responses: # 404 Not Found (if auto_create_user=False and user doesn't exist) { "detail": "No user found with email: user@example.com" } # 429 Too Many Requests (rate limited) { "detail": "Please wait 45 seconds before requesting a new OTP code." } ``` -------------------------------- ### FastAPI OTP Authentication with MongoDB Source: https://context7.com/gronnmann/fastapi-otp-authentication/llms.txt A FastAPI application example demonstrating OTP authentication using MongoDB. It sets up the necessary components for MongoDB integration, including database client, user document, and adapter configuration. This example focuses on the MongoDB-specific aspects of the authentication setup. ```python from datetime import timedelta from typing import Any, ClassVar from fastapi import Depends, FastAPI, HTTPException from motor.motor_asyncio import AsyncIOMotorClient, AsyncIOMotorDatabase from pydantic import Field from fastapi_otp_authentication import ( BaseOTPUserDocument, MongoDBAdapter, OTPAuthConfig, TokenBlacklistDocument, get_auth_router, get_current_user_dependency, get_verified_user_dependency, ) ``` -------------------------------- ### FastAPI Application Setup with OTP Authentication Router Source: https://context7.com/gronnmann/fastapi-otp-authentication/llms.txt This Python script initializes a FastAPI application and integrates the OTP authentication router. It configures the application with a title, instantiates the custom OTP configuration, and includes the authentication router under the `/auth` prefix. It also defines dependencies for obtaining the current and verified user, and sets up startup and shutdown events for database index creation and client closure. ```python from fastapi import FastAPI, Depends from fastapi_otp.dependencies import get_current_user_dependency, get_verified_user_dependency from fastapi_otp.routers import get_auth_router app = FastAPI(title="OTP Auth API (MongoDB)") config = MyOTPConfig() auth_router = get_auth_router(get_otp_db, config) app.include_router(auth_router, prefix="/auth", tags=["auth"]) current_user = Depends(get_current_user_dependency(get_otp_db, config)) verified_user = Depends(get_verified_user_dependency(get_otp_db, config)) @app.on_event("startup") async def startup(): # Create indexes await database["users"].create_index("email", unique=True) await database["token_blacklist"].create_index("jti", unique=True) await database["token_blacklist"].create_index("expires_at", expireAfterSeconds=0) @app.on_event("shutdown") async def shutdown(): client.close() @app.get("/me") async def get_me(user: User = current_user): return {"id": str(user.id), "email": str(user.email), "username": user.username} if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=8000) ``` -------------------------------- ### Integrate SQLAlchemy User Model with BaseOTPUserTable Source: https://context7.com/gronnmann/fastapi-otp-authentication/llms.txt Demonstrates how to create a SQLAlchemy user model that supports OTP authentication by inheriting from `BaseOTPUserTable`. This class provides all necessary fields for OTP functionality. The example also shows how to define a `TokenBlacklist` model for managing revoked tokens. ```python from sqlalchemy import Integer, String from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column from fastapi_otp_authentication import BaseOTPUserTable, TokenBlacklist class Base(DeclarativeBase): pass class User(BaseOTPUserTable[int], Base): """User model with OTP authentication support.""" __tablename__ = "users" # Primary key (generic type parameter defines ID type) id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) # Custom fields username: Mapped[str] = mapped_column(String(50), unique=True, nullable=False) full_name: Mapped[str | None] = mapped_column(String(100), nullable=True) role: Mapped[str] = mapped_column(String(20), default="user", nullable=False) # Inherited fields from BaseOTPUserTable: # - email: str (unique, indexed) # - otp_code: str | None # - otp_created_at: datetime | None # - otp_attempts: int (default 0) # - last_otp_request_at: datetime | None # - is_verified: bool (default False) class Blacklist(TokenBlacklist, Base): """Token blacklist table for logout/revocation.""" # Inherits: id, jti, token_type, blacklisted_at, expires_at pass ``` -------------------------------- ### Logout Endpoint Example (curl) Source: https://context7.com/gronnmann/fastapi-otp-authentication/llms.txt Illustrates how to log out a user by blacklisting their refresh token and clearing the associated cookie. The `curl` command sends the request with the cookie and also instructs `curl` to clear the cookie upon receiving a response, effectively logging the user out. ```bash # Logout (blacklist token and clear cookie) curl -X POST "http://localhost:8000/auth/logout" \ -b cookies.txt \ -c cookies.txt # Cookie will be cleared # Response (200 OK) { "message": "Successfully logged out" } ``` -------------------------------- ### User Authentication Dependency Example Source: https://context7.com/gronnmann/fastapi-otp-authentication/llms.txt Provides a Python snippet showing how to create a FastAPI dependency using `get_current_user_dependency`. This dependency is designed to validate an access token from the request and return the authenticated user object, enabling route protection. ```python from fastapi import Depends from fastapi_otp_authentication import get_current_user_dependency config = MyOTPConfig() # Example usage within a route (assuming 'current_user' is defined elsewhere) # @app.get("/protected-route") # async def protected_route(current_user: User = Depends(get_current_user_dependency(config))): # return {"message": f"Hello, {current_user.username}!"} ``` -------------------------------- ### Refresh Token Endpoint Example (curl) Source: https://context7.com/gronnmann/fastapi-otp-authentication/llms.txt Demonstrates how to refresh an access token using a refresh token stored in an HTTP-only cookie. This `curl` command sends the request with the cookie, and a new access token is returned if the refresh token is valid. It covers scenarios where the refresh token is missing or invalid. ```bash # Refresh access token (uses cookie) curl -X POST "http://localhost:8000/auth/refresh" \ -b cookies.txt # Send refresh token cookie # Response (200 OK) { "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "token_type": "bearer" } # Error responses: # 401 Unauthorized {"detail": "Refresh token not found in cookies"} {"detail": "Invalid token type"} {"detail": "Token has been revoked"} {"detail": "Invalid or expired token: ..."} # 404 Not Found {"detail": "User not found"} ``` -------------------------------- ### Verify OTP Endpoint Example (curl) Source: https://context7.com/gronnmann/fastapi-otp-authentication/llms.txt Shows how to verify an OTP code using `curl` to obtain JWT tokens. The access token is returned in the response, and the refresh token is set as an HTTP-only cookie. Handles successful verification and various error conditions like invalid codes or exceeding attempt limits. ```bash # Verify OTP code curl -X POST "http://localhost:8000/auth/verify-otp" \ -H "Content-Type: application/json" \ -d '{"email": "user@example.com", "code": "123456"}' \ -c cookies.txt # Save refresh token cookie # Response (200 OK) { "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxIiwidHlwZSI6ImFjY2VzcyIsImp0aSI6IjU1MGU4NDAwLWUyOWItNDFkNC1hNzE2LTQ0NjY1NDRlMDAwMCIsImlhdCI6MTcwOTEyMzQ1NiwiZXhwIjoxNzA5MTI3MDU2LCJ1c2VybmFtZSI6InRlc3R1c2VyIn0.abc123", "token_type": "bearer" } # Error responses: # 404 Not Found {"detail": "No user found with email: user@example.com"} # 401 Unauthorized (invalid/expired code) {"detail": "Invalid OTP code"} {"detail": "OTP code has expired"} {"detail": "No OTP code found. Please request a new one."} # 429 Too Many Requests (max attempts exceeded) {"detail": "Too many OTP attempts. Please request a new code."} ``` -------------------------------- ### Register OTP Authentication Router and Protect Routes (MongoDB) Source: https://github.com/gronnmann/fastapi-otp-authentication/blob/master/README.md Shows how to integrate the OTP authentication router into a FastAPI application and protect a specific route using the `current_user` dependency. This involves creating an instance of the configuration, getting the authentication router, including it in the app, and defining a protected endpoint. ```python from fastapi_otp_authentication import get_auth_router, get_current_user_dependency config = MyOTPConfig() # Assuming MyOTPConfig is defined auth_router = get_auth_router(get_otp_db, config) app.include_router(auth_router, prefix="/auth", tags=["auth"]) current_user = Depends(get_current_user_dependency(get_otp_db, config)) @app.get("/protected") async def protected_route(user: User = current_user): # Assuming User model is defined return {"user_id": str(user.id), "email": user.email} ``` -------------------------------- ### Run Test Suite (Bash) Source: https://github.com/gronnmann/fastapi-otp-authentication/blob/master/README.md Execute the project's test suite using `uv` and `pytest`. This command runs all tests located in the `tests/` directory with verbose output. ```bash uv run pytest tests/ -v ``` -------------------------------- ### Set Up MongoDB Adapter for OTP Authentication Source: https://github.com/gronnmann/fastapi-otp-authentication/blob/master/README.md Provides code for setting up the MongoDB adapter for fastapi-otp-authentication. It initializes an AsyncIOMotorClient, selects a database, and defines an asynchronous function `get_otp_db` that returns a MongoDBAdapter instance configured with user and blacklist collections, and the custom user model. ```python from motor.motor_asyncio import AsyncIOMotorClient from fastapi_otp_authentication import MongoDBAdapter # MongoDB setup client = AsyncIOMotorClient("mongodb://localhost:27017") database = client["myapp"] async def get_otp_db(): return MongoDBAdapter( database=database, user_collection_name="users", blacklist_collection_name="token_blacklist", user_model_class=User, # Assuming User model is defined ) ``` -------------------------------- ### Setting Up Authentication Router with FastAPI Source: https://context7.com/gronnmann/fastapi-otp-authentication/llms.txt Shows how to create and include a FastAPI authentication router using `get_auth_router`. This function generates endpoints for requesting OTP, verifying OTP, refreshing tokens, and logging out. It requires a database getter and configuration. ```python from fastapi import FastAPI from fastapi_otp_authentication import get_auth_router app = FastAPI(title="My API") config = MyOTPConfig() # Create and mount authentication router auth_router = get_auth_router(get_otp_db, config) app.include_router(auth_router, prefix="/auth", tags=["Authentication"]) # Endpoints created: # POST /auth/request-otp - Request OTP code # POST /auth/verify-otp - Verify OTP and get tokens # POST /auth/refresh - Refresh access token # POST /auth/logout - Logout and blacklist tokens ``` -------------------------------- ### Registering the Authentication Router in FastAPI Source: https://github.com/gronnmann/fastapi-otp-authentication/blob/master/README.md Initializes a FastAPI application, creates an instance of the custom OTP configuration, and includes the authentication router obtained from get_auth_router. This integrates the OTP authentication endpoints into the main FastAPI application. ```python from fastapi import FastAPI from fastapi_otp_authentication import get_auth_router app = FastAPI() config = MyOTPConfig() auth_router = get_auth_router(get_otp_db, config) app.include_router(auth_router, prefix="/auth", tags=["auth"]) ``` -------------------------------- ### Protected Routes Source: https://github.com/gronnmann/fastapi-otp-authentication/blob/master/README.md Demonstrates how to protect routes using dependencies provided by the library. ```APIDOC ## GET /protected ### Description An example protected route that requires a valid user. ### Method GET ### Endpoint /protected ### Parameters #### Query Parameters None #### Request Body None ### Response #### Success Response (200) - **user_id** (string) - The ID of the authenticated user. - **email** (string) - The email of the authenticated user. #### Response Example ```json { "user_id": "some-user-id", "email": "user@example.com" } ``` ## GET /verified-only ### Description This route is accessible only to users who have successfully verified their OTP. ### Method GET ### Endpoint /verified-only ### Parameters #### Query Parameters None #### Request Body None ### Response #### Success Response (200) - **message** (string) - A confirmation message indicating access is granted. #### Response Example ```json { "message": "Access granted to verified user" } ``` ## GET /check-claims ### Description This route demonstrates how to access custom claims associated with the authenticated user. ### Method GET ### Endpoint /check-claims ### Parameters #### Query Parameters None #### Request Body None ### Response #### Success Response (200) - **custom_claims** (dict) - A dictionary containing custom claims. #### Response Example ```json { "custom_claims": { "key": "value" } } ``` ``` -------------------------------- ### Configure OTP Authentication Settings Source: https://github.com/gronnmann/fastapi-otp-authentication/blob/master/README.md Illustrates how to configure OTP authentication by extending the OTPAuthConfig class. This includes setting secret keys, token lifetimes, OTP parameters (length, expiry, attempts), and defining custom logic for sending OTP codes and retrieving additional user claims. ```python from datetime import timedelta from fastapi_otp_authentication import OTPAuthConfig class MyOTPConfig(OTPAuthConfig): secret_key = "your-secret-key-generate-with-openssl-rand-hex-32" developer_mode = False access_token_lifetime = timedelta(hours=1) refresh_token_lifetime = timedelta(days=7) otp_length = 6 otp_expiry = timedelta(minutes=10) max_otp_attempts = 5 async def send_otp(self, email: str, code: str) -> None: print(f"OTP for {email}: {code}") def get_additional_claims(self, user: User) -> dict[str, Any]: # Assuming User is defined return {"username": user.username} ``` -------------------------------- ### Protect FastAPI Routes with OTP Authentication Dependencies Source: https://github.com/gronnmann/fastapi-otp-authentication/blob/master/README.md Demonstrates how to protect FastAPI routes using dependencies provided by fastapi-otp-authentication. These dependencies ensure that only authenticated and/or verified users can access specific endpoints. It requires a configured OTP database and authentication configuration. ```python from fastapi import Depends from fastapi_otp_authentication import ( get_current_user_dependency, get_verified_user_dependency, get_custom_claims_dependency, ) # Assuming get_otp_db, config, User, and app are defined elsewhere current_user = Depends(get_current_user_dependency(get_otp_db, config)) verified_user = Depends(get_verified_user_dependency(get_otp_db, config)) custom_claims = Depends(get_custom_claims_dependency(config)) @app.get("/protected") async def protected_route(user: User = current_user): return {"user_id": user.id, "email": user.email} @app.get("/verified-only") async def verified_only(user: User = verified_user): return {"message": "Access granted to verified user"} @app.get("/check-claims") async def check_claims(claims: dict = custom_claims): return {"custom_claims": claims} ``` -------------------------------- ### SQLAlchemy User Model and Blacklist Table Definition Source: https://github.com/gronnmann/fastapi-otp-authentication/blob/master/README.md Defines a SQLAlchemy User model inheriting from BaseOTPUserTable and a TokenBlacklist table, both using SQLAlchemy's declarative base. This sets up the database schema for user and token management. ```python from sqlalchemy import Integer, String from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column from fastapi_otp_authentication import BaseOTPUserTable from fastapi_otp_authentication import TokenBlacklist class Base(DeclarativeBase): pass class User(BaseOTPUserTable[int], Base): __tablename__ = "users" id: Mapped[int] = mapped_column(Integer, primary_key=True) username: Mapped[str] = mapped_column(String(50), unique=True) class Blacklist(TokenBlacklist, Base): pass ``` -------------------------------- ### SQLAlchemy Adapter for OTP Authentication (Python) Source: https://context7.com/gronnmann/fastapi-otp-authentication/llms.txt The SQLAlchemyAdapter facilitates OTP authentication operations with SQLAlchemy-compatible databases. It handles user retrieval, OTP management, and token blacklisting, providing a consistent interface for database interactions. ```python from fastapi import Depends from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine from fastapi_otp_authentication import SQLAlchemyAdapter # Database setup DATABASE_URL = "postgresql+asyncpg://user:pass@localhost/mydb" engine = create_async_engine(DATABASE_URL, echo=False) async_session_maker = async_sessionmaker(engine, expire_on_commit=False) async def create_tables() -> None: """Create database tables on startup.""" async with engine.begin() as conn: await conn.run_sync(Base.metadata.create_all) async def get_async_session(): """Dependency: Get database session.""" async with async_session_maker() as session: yield session async def get_otp_db(session: AsyncSession = Depends(get_async_session)): """Dependency: Get OTP database adapter.""" yield SQLAlchemyAdapter(session, User, Blacklist) # Direct adapter usage example async def example_operations(): async with async_session_maker() as session: db = SQLAlchemyAdapter(session, User, Blacklist) # Get user by email user = await db.get_by_email("user@example.com") # Get user by ID user = await db.get_by_id(123) # Create new user user = await db.create_user("new@example.com", username="newuser") # Update OTP (resets attempts, sets created_at) await db.update_otp(user, "123456") # Increment failed attempts await db.increment_otp_attempts(user) # Mark user verified and clear OTP await db.verify_user(user) # Token blacklist operations await db.add_to_blacklist( jti="unique-jwt-id", token_type="refresh", expires_at=datetime.now(UTC) + timedelta(days=7) ) is_revoked = await db.is_blacklisted("unique-jwt-id") removed_count = await db.cleanup_blacklist() # Remove expired tokens ``` -------------------------------- ### Generate Secure Secret Key for OTP Authentication Source: https://github.com/gronnmann/fastapi-otp-authentication/blob/master/README.md Provides the bash command to generate a cryptographically secure random key, which is essential for the security of the OTP authentication system. The library requires a secret key of at least 32 characters for production use. ```bash openssl rand -hex 32 ``` -------------------------------- ### Enable Developer Mode for Testing OTP Authentication Source: https://github.com/gronnmann/fastapi-otp-authentication/blob/master/README.md Demonstrates how to enable developer mode in the OTP authentication configuration for easier testing. In developer mode, OTP codes are simplified (e.g., '000000'), and secret key validation is relaxed. This mode should NEVER be used in production environments. ```python from fastapi_otp_authentication import OTPAuthConfig class MyOTPConfig(OTPAuthConfig): developer_mode = True secret_key = "any-key-allowed-in-dev-mode" ``` -------------------------------- ### Verified User Dependency for Sensitive Operations Source: https://context7.com/gronnmann/fastapi-otp-authentication/llms.txt Creates a dependency that ensures the user has completed OTP verification before accessing a route. It extends the standard user dependency by adding an explicit check for the user's verified status. This is crucial for operations that require a higher level of user assurance. ```python from fastapi import Depends, FastAPI, HTTPException from fastapi_otp_authentication import get_verified_user_dependency from pydantic import BaseModel # Mock definitions for demonstration purposes class User(BaseModel): id: int email: str username: str is_verified: bool class MyOTPConfig: pass def get_otp_db(): pass def get_verified_user_dependency(otp_db_func, config): # This is a placeholder for the actual dependency async def verified_user(user: User = Depends(get_current_user_dependency(otp_db_func, config))): if not user.is_verified: raise HTTPException(status_code=403, detail="User has not completed OTP verification") return user return verified_user def get_current_user_dependency(otp_db_func, config): # Mock dependency from previous snippet async def current_user(token: str = "dummy_token"): return User(id=1, email="user@example.com", username="testuser", is_verified=True) return current_user app = FastAPI() config = MyOTPConfig() # Create dependency for verified users only verified_user_dep = get_verified_user_dependency(get_otp_db, config) @app.get("/sensitive-data") async def get_sensitive_data(user: User = Depends(verified_user_dep)): """Route only accessible to verified users.""" return { "message": "Access granted", "user_id": user.id, "is_verified": user.is_verified, # Always True } @app.post("/change-email") async def change_email( new_email: str, user: User = Depends(verified_user_dep), ): """Sensitive operation requiring verified status.""" # Only verified users can change email return {"message": f"Email change initiated for {new_email}"} ``` ```bash # Access verified-only route curl -X GET "http://localhost:8000/sensitive-data" \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." # Response (200 OK) - if user is verified { "message": "Access granted", "user_id": 1, "is_verified": true } # Error response (403 Forbidden) - if user not verified {"detail": "User has not completed OTP verification"} ``` -------------------------------- ### Configure OTP Authentication with OTPAuthConfig Source: https://context7.com/gronnmann/fastapi-otp-authentication/llms.txt Defines the `OTPAuthConfig` abstract class for configuring OTP authentication settings. Users must extend this class and implement the `send_otp` method for delivering codes. It includes settings for secret keys, token lifetimes, OTP parameters, and user management, with options for developer mode and custom JWT claims. ```python from datetime import timedelta from typing import Any from fastapi_otp_authentication import OTPAuthConfig class MyOTPConfig(OTPAuthConfig): # Required: Secret key for JWT signing (min 32 chars in production) secret_key = "your-secret-key-generate-with-openssl-rand-hex-32" # Security settings developer_mode = False # Set True for testing (OTP becomes 000000) cookie_secure = True # Require HTTPS for cookies in production algorithm = "HS256" # JWT signing algorithm # Token lifetimes access_token_lifetime = timedelta(hours=1) refresh_token_lifetime = timedelta(days=7) # OTP settings otp_length = 6 # 4-8 digit codes supported otp_expiry = timedelta(minutes=10) # OTP validity period max_otp_attempts = 5 # Max verification attempts otp_rate_limit_seconds = 60 # Minimum seconds between requests # User management auto_create_user = True # Auto-create users on first OTP request async def send_otp(self, email: str, code: str) -> None: """Required: Implement OTP delivery (email, SMS, etc.)""" # Example: Send via email service await send_email( to=email, subject="Your Verification Code", body=f"Your OTP code is: {code}. Valid for 10 minutes." ) def get_additional_claims(self, user: Any) -> dict[str, Any]: """Optional: Add custom claims to JWT tokens""" return { "username": user.username, "role": getattr(user, "role", "user"), } ``` -------------------------------- ### Create MongoDB Indexes for OTP Authentication Collections Source: https://github.com/gronnmann/fastapi-otp-authentication/blob/master/README.md Details the creation of necessary indexes on MongoDB collections for optimal performance of the OTP authentication system. It includes creating a unique index on the 'email' field for the users collection, an index on 'jti' for the token blacklist, and a TTL index on 'expires_at' to automatically remove expired tokens. ```python @app.on_event("startup") # Assuming app is a FastAPI instance async def startup(): # Unique index on email await database["users"].create_index("email", unique=True) # Index on jti for blacklist lookups await database["token_blacklist"].create_index("jti", unique=True) # TTL index to auto-delete expired tokens await database["token_blacklist"].create_index( "expires_at", expireAfterSeconds=0 ) ``` -------------------------------- ### MongoDB Adapter for OTP Authentication (Python) Source: https://context7.com/gronnmann/fastapi-otp-authentication/llms.txt The MongoDBAdapter simplifies OTP authentication with MongoDB using the Motor async driver. It manages user documents, OTP operations, and token blacklisting, including automatic conversion of MongoDB ObjectIds. ```python from motor.motor_asyncio import AsyncIOMotorClient, AsyncIOMotorDatabase from fastapi_otp_authentication import MongoDBAdapter # MongoDB setup MONGODB_URL = "mongodb://localhost:27017" client: AsyncIOMotorClient = AsyncIOMotorClient(MONGODB_URL) database: AsyncIOMotorDatabase = client["myapp"] async def create_indexes() -> None: """Create indexes on startup for optimal performance.""" # Unique index on email for fast lookups await database["users"].create_index("email", unique=True) # Unique index on jti for blacklist await database["token_blacklist"].create_index("jti", unique=True) # TTL index to auto-delete expired blacklist entries await database["token_blacklist"].create_index( "expires_at", expireAfterSeconds=0 ) async def get_otp_db() -> MongoDBAdapter[User]: """Dependency: Get OTP database adapter.""" return MongoDBAdapter( database=database, user_collection_name="users", blacklist_collection_name="token_blacklist", user_model_class=User, ) ``` -------------------------------- ### Custom OTP Authentication Configuration (SQLAlchemy) Source: https://github.com/gronnmann/fastapi-otp-authentication/blob/master/README.md Extends the OTPAuthConfig abstract class to define custom security settings, token lifetimes, OTP parameters, and methods for sending OTPs and retrieving additional JWT claims. This configuration is essential for the authentication flow. ```python from datetime import timedelta from fastapi_otp_authentication import OTPAuthConfig class MyOTPConfig(OTPAuthConfig): # Security - REQUIRED secret_key = "your-secret-key-generate-with-openssl-rand-hex-32" # Optional: Developer mode for testing (default: False) developer_mode = False cookie_secure = True # Use secure cookies (https) in production # Token lifetimes access_token_lifetime = timedelta(hours=1) refresh_token_lifetime = timedelta(days=7) # OTP settings otp_length = 6 otp_expiry = timedelta(minutes=10) max_otp_attempts = 5 async def send_otp(self, email: str, code: str) -> None: """Implement your OTP delivery method.""" # Send via email, SMS, etc. print(f"OTP for {email}: {code}") def get_additional_claims(self, user: User) -> dict[str, Any]: """Add custom claims to JWT tokens.""" return {"username": user.username} ``` -------------------------------- ### Define User Model for OTP Authentication (MongoDB) Source: https://github.com/gronnmann/fastapi-otp-authentication/blob/master/README.md Shows how to define a custom user model inheriting from BaseOTPUserDocument for use with MongoDB. This allows for custom fields like username and full_name, in addition to the standard fields required by the authentication system. It also demonstrates defining a custom TokenBlacklistDocument. ```python from pydantic import Field from fastapi_otp_authentication import BaseOTPUserDocument, TokenBlacklistDocument class User(BaseOTPUserDocument): """User model with custom fields.""" username: str = Field(..., max_length=50) full_name: str | None = Field(None, max_length=100) # Blacklist uses default TokenBlacklistDocument class Blacklist(TokenBlacklistDocument): pass ``` -------------------------------- ### User Authentication API Source: https://context7.com/gronnmann/fastapi-otp-authentication/llms.txt This section details the authentication endpoints provided by the FastAPI OTP Authentication library, including user registration, login, and OTP verification. ```APIDOC ## POST /auth/register ### Description Registers a new user with the provided email and password. ### Method POST ### Endpoint /auth/register ### Parameters #### Request Body - **email** (string) - Required - User's email address. - **password** (string) - Required - User's password. ### Request Example ```json { "email": "user@example.com", "password": "securepassword123" } ``` ### Response #### Success Response (200) - **message** (string) - Indicates successful registration. #### Response Example ```json { "message": "User registered successfully" } ``` ## POST /auth/login ### Description Logs in a user using their email and password, returning access and refresh tokens. ### Method POST ### Endpoint /auth/login ### Parameters #### Request Body - **email** (string) - Required - User's email address. - **password** (string) - Required - User's password. ### Request Example ```json { "email": "user@example.com", "password": "securepassword123" } ``` ### Response #### Success Response (200) - **access_token** (string) - The JWT access token. - **token_type** (string) - The type of token (e.g., "bearer"). - **refresh_token** (string) - The JWT refresh token. #### Response Example ```json { "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "token_type": "bearer", "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." } ``` ## POST /auth/refresh-token ### Description Refreshes an expired access token using a valid refresh token. ### Method POST ### Endpoint /auth/refresh-token ### Parameters #### Request Body - **refresh_token** (string) - Required - The user's refresh token. ### Request Example ```json { "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." } ``` ### Response #### Success Response (200) - **access_token** (string) - The new JWT access token. - **token_type** (string) - The type of token (e.g., "bearer"). #### Response Example ```json { "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "token_type": "bearer" } ``` ## POST /auth/logout ### Description Logs out the current user by invalidating their access token. ### Method POST ### Endpoint /auth/logout ### Response #### Success Response (200) - **message** (string) - Indicates successful logout. #### Response Example ```json { "message": "Successfully logged out" } ``` ``` -------------------------------- ### Security Functions for OTP and JWT Utilities Source: https://context7.com/gronnmann/fastapi-otp-authentication/llms.txt Provides core security functions for generating One-Time Passwords (OTPs) and creating/decoding JWT tokens. These functions are intended for internal use but can be imported for custom authentication flows. They include utilities for OTP generation, access/refresh token creation, and token verification. ```python from datetime import timedelta, datetime, UTC from fastapi_otp_authentication.security import ( generate_otp, create_access_token, create_refresh_token, decode_token, verify_otp_code, ) # Generate cryptographically secure OTP code = generate_otp(length=6, developer_mode=False) # e.g., "847291" dev_code = generate_otp(length=6, developer_mode=True) # "000000" # Create access token with custom claims access_token = create_access_token( user_id=123, additional_claims={"username": "john", "role": "admin"}, secret_key="your-32-char-secret-key-here-xxx", algorithm="HS256", lifetime=timedelta(hours=1), ) # Create refresh token (no custom claims) refresh_token = create_refresh_token( user_id=123, secret_key="your-32-char-secret-key-here-xxx", algorithm="HS256", lifetime=timedelta(days=7), ) # Example of decoding and verifying (requires a valid token and secret) # try: # decoded = decode_token(access_token, "your-32-char-secret-key-here-xxx", algorithms=["HS256"]) # print(f"Decoded token: {decoded}") # except Exception as e: # print(f"Token decoding failed: {e}") # Example of verifying an OTP code (requires a stored OTP and user ID) # is_valid = verify_otp_code(user_id="user1", code="123456") # print(f"OTP verification result: {is_valid}") ``` -------------------------------- ### POST /auth/request-otp Source: https://context7.com/gronnmann/fastapi-otp-authentication/llms.txt This endpoint allows users to request an OTP code, which is sent to their email. If the `auto_create_user` setting is enabled and the user does not exist, a new user account will be created automatically. The endpoint is rate-limited to prevent misuse. ```APIDOC ## POST /auth/request-otp - Request OTP Endpoint Request an OTP code to be sent to the user's email. Creates user automatically if `auto_create_user` is enabled and user doesn't exist. Rate-limited to prevent abuse. ### Method POST ### Endpoint /auth/request-otp ### Parameters #### Request Body - **email** (string) - Required - The email address of the user. ### Request Example ```json { "email": "user@example.com" } ``` ### Response #### Success Response (200 OK) - **message** (string) - Indicates that the OTP code has been sent. #### Response Example (200 OK) ```json { "message": "OTP code has been sent to your email" } ``` #### Response Example (Developer Mode) ```json { "message": "Developer mode: OTP code is 000000" } ``` #### Error Responses - **404 Not Found** (if `auto_create_user` is false and user does not exist) ```json { "detail": "No user found with email: user@example.com" } ``` - **429 Too Many Requests** (rate limited) ```json { "detail": "Please wait 45 seconds before requesting a new OTP code." } ``` ``` -------------------------------- ### Verified User Endpoints Source: https://context7.com/gronnmann/fastapi-otp-authentication/llms.txt Routes that are exclusively accessible to users who have completed OTP verification. ```APIDOC ## GET /sensitive-data ### Description Provides access to sensitive data, but only for users who have completed OTP verification. ### Method GET ### Endpoint /sensitive-data ### Parameters #### Query Parameters None #### Request Body None ### Request Example ```bash curl -X GET "http://localhost:8000/sensitive-data" \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." ``` ### Response #### Success Response (200) - **message** (string) - A success message indicating access is granted. - **user_id** (integer) - The ID of the verified user. - **is_verified** (boolean) - Always true for verified users. #### Response Example ```json { "message": "Access granted", "user_id": 1, "is_verified": true } ``` #### Error Responses - **401 Unauthorized**: If the access token is missing, invalid, or expired. - **403 Forbidden**: If the user has not completed OTP verification. ``` ```APIDOC ## POST /change-email ### Description Allows a verified user to initiate an email change. This operation is restricted to users who have completed OTP verification. ### Method POST ### Endpoint /change-email ### Parameters #### Query Parameters None #### Request Body - **new_email** (string) - Required - The new email address to change to. ### Request Example ```json { "new_email": "new.email@example.com" } ``` ### Response #### Success Response (200) - **message** (string) - Confirmation message for the email change initiation. #### Response Example ```json { "message": "Email change initiated for new.email@example.com" } ``` #### Error Responses - **401 Unauthorized**: If the access token is missing, invalid, or expired. - **403 Forbidden**: If the user has not completed OTP verification. ```