Skip to content

Database Configuration

This guide covers SQLAlchemy setup with aiosqlite for persistent API key storage.

Installation

Install the SQLAlchemy extra:

pip install fastapi-api-key[sqlalchemy]

Example

This is the canonical example from examples/example_sql.py:

Always set a pepper

The default pepper is a placeholder. Set SECRET_PEPPER (or pass it explicitly to the hashers) in every environment.

import asyncio
import os
from pathlib import Path

from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine

from fastapi_api_key import ApiKeyService
from fastapi_api_key.hasher.argon2 import Argon2ApiKeyHasher
from fastapi_api_key.repositories.sql import SqlAlchemyApiKeyRepository

# Set env var to override default pepper
# Using a strong, unique pepper is crucial for security
# Default pepper is insecure and should not be used in production
pepper = os.getenv("SECRET_PEPPER")
hasher = Argon2ApiKeyHasher(pepper=pepper)

path = Path(__file__).parent / "db.sqlite3"
database_url = os.environ.get("DATABASE_URL", f"sqlite+aiosqlite:///{path}")

async_engine = create_async_engine(database_url, future=True)
async_session_maker = async_sessionmaker(
    async_engine,
    class_=AsyncSession,
    expire_on_commit=False,
)


async def main():
    async with async_session_maker() as session:
        repo = SqlAlchemyApiKeyRepository(session)

        # Don't need to create Base and ApiKeyModel, the repository does it for you
        await repo.ensure_table(async_engine=async_engine)

        service = ApiKeyService(repo=repo, hasher=hasher)

        # Entity have updated id after creation
        entity, secret = await service.create(name="persistent")
        print("Stored key", entity.id_, "secret", secret)

        # Don't forget to commit the session to persist the key
        # You can also use a transaction `async with session.begin():`
        await session.commit()


asyncio.run(main())