Files
Nexus-Guard-Suite/.sisyphus/plans/nxg-fix-cors.md
T
2026-05-21 14:18:18 +07:00

3.4 KiB

Plan: Fix CORS Configuration

Scope: Trivial — 3 files, ~20 lines Goal: Ensure server-core CORS properly accepts requests from frontend origins, configurable via CORS_ALLOWED_ORIGINS env var, documented in .env.example.


Context

Current CORS config in main.go:114-130:

  • Uses CORS_ALLOWED_ORIGINS env var (defaults to *)
  • Has BOTH AllowOrigins AND AllowOriginFunc — redundant
  • strings.Contains(corsOrigins, origin) is weak (substring match: "example.com" matches "notexample.com")
  • AllowCredentials: true is needed for JWT Authorization header
  • CORS_ALLOWED_ORIGINS is NOT documented in any .env.example file
  • SHARE_LINK_TTL (from Phase 5.0) also missing from .env.example

Task 1: Fix CORS config in main.go

File: apps/server-core/main.go lines 114-130

Replace the current CORS block with:

// CORS Configuration
corsOrigins := os.Getenv("CORS_ALLOWED_ORIGINS")
if corsOrigins == "" {
    corsOrigins = "*"
}

corsConfig := cors.Config{
    AllowMethods:     []string{"GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"},
    AllowHeaders:     []string{"Origin", "Content-Length", "Content-Type", "Authorization", "X-Admin-Key", "X-Device-Token"},
    ExposeHeaders:    []string{"Content-Length"},
    AllowCredentials: true,
}

if corsOrigins == "*" {
    // Wildcard: allow all origins but use AllowOriginFunc so the response
    // header echoes the actual origin (required when AllowCredentials=true).
    corsConfig.AllowOriginFunc = func(origin string) bool {
        return true
    }
} else {
    // Explicit list: split by comma, trim spaces, exact match only.
    origins := strings.Split(corsOrigins, ",")
    for i := range origins {
        origins[i] = strings.TrimSpace(origins[i])
    }
    corsConfig.AllowOrigins = origins
}

r.Use(cors.New(corsConfig))

Key changes:

  1. Remove simultaneous AllowOrigins + AllowOriginFunc (pick one based on * vs explicit)
  2. When *: use AllowOriginFunc returning true → gin-contrib/cors echoes the requesting origin (compatible with AllowCredentials: true)
  3. When explicit: use AllowOrigins with trimmed values, exact match (no more strings.Contains substring bug)

Verify: go build ./... passes


Task 2: Add CORS_ALLOWED_ORIGINS to root .env.example

File: .env.example

Add after VITE_API_BASE_URL line (section 5):

# 7. CORS Configuration
# Comma-separated list of allowed origins for the API.
# Use '*' to allow all origins (NOT recommended for production).
# Example: https://dash.yourdomain.com,https://admin.yourdomain.com
CORS_ALLOWED_ORIGINS=http://localhost:5173

# 8. Share Link Configuration
# TTL for peer config share links (Go duration format)
SHARE_LINK_TTL=24h

Task 3: Add CORS_ALLOWED_ORIGINS to server-core .env.example

File: apps/server-core/.env.example

Add at the end:

# CORS
# Comma-separated allowed origins. '*' = allow all (not recommended for production)
CORS_ALLOWED_ORIGINS=http://localhost:5173

# Share Link TTL (Go duration format)
SHARE_LINK_TTL=24h

Verify: all .env.example files contain CORS_ALLOWED_ORIGINS


Final Verification Wave

  • go build ./... passes in apps/server-core/
  • CORS_ALLOWED_ORIGINS present in root .env.example
  • CORS_ALLOWED_ORIGINS present in apps/server-core/.env.example
  • No other files reference CORS_ALLOWED_ORIGINS that need updating