re-uploading work
This commit is contained in:
186
work-summary/sessions/2026-01-20-cors-fix-final.md
Normal file
186
work-summary/sessions/2026-01-20-cors-fix-final.md
Normal file
@@ -0,0 +1,186 @@
|
||||
# Work Summary: CORS Error Resolution
|
||||
|
||||
**Date:** 2026-01-20
|
||||
**Status:** RESOLVED
|
||||
|
||||
## Problem
|
||||
|
||||
User experiencing CORS error when attempting to login from the web UI at `http://localhost:3000`. The error was preventing requests from reaching the API server at `http://localhost:8080`.
|
||||
|
||||
## Root Cause
|
||||
|
||||
The issue had multiple contributing factors:
|
||||
|
||||
1. **Environment variable override**: `web/.env.development` had `VITE_API_BASE_URL=http://localhost:8080` set, which overrode the code configuration
|
||||
2. **Generated API client hardcoded values**: `web/src/api/core/OpenAPI.ts` (auto-generated file) had hardcoded `BASE: 'http://localhost:8080'`
|
||||
3. **Alternative API client**: `web/src/lib/api-client.ts` also had hardcoded base URL
|
||||
4. **Login form UX issue**: Submit button was `type="button"` instead of `type="submit"`, preventing Enter key submission
|
||||
|
||||
## Solution
|
||||
|
||||
### 1. Fixed Environment Configuration
|
||||
|
||||
**File:** `web/.env.development`
|
||||
|
||||
Changed from:
|
||||
```
|
||||
VITE_API_BASE_URL=http://localhost:8080
|
||||
```
|
||||
|
||||
To:
|
||||
```
|
||||
# Use empty/omit VITE_API_BASE_URL to use Vite proxy (recommended for local dev)
|
||||
# VITE_API_BASE_URL=
|
||||
```
|
||||
|
||||
This ensures the Vite proxy is used for local development, avoiding CORS entirely.
|
||||
|
||||
### 2. Fixed Generated OpenAPI Client
|
||||
|
||||
**File:** `web/src/api/core/OpenAPI.ts`
|
||||
|
||||
Changed:
|
||||
```typescript
|
||||
export const OpenAPI: OpenAPIConfig = {
|
||||
BASE: "http://localhost:8080", // ❌ Wrong
|
||||
WITH_CREDENTIALS: false, // ❌ Wrong
|
||||
```
|
||||
|
||||
To:
|
||||
```typescript
|
||||
export const OpenAPI: OpenAPIConfig = {
|
||||
BASE: "", // ✅ Correct - uses proxy
|
||||
WITH_CREDENTIALS: true, // ✅ Correct - sends credentials
|
||||
```
|
||||
|
||||
**Note:** This is a generated file, so it will be overwritten when running `npm run generate:api`. The fix in `api-config.ts` (which runs after) ensures correct values are set at runtime.
|
||||
|
||||
### 3. Fixed Manual API Client
|
||||
|
||||
**File:** `web/src/lib/api-client.ts`
|
||||
|
||||
Changed:
|
||||
```typescript
|
||||
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || 'http://localhost:8080';
|
||||
```
|
||||
|
||||
To:
|
||||
```typescript
|
||||
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || "";
|
||||
```
|
||||
|
||||
Also fixed the refresh token endpoint to use relative URL when BASE_URL is empty.
|
||||
|
||||
### 4. Fixed Login Form UX
|
||||
|
||||
**File:** `web/src/pages/auth/LoginPage.tsx`
|
||||
|
||||
Changed:
|
||||
```typescript
|
||||
<button
|
||||
type="button" // ❌ Wrong - doesn't submit on Enter
|
||||
onClick={handleSubmit}
|
||||
```
|
||||
|
||||
To:
|
||||
```typescript
|
||||
<button
|
||||
type="submit" // ✅ Correct - submits on Enter
|
||||
```
|
||||
|
||||
Also simplified `handleSubmit` to only accept `React.FormEvent` instead of `FormEvent | MouseEvent`.
|
||||
|
||||
### 5. Updated Documentation
|
||||
|
||||
**File:** `web/.env.example`
|
||||
|
||||
Added comprehensive comments explaining:
|
||||
- Recommended configuration for local development (use proxy)
|
||||
- How to configure for direct API access
|
||||
- Production deployment configuration
|
||||
|
||||
## How It Works Now
|
||||
|
||||
### Development Request Flow
|
||||
|
||||
```
|
||||
Browser → http://localhost:3000 (Vite Dev Server)
|
||||
↓ (via proxy)
|
||||
http://localhost:8080 (API Server)
|
||||
```
|
||||
|
||||
**Key points:**
|
||||
- Browser only talks to `localhost:3000` (same origin)
|
||||
- Vite proxy forwards `/api/*` and `/auth/*` to backend
|
||||
- No CORS headers needed because requests are same-origin
|
||||
- `WITH_CREDENTIALS: true` ensures cookies/auth headers are sent
|
||||
|
||||
### Configuration Precedence
|
||||
|
||||
1. **Runtime configuration** (`api-config.ts`) sets `OpenAPI.BASE` at startup
|
||||
2. **Environment variable** `VITE_API_BASE_URL` is checked first
|
||||
3. **Default fallback** is `""` (empty string = relative URLs = proxy)
|
||||
|
||||
## Files Modified
|
||||
|
||||
- `web/.env.development` - Removed hardcoded API URL
|
||||
- `web/.env.example` - Updated with better documentation
|
||||
- `web/src/api/core/OpenAPI.ts` - Fixed generated defaults
|
||||
- `web/src/lib/api-client.ts` - Fixed manual axios client
|
||||
- `web/src/pages/auth/LoginPage.tsx` - Fixed form submission
|
||||
- `web/src/lib/api-config.ts` - Already had debug logging (no changes needed)
|
||||
|
||||
## Testing
|
||||
|
||||
Verified the fix works:
|
||||
```bash
|
||||
# Proxy test - returns 401 (proxy working, just wrong credentials)
|
||||
curl -X POST http://localhost:3000/auth/login \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"login":"admin","password":"admin"}'
|
||||
|
||||
# Response shows proxy is working (no CORS error)
|
||||
HTTP/1.1 401 Unauthorized
|
||||
access-control-allow-credentials: true
|
||||
```
|
||||
|
||||
## User Instructions
|
||||
|
||||
1. **Hard refresh browser** (`Ctrl+Shift+R` or `Cmd+Shift+R`)
|
||||
2. **Clear browser cache and localStorage** if needed
|
||||
3. **Try logging in** - CORS error should be gone
|
||||
4. **Enter key now works** - can press Enter to submit login form
|
||||
|
||||
## Known Issues
|
||||
|
||||
### Password Authentication (Separate Issue)
|
||||
|
||||
The CORS issue is resolved, but there's a separate authentication issue:
|
||||
- User accounts exist in database with Argon2id password hashes
|
||||
- Login attempts return 401 "Invalid login or password"
|
||||
- This appears to be a password verification issue in the backend
|
||||
- Needs separate investigation
|
||||
|
||||
**Temporary workaround:** User needs to reset password or create new test user with known hash.
|
||||
|
||||
## Prevention
|
||||
|
||||
To prevent this issue in the future:
|
||||
|
||||
1. **Don't commit `.env.development` with hardcoded URLs** - keep it in `.gitignore`
|
||||
2. **Regenerating API client** - After running `npm run generate:api`, verify `OpenAPI.ts` settings
|
||||
3. **Document proxy pattern** - Make it clear that proxy is the recommended approach
|
||||
4. **CI/CD check** - Could add a check to ensure `.env.development` doesn't have `VITE_API_BASE_URL` set
|
||||
|
||||
## Architecture Notes
|
||||
|
||||
The proxy-based approach is:
|
||||
- ✅ **Recommended for development** - no CORS configuration needed
|
||||
- ✅ **Production-ready pattern** - same pattern used with nginx/caddy reverse proxy
|
||||
- ✅ **Simpler** - one less thing to configure
|
||||
- ✅ **More secure** - API server doesn't need to expose CORS to browser origins
|
||||
|
||||
Only use direct API access (`VITE_API_BASE_URL` set) when:
|
||||
- Testing API independently
|
||||
- Connecting to remote API
|
||||
- Production deployment without reverse proxy (not recommended)
|
||||
Reference in New Issue
Block a user