Spaces:
Running
Running
| # Auth-System-SMTP β Summary of Important Questions & Concepts | |
| --- | |
| ## 1. Project Overview | |
| **Q: What is this project?** | |
| A full-stack authentication system with email verification and password reset using SMTP. Built with **FastAPI** (backend) + **React** (frontend). | |
| **Q: What is the tech stack?** | |
| | Layer | Technology | | |
| |-------|-----------| | |
| | Backend | FastAPI, SQLAlchemy, SQLite, bcrypt, JWT (python-jose) | | |
| | Frontend | React 18, Vite, Axios, React Router v6 | | |
| | Email | Python `smtplib` (STARTTLS on port 587) | | |
| | Auth | Dual JWT tokens (access + refresh), bcrypt hashing, OTP verification | | |
| --- | |
| ## 2. Authentication Flow | |
| **Q: What happens during registration?** | |
| 1. User submits `username`, `email`, `password` | |
| 2. Backend validates password strength (β₯8 chars, 1 letter, 1 digit) | |
| 3. Password is hashed with bcrypt | |
| 4. A 6-digit OTP is generated and stored in `verification_code` | |
| 5. OTP is sent via email (SMTP or console fallback) | |
| 6. User is redirected to `/verify-email` | |
| **Q: How does email verification work?** | |
| 1. User enters email + 6-digit OTP | |
| 2. Backend matches OTP against `verification_code` column | |
| 3. On success: `is_verified = True`, `verification_code = None` | |
| 4. User can now log in | |
| **Q: What happens during login?** | |
| 1. User submits `username` + `password` (OAuth2 form body) | |
| 2. Backend validates credentials with `bcrypt.checkpw()` | |
| 3. Checks `is_active` and `is_verified` flags | |
| 4. Issues two JWT tokens: | |
| - **Access token**: 30-minute expiry, type `"access"` | |
| - **Refresh token**: 7-day expiry, type `"refresh"` | |
| 5. Frontend stores both in `sessionStorage` | |
| **Q: How does token refresh work?** | |
| 1. Axios interceptor detects a 401 response | |
| 2. Sends refresh token to `/auth/refresh` | |
| 3. Backend validates refresh token (not revoked, valid type, user active) | |
| 4. **Revokes old refresh token** (adds to `revoked_tokens` table) | |
| 5. Issues new access + refresh token pair (token rotation) | |
| 6. Original request is retried with new token | |
| **Q: How does logout work?** | |
| 1. Frontend sends refresh token to `/auth/logout` | |
| 2. Backend inserts both tokens into `revoked_tokens` table | |
| 3. Frontend clears `sessionStorage` and resets user state | |
| --- | |
| ## 3. Password Reset Flow | |
| **Q: How does forgot password work?** | |
| - **Step 1**: User enters email β backend generates 6-digit OTP β stores in `reset_code` β sends via email | |
| - **Step 2**: User enters email + code + new password β backend validates OTP β hashes new password β clears `reset_code` | |
| --- | |
| ## 4. JWT Token Structure | |
| **Q: What claims are in the access token?** | |
| ```json | |
| { | |
| "sub": "<user_id>", | |
| "email": "<email>", | |
| "type": "access", | |
| "exp": "<datetime>" | |
| } | |
| ``` | |
| **Q: What claims are in the refresh token?** | |
| ```json | |
| { | |
| "sub": "<user_id>", | |
| "type": "refresh", | |
| "exp": "<datetime>" | |
| } | |
| ``` | |
| **Q: Why use two token types?** | |
| - Access token: Short-lived, used for API requests | |
| - Refresh token: Long-lived, used only to get new access tokens | |
| - Separation limits exposure if a token is compromised | |
| --- | |
| ## 5. Database Schema | |
| **Q: What tables exist?** | |
| ### `users` Table | |
| | Column | Type | Purpose | | |
| |--------|------|---------| | |
| | `id` | Integer (PK) | User ID | | |
| | `username` | String (UNIQUE) | Login username | | |
| | `email` | String (UNIQUE) | User email | | |
| | `password` | String | bcrypt hashed password | | |
| | `is_active` | Boolean | Account enabled/disabled | | |
| | `role` | String | `"user"` or `"admin"` | | |
| | `created_at` | DateTime | Registration timestamp | | |
| | `is_verified` | Boolean | Email verified flag | | |
| | `verification_code` | String (nullable) | Active registration OTP | | |
| | `reset_code` | String (nullable) | Active password reset OTP | | |
| ### `revoked_tokens` Table | |
| | Column | Type | Purpose | | |
| |--------|------|---------| | |
| | `id` | Integer (PK) | Record ID | | |
| | `token` | String (UNIQUE) | Revoked JWT string | | |
| | `revoked_at` | DateTime | When it was revoked | | |
| | `expires_at` | DateTime | Original token expiry | | |
| --- | |
| ## 6. API Endpoints | |
| **Q: What are all the endpoints?** | |
| ### Auth Routes (`/auth`) | |
| | Method | Endpoint | Description | | |
| |--------|----------|-------------| | |
| | POST | `/auth/register` | Register new user | | |
| | POST | `/auth/verify-email` | Verify email with OTP | | |
| | POST | `/auth/login` | Login, returns JWT tokens | | |
| | POST | `/auth/forgot-password` | Request password reset OTP | | |
| | POST | `/auth/reset-password` | Reset password with OTP | | |
| | POST | `/auth/refresh` | Refresh access token | | |
| | POST | `/auth/logout` | Revoke tokens | | |
| ### User Routes | |
| | Method | Endpoint | Description | | |
| |--------|----------|-------------| | |
| | GET | `/me` | Get current user profile | | |
| | PUT | `/me` | Update profile | | |
| | DELETE | `/me` | Delete own account | | |
| | GET | `/admin/users` | List all users (admin only) | | |
| --- | |
| ## 7. Security Concepts | |
| **Q: How are passwords stored?** | |
| - Hashed with **bcrypt** using `bcrypt.gensalt()` + `bcrypt.hashpw()` | |
| - Verified with `bcrypt.checkpw()` (constant-time comparison) | |
| **Q: What is token revocation?** | |
| - Tokens are inserted into `revoked_tokens` table | |
| - Every authenticated request checks this table | |
| - If token is found β 401 Unauthorized | |
| **Q: What is token rotation?** | |
| - On each refresh, the old refresh token is revoked | |
| - A new access + refresh token pair is issued | |
| - Prevents long-lived refresh token abuse | |
| **Q: How is rate limiting implemented?** | |
| - Custom HTTP middleware in FastAPI | |
| - Max 60 requests per 60-second window per client IP | |
| - Returns HTTP 429 when exceeded | |
| **Q: How is CORS configured?** | |
| - Allows only `http://localhost:5173` and `http://localhost:3000` | |
| - Allows credentials, all methods, all headers | |
| **Q: What is the SMTP fallback mechanism?** | |
| - If SMTP credentials are empty/missing β prints OTP to console | |
| - If SMTP sending fails β falls back to console printing | |
| - Allows development without a real mail server | |
| --- | |
| ## 8. Frontend Architecture | |
| **Q: How does the frontend manage auth state?** | |
| - `AuthContext` (React Context) holds `user` state | |
| - On mount, checks `sessionStorage` for `access_token` | |
| - Calls `GET /me` to validate and hydrate user state | |
| - If validation fails β clears session | |
| **Q: How does the axios interceptor work?** | |
| - **Request interceptor**: Attaches `Authorization: Bearer <token>` from `sessionStorage` | |
| - **Response interceptor**: On 401 β attempts refresh β retries request β on failure redirects to `/login` | |
| **Q: What is the ProtectedRoute component?** | |
| - Wraps routes that require authentication | |
| - Checks `user` from AuthContext | |
| - Redirects to `/login` if not authenticated | |
| - Shows loading spinner while checking | |
| --- | |
| ## 9. Environment Variables | |
| | Variable | Default | Purpose | | |
| |----------|---------|---------| | |
| | `SECRET_KEY` | `super_secret_dev_key_change_me_123456789` | JWT signing key | | |
| | `ALGORITHM` | `HS256` | JWT algorithm | | |
| | `ACCESS_TOKEN_EXPIRE_MINUTES` | `30` | Access token TTL | | |
| | `REFRESH_TOKEN_EXPIRE_DAYS` | `7` | Refresh token TTL | | |
| | `DATABASE_URL` | `sqlite:///./users.db` | Database connection | | |
| | `SMTP_SERVER` | `""` | SMTP host (empty = simulation) | | |
| | `SMTP_PORT` | `587` | SMTP port | | |
| | `SMTP_USER` | `""` | SMTP login (empty = simulation) | | |
| | `SMTP_PASSWORD` | `""` | SMTP password (empty = simulation) | | |
| --- | |
| ## 10. Important Security Notes & Weaknesses | |
| **Q: What security concerns exist?** | |
| 1. `.env` contains real Gmail credentials β must not be committed to version control | |
| 2. `SECRET_KEY` is a weak dev key β must be changed in production | |
| 3. OTP generated with `random.choices` (non-cryptographic PRNG) β should use `secrets` module | |
| 4. `forgot_password` endpoint may expose whether an email exists (different error responses) | |
| 5. No per-account brute-force protection β only global rate limiter | |
| 6. No `.gitignore` file β secrets could be accidentally committed | |
| **Q: What should be improved for production?** | |
| 1. Use a production database (PostgreSQL, MySQL) instead of SQLite | |
| 2. Add `.gitignore` to exclude `.env`, `users.db`, `__pycache__`, `node_modules` | |
| 3. Use `secrets` module for OTP generation | |
| 4. Implement account lockout after failed login attempts | |
| 5. Add email rate limiting (prevent OTP spam) | |
| 6. Use asymmetric JWT signing (RS256) for microservice architectures | |
| 7. Add HTTPS enforcement | |
| 8. Implement CSRF protection | |
| 9. Add comprehensive logging and monitoring | |
| --- | |
| ## 11. Key Files Reference | |
| | File | Purpose | | |
| |------|---------| | |
| | `backend/main.py` | FastAPI app entry, CORS, rate limiting, middleware | | |
| | `backend/auth.py` | Password hashing, JWT creation, SMTP email sending | | |
| | `backend/models.py` | SQLAlchemy ORM models (User, RevokedToken) | | |
| | `backend/schemas.py` | Pydantic request/response schemas | | |
| | `backend/config.py` | Centralized config from `.env` | | |
| | `backend/database.py` | SQLAlchemy engine, session, Base | | |
| | `backend/routes/auth_routes.py` | Auth endpoints | | |
| | `backend/routes/user_routes.py` | User profile + admin endpoints | | |
| | `frontend/src/context/AuthContext.jsx` | Auth state management | | |
| | `frontend/src/api/axios.js` | Axios instance with interceptors | | |
| | `frontend/src/components/ProtectedRoute.jsx` | Route guard | | |
| | `frontend/src/pages/Login.jsx` | Login form | | |
| | `frontend/src/pages/Register.jsx` | Registration form | | |
| | `frontend/src/pages/VerifyEmail.jsx` | OTP verification form | | |
| | `frontend/src/pages/Dashboard.jsx` | User dashboard + admin panel | | |