Complete authentication system with Email/Password, Google OAuth, GitHub OAuth, and JWT token management.
fastapi-auth/
├── app/
│ ├── main.py # FastAPI app entry point
│ ├── core/
│ │ ├── config.py # Settings (env vars)
│ │ ├── database.py # SQLAlchemy engine + session
│ │ └── security.py # JWT utilities (access + refresh tokens)
│ ├── models/
│ │ └── user.py # SQLAlchemy models: User, RefreshToken
│ ├── schemas/
│ │ └── user.py # Pydantic request/response schemas
│ ├── routers/
│ │ ├── auth.py # Login, signup, refresh, logout
│ │ ├── oauth.py # Google & GitHub OAuth
│ │ └── users.py # User CRUD + admin
│ └── dependencies/
│ └── auth.py # FastAPI dependencies (get_current_user)
├── alembic/ # Database migrations
├── pgadmin/
│ └── servers.json # pgAdmin auto-connection config
├── docker-compose.yml # PostgreSQL + pgAdmin4 + App
├── Dockerfile
├── requirements.txt
└── .env.example
cp .env.example .env
# Edit .env with your valuesdocker-compose up postgres pgadmin -d- pgAdmin4 → http://localhost:5050 (login:
admin@admin.com/admin) - PostgreSQL → localhost:5432
pip install -r requirements.txtuvicorn app.main:app --reload- API Docs → http://localhost:8000/docs
- ReDoc → http://localhost:8000/redoc
This is the most important concept in the project:
┌─────────────────────────────────────────────────────────────┐
│ ACCESS TOKEN │
├─────────────────────────────────────────────────────────────┤
│ Lifetime: 15 minutes (short-lived) │
│ Purpose: Authenticate API requests │
│ Storage: JS Memory / Session storage │
│ Header: Authorization: Bearer <token> │
│ DB stored: NO (stateless, just verify signature) │
│ Risk if stolen: LOW (expires in 15 min) │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ REFRESH TOKEN │
├─────────────────────────────────────────────────────────────┤
│ Lifetime: 7 days (long-lived) │
│ Purpose: Get a NEW access token when it expires │
│ Storage: HttpOnly Cookie (XSS-safe) │
│ Endpoint: POST /auth/refresh │
│ DB stored: YES (for revocation on logout) │
│ Risk if stolen: HIGH (can get new access tokens) │
└─────────────────────────────────────────────────────────────┘
User Login
│
▼
POST /auth/login
│
├─── access_token (15 min) ──► Store in JS memory
└─── refresh_token (7 days) ──► Store in HttpOnly Cookie
API Request
│
▼
Authorization: Bearer <access_token>
│
├─── Valid ──► 200 OK ✅
└─── Expired ──► 401 ❌
│
▼
POST /auth/refresh
{ refresh_token: "..." }
│
├─── Valid ──► new access_token ✅
└─── Expired/Revoked ──► 401 → Login again
Logout
│
▼
POST /auth/logout
{ refresh_token: "..." }
│
└─── Refresh token marked is_revoked=True in DB
(Access token expires naturally in ≤15 min)
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| POST | /auth/signup |
None | Register new user |
| POST | /auth/login |
None | Login with email/password |
| POST | /auth/refresh |
Refresh token | Get new access token |
| POST | /auth/logout |
Access + Refresh | Logout (revoke refresh token) |
| POST | /auth/logout-all |
Access token | Logout all devices |
| GET | /auth/me |
Access token | Current user profile |
| PUT | /auth/change-password |
Access token | Change password |
| GET | /auth/token-info |
None | Explains access vs refresh |
| GET | /auth/active-sessions |
Access token | List active sessions |
| Method | Endpoint | Description |
|---|---|---|
| GET | /auth/google/login |
Redirect to Google OAuth |
| GET | /auth/google/callback |
Google OAuth callback |
| GET | /auth/github/login |
Redirect to GitHub OAuth |
| GET | /auth/github/callback |
GitHub OAuth callback |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | /users/me |
Access token | Get profile |
| DELETE | /users/me |
Access token | Delete account |
| GET | /users/ |
Superuser | List all users |
| PUT | /users/{id}/activate |
Superuser | Activate user |
- Go to Google Cloud Console
- Create a project → Enable "Google+ API"
- OAuth 2.0 Credentials → Authorized redirect URI:
http://localhost:8000/auth/google/callback - Copy Client ID & Secret to
.env
- Go to GitHub Developer Settings
- New OAuth App → Callback URL:
http://localhost:8000/auth/github/callback - Copy Client ID & Secret to
.env
pgAdmin4 starts automatically with Docker Compose:
docker-compose up pgadmin -d- Open http://localhost:5050
- Login:
admin@admin.com/admin - The FastAPI Auth DB server is pre-configured!
- Navigate: Servers → FastAPI Auth DB → Databases → fastapi_auth → Schemas → Tables
users- All users (local + OAuth)refresh_tokens- Active and revoked refresh tokens
Run everything in Docker:
docker-compose up -dServices:
- FastAPI App → http://localhost:8000
- PostgreSQL → localhost:5432
- pgAdmin4 → http://localhost:5050
# 1. Signup
curl -X POST http://localhost:8000/auth/signup \
-H "Content-Type: application/json" \
-d '{"email":"user@example.com","username":"testuser","password":"Password123","full_name":"Test User"}'
# 2. Login
curl -X POST http://localhost:8000/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"user@example.com","password":"Password123"}'
# 3. Use access token
curl http://localhost:8000/auth/me \
-H "Authorization: Bearer <access_token>"
# 4. Refresh access token (when expired)
curl -X POST http://localhost:8000/auth/refresh \
-H "Content-Type: application/json" \
-d '{"refresh_token":"<refresh_token>"}'
# 5. Logout
curl -X POST http://localhost:8000/auth/logout \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{"refresh_token":"<refresh_token>"}'