# JWT Authentication Testing Guide ## Local Testing (Release Mode) ### Prerequisites - .NET 10 SDK - PostgreSQL SSH tunnel - curl or Postman ### Step 1: Start SSH Tunnel ```powershell ssh -L 5432:127.0.0.1:5432 kjh2064@178.104.200.7 ``` Keep this terminal open. ### Step 2: Start Backend (Release Mode) ```powershell cd D:\JobRoomz\KArtSell.Aegis # Set test JWT key (32 bytes = 256 bits) $env:JWT_KEY = "test-key-32-bytes-min-for-hs256!!" # Set PostgreSQL connection $env:KARTSELL_POSTGRES = "Host=127.0.0.1;Port=5432;Database=kartselldb;Username=kartsell;Password=kartsell4321@!" # Run Release mode dotnet run -c Release --project src/KArtSell.Host # Expected output: # Now listening on: http://0.0.0.0:5002 ``` Wait for "Application started" message. ### Step 3: Start Frontend Dev Server ```powershell cd D:\JobRoomz\KArtSell.Aegis\frontend pnpm dev # Expected output: # VITE v... ready in ... ms # ➜ Local: http://localhost:5174/ ``` ### Step 4: Test Login Flow #### Option A: Browser (Recommended) 1. Open http://localhost:5174 2. Should redirect to `/login` (no auth token) 3. Enter credentials: - Username: `testuser` - Password: `testpass` 4. Click "Sign In" 5. Should receive JWT token and redirect to `/home` 6. Check browser DevTools > Application > localStorage - `kartsell_auth_token`: Contains JWT token - `kartsell_expires_at`: Unix timestamp (current time + 1 hour) #### Option B: curl (API Testing) **1. Login Request** ```bash curl -X POST http://localhost:5002/api/auth/login \ -H "Content-Type: application/json" \ -d '{"username":"testuser","password":"testpass","role":"Admin"}' ``` **Expected Response:** ```json { "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "expiresIn": 3600, "tokenType": "Bearer" } ``` **2. Extract Token** ```bash # Copy accessToken value TOKEN="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." ``` **3. Use Token in Protected Endpoint** ```bash curl http://localhost:5002/api/identities \ -H "Authorization: Bearer $TOKEN" ``` **Expected:** Success (200 OK) or relevant business response **4. Test Expired/Invalid Token** ```bash # Invalid token curl http://localhost:5002/api/identities \ -H "Authorization: Bearer invalid.token.here" # Expected: 401 Unauthorized ``` ## Test Scenarios ### Scenario 1: Successful Login ✅ User provides correct credentials ✅ Backend returns JWT token ✅ Frontend stores token in localStorage ✅ Subsequent requests include Authorization header ✅ User can access protected resources ### Scenario 2: Invalid Credentials ❌ User provides wrong password ✅ Backend returns 401 Unauthorized ✅ Frontend shows error message ✅ No token stored ✅ User remains on login page ### Scenario 3: Token Expiration ✅ Token is valid initially ⏳ Wait for token expiration (or manually adjust `kartsell_expires_at`) ✅ Frontend detects expiration ✅ Protected endpoint returns 401 ✅ Frontend automatically logs out ✅ User redirected to login ### Scenario 4: API Interceptor ✅ User logs in and receives token ✅ Make request via fetch API ✅ setupAuthInterceptor adds Authorization header ✅ Backend receives and validates token ✅ Request succeeds with 200 OK ### Scenario 5: Multiple Tabs/Windows ✅ Login in Tab 1 ✅ Token stored in localStorage ✅ Open Tab 2 to same app ✅ Tab 2 automatically has token (from localStorage) ✅ Both tabs can make authenticated requests ## Debugging ### Check Backend JWT Configuration ```bash # Add this to Program.cs temporarily for debugging Console.WriteLine($"JWT Key: {config["Jwt:Key"]}"); Console.WriteLine($"JWT Issuer: {config["Jwt:Issuer"]}"); Console.WriteLine($"JWT Audience: {config["Jwt:Audience"]}"); ``` ### Check Frontend Token ```javascript // Open browser console localStorage.getItem('kartsell_auth_token') localStorage.getItem('kartsell_expires_at') new Date(parseInt(localStorage.getItem('kartsell_expires_at'))) ``` ### Enable Debug Logging **Backend:** ```json { "Serilog": { "MinimumLevel": "Debug" } } ``` **Frontend:** ```typescript // In useAuthApi.ts console.log('Auth state:', authState.value) console.log('Token valid:', getToken()) ``` ### Network Inspector 1. Open browser DevTools > Network tab 2. Click "Sign In" 3. Look for `POST /api/auth/login` 4. Check response has `accessToken` 5. Make subsequent API request 6. Check request headers include `Authorization: Bearer ...` ## Common Issues & Solutions ### Issue: 401 Unauthorized on Protected Endpoints **Possible Causes:** 1. Token not included in Authorization header - Check setupAuthInterceptor in main.ts - Verify localStorage token exists 2. Token expired - Check `kartsell_expires_at` in localStorage - Set `Jwt:ExpirationMinutes` to larger value for testing 3. JWT key mismatch - Backend JWT key must match production key - Ensure `JWT_KEY` environment variable is set 4. Token signature invalid - Check JWT signature on jwt.io - Verify HMAC SHA256 algorithm **Solution:** ```bash # 1. Check token value localStorage.getItem('kartsell_auth_token') # 2. Decode token (jwt.io) # Copy token to https://jwt.io # 3. Verify claims # Should have: NameIdentifier, Name, Role, auth_mode # 4. Check expiration new Date(parseInt(localStorage.getItem('kartsell_expires_at'))) ``` ### Issue: Redirect Loop **Possible Causes:** 1. Token always invalid 2. setupAuthInterceptor not working 3. Router guard issue **Solution:** ```bash # Check LocalStorage localStorage.clear() # Restart frontend # Re-login # Check Network tab for actual requests ``` ### Issue: CORS Errors **Backend and Frontend on Different Ports** - Backend: http://localhost:5002 - Frontend: http://localhost:5174 **Solution:** Add CORS middleware to backend: ```csharp // In Program.cs app.UseCors(builder => builder .AllowAnyOrigin() .AllowAnyMethod() .AllowAnyHeader()); ``` ## Performance Testing ### Load Test JWT Validation ```powershell # Generate 100 requests with valid token $token = "eyJ..." # from login response 1..100 | ForEach-Object { curl http://localhost:5002/api/identities ` -H "Authorization: Bearer $token" ` -w "%{http_code}\n" } ``` Expected: All 200 or 401 (consistent) ### Token Generation Performance ```bash time (for i in {1..10}; do curl -X POST http://localhost:5002/api/auth/login \ -H "Content-Type: application/json" \ -d '{"username":"test","password":"test"}' \ > /dev/null done) ``` Expected: < 500ms per request ## Cleanup After testing: ```powershell # Kill backend Ctrl+C in backend terminal # Kill frontend Ctrl+C in frontend terminal # Clear test data localStorage.clear() # Close SSH tunnel Ctrl+C in SSH terminal ``` ## Next Steps If all tests pass: 1. ✅ JWT authentication working in Release mode 2. → Proceed to **Phase 2: Production Deployment Preparation** 3. → Implement database credential validation 4. → Configure production JWT key