A simple authentication API built with FastAPI, SQLAlchemy, and PostgreSQL, providing endpoints for user registration and login.
Note: The original assignment requested Flask; this implementation uses FastAPI instead, while still fulfilling the same API contract and database requirements.
fastapi-auth-example
├── migrations # Alembic database migrations
│ ├── env.py
│ ├── script.py.mako
│ └── versions
│ └── 7dfc9f79011c_initial_migration.py
├── src
│ └── app
│ ├── __init__.py
│ ├── core # Application configuration & utilities
│ │ ├── app.py # FastAPI app instance + router loading
│ │ ├── config.py # Environment variables & settings
│ │ ├── database.py # Async SQLAlchemy engine & session setup
│ │ ├── dependencies.py # Common FastAPI dependencies
│ │ └── security.py # Auth helpers: hashing, JWT, OAuth cookie
│ ├── models # SQLAlchemy ORM models
│ │ └── user.py
│ ├── routers # API route handlers
│ │ └── auth.py # /auth routes (register, login, me, logout)
│ └── schemas # Pydantic schemas for validation & responses
│ ├── auth.py
│ └── user.py
├── tests # Automated test suite (pytest)
│ ├── __init__.py
│ ├── conftest.py # Test DB override + client fixture
│ └── test_auth.py # Authentication endpoint tests
├── alembic.ini # Alembic configuration
├── compose.yml # Local Postgres + app + migrations via Docker
├── Dockerfile # Application container build with uv
├── pyproject.toml # Dependencies & entrypoint
├── README.md # Documentation
└── uv.lock # Locked dependencies
| Endpoint | Method | Description |
|---|---|---|
/auth/register |
POST | Register a new user |
/auth/login |
POST | Authenticate an existing user |
Passwords are securely hashed before storage.
On successful login, an HTTP-only token cookie is set with the JWT-encoded credentials.
| Endpoint | Method | Description |
|---|---|---|
/auth/me |
GET | Retrieve details of currently logged in user |
/auth/logout |
GET | Logout currently logged in user |
- Docker installed and running
- UV (Python package manager)
- Create environment config:
cp .env.example .env- Build & start the app:
docker compose up --buildThis will automatically:
- Start PostgreSQL
- Apply Alembic migrations
- Launch the FastAPI backend
To stop everything:
docker compose down -v
-vclears the database volume for a fresh start
- Sync dependencies and activate virtual environment:
uv sync
source .venv/bin/activate- Create environment config:
cp .env.example .env- Start PostgreSQL database via Docker:
docker compose up -d database- Apply alembic database migrations:
alembic upgrade head- Start the FastAPI server:
uv run startThe API will be available at http://localhost:8000 with an interactive Swagger UI at http://localhost:8000/docs
I would recomend playing around with the /docs page, but here are some quick curl commands to get started!
curl -X POST http://localhost:8000/auth/register \
-H "Content-Type: application/json" \
-d '{
"name": "My name",
"email": "user@example.com",
"password": "test123"
}'
curl -X POST http://localhost:8000/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"password": "test123"
}' \
-iLogin and store cookies:
curl -X POST http://localhost:8000/auth/login \
-H "Content-Type: application/json" \
-d '{"email": "user@example.com", "password": "test123"}' \
-c cookies.txtCall /auth/me sending stored cookie::
curl http://localhost:8000/auth/me \
-b cookies.txtThis project includes a full test suite using pytest, FastAPI’s TestClient, and an in-memory SQLite test database.
It also included a github action workflow to automatically run these tests on push to main branch.
Install test dependencies:
uv sync --group devRun the tests:
uv run pytestTests automatically:
- Spin up an isolated in-memory SQLite database (no external DB required)
- Override the app’s database dependency
- Exercise all authentication endpoints:
/auth/register/auth/login/auth/me/auth/logout
- FastAPI - API framework
- SQLAlchemy - ORM
- Alembic - database migrations
- PostgreSQL - persistent database
- Docker Compose - running infrastructure services
- Argon2 - password hashing