# 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": "", "email": "", "type": "access", "exp": "" } ``` **Q: What claims are in the refresh token?** ```json { "sub": "", "type": "refresh", "exp": "" } ``` **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 ` 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 |