A production-style JWT authentication server with register, login, token refresh, role-based access control, per-session logout, and brute-force protection.
Client → Nginx (port 80) → FastAPI/Gunicorn (port 8000) → PostgreSQL
| Service | Technology | Role |
|---|---|---|
nginx |
Nginx 1.25 | Reverse proxy, rate limiting on /auth/* |
api |
FastAPI + Gunicorn | Auth logic, JWT, bcrypt, RBAC |
db |
PostgreSQL 16 | Users + refresh token store |
# Windows
tar -xzf authserver.tar.gz
cd authserver\authserver
docker compose up --build# Mac / Linux
tar -xzf authserver.tar.gz && cd authserver/authserver
docker compose up --buildVerify: curl http://localhost/health → {"status":"ok","version":"1.0.0"}
Interactive docs: http://localhost/docs
curl -X POST http://localhost/auth/register \
-H "Content-Type: application/json" \
-d '{"username":"alice","email":"alice@example.com","password":"secret123"}'Response:
{
"access_token": "eyJ...",
"refresh_token": "eyJ...",
"token_type": "bearer",
"expires_in": 1800
}curl -X POST http://localhost/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"alice","password":"secret123"}'export TOKEN="<access_token from login>"
curl http://localhost/users/me \
-H "Authorization: Bearer $TOKEN"curl -X POST http://localhost/auth/refresh \
-H "Content-Type: application/json" \
-d '{"refresh_token":"<your refresh token>"}'curl -X POST http://localhost/auth/logout \
-H "Content-Type: application/json" \
-d '{"refresh_token":"<your refresh token>"}'curl -X POST http://localhost/auth/logout-all \
-H "Authorization: Bearer $TOKEN"| Role | Can access |
|---|---|
user |
/auth/*, /users/me |
admin |
everything above + GET /users, GET /users/{id}, PATCH /users/{id}/role |
docker compose exec db psql -U authuser -d authserver \
-c "UPDATE users SET role='admin' WHERE username='alice';"| Feature | Implementation |
|---|---|
| Password hashing | bcrypt via passlib (work factor 12) |
| Access token | HS256 JWT, 30-minute TTL |
| Refresh token | HS256 JWT, 7-day TTL, stored as SHA-256 hash in DB |
| Token reuse detection | Revoked token re-use revokes entire token family |
| User enumeration defence | Constant-time check even for unknown usernames |
| Rate limiting (app) | slowapi — 10 logins/min, 5 registrations/min per IP |
| Rate limiting (Nginx) | limit_req_zone — 20r/m burst 5 on /auth/* |
| Security headers | X-Frame-Options, X-Content-Type-Options, XSS |
| Variable | Default | Description |
|---|---|---|
SECRET_KEY |
change-me |
JWT signing key — change this! |
ACCESS_TOKEN_EXPIRE_MINUTES |
30 |
Access token TTL |
REFRESH_TOKEN_EXPIRE_DAYS |
7 |
Refresh token TTL |
POSTGRES_USER |
authuser |
DB username |
POSTGRES_PASSWORD |
authpass |
DB password |
LOG_LEVEL |
INFO |
Python log level |
docker compose up db -d
pip install -r requirements.txt
set POSTGRES_HOST=localhost # Windows
export POSTGRES_HOST=localhost # Mac/Linux
uvicorn api.main:app --reload --port 8000docker compose logs -f api
docker compose exec db psql -U authuser -d authserver
# SELECT id, username, email, role, is_active FROM users;
# SELECT id, user_id, is_revoked, expires_at FROM refresh_tokens;
docker compose down -v # destroy all data