A minimal, production-style authentication backend built with FastAPI.
It demonstrates modern authentication using JWT, secure password hashing, and protected API endpoints.
- User registration
- Secure password hashing (bcrypt)
- Login via OAuth2 Password flow
- JWT access tokens (HS256 + expiration)
- Protected endpoints via dependency injection
- SQLite persistence (easy to replace)
- Automated tests with pytest
- FastAPI
- SQLAlchemy
- SQLite
- passlib + bcrypt
- python-jose (JWT)
- pytest + httpx
app/
├─ api/
│ ├─ routes/
│ │ ├─ auth.py # authentication endpoints (register, login)
│ │ └─ users.py # protected user endpoints
│ └─ deps.py # shared dependencies (JWT auth, current user)
├─ core/
│ ├─ config.py # application settings (JWT secret, algorithm)
│ └─ security.py # password hashing & JWT helpers
├─ db/
│ └─ database.py # database engine, sessions, Base
├─ models/
│ └─ user.py # SQLAlchemy user model
├─ schemas/
│ ├─ user.py # Pydantic user schemas
│ └─ token.py # JWT response schema
└─ main.py # FastAPI application entry point
tests/
├─ conftest.py # test database & dependency overrides
├─ test_auth.py # registration & login tests
└─ test_users.py # protected endpoint tests
python3 -m venv .venv
source .venv/bin/activatepip install -r requirements.txtuvicorn app.main:app --reloadOnce the server is running, open the Swagger UI:
- API Docs: http://127.0.0.1:8000/docs
Creates a new user account with a securely hashed password.
curl -X POST http://127.0.0.1:8000/auth/register \
-H "Content-Type: application/json" \
-d '{"email":"user@example.com","password":"Secret1234"}'Successful response:
{
"id": 1,
"email": "user@example.com",
"is_active": true
}Authenticates a user and returns a JWT access token.
Uses OAuth2 Password Flow with form data.
curl -X POST http://127.0.0.1:8000/auth/login \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "username=user@example.com&password=Secret1234"Response:
{
"access_token": "<JWT>",
"token_type": "bearer"
}Returns the currently authenticated user.
Requires a valid JWT access token.
curl -X GET http://127.0.0.1:8000/users/me \
-H "Authorization: Bearer <JWT>"Response:
{
"id": 1,
"email": "user@example.com",
"is_active": true
}The JWT secret can be configured via environment variable:
export SECRET_KEY="change-this-in-production"If not set, a default development key is used.
For production deployments, always provide a strong, private secret.
All tests run against an isolated SQLite test database.
pytest- Passwords are never stored in plaintext
bcryptis used to protect against brute-force attacks- JWT tokens include an expiration (
exp) claim - Authentication is stateless (no server-side sessions)
For production usage:
- Always use HTTPS
- Use a strong and private
SECRET_KEY - Consider refresh tokens and token rotation
- Apply rate limiting on authentication endpoints
This project is intended as:
- A learning project for backend authentication
- A portfolio-ready FastAPI service
- A clean foundation for extending into a full application