Configure Cross-Origin Resource Sharing (CORS) to allow browser-based clients to interact with your Nexus server.

[server.cors] allow_origins = ["https://app.example.com", "http://localhost:3000"] allow_methods = ["GET", "POST"] allow_headers = ["authorization", "content-type", "x-request-id"] allow_credentials = true max_age = 3600 allow_private_network = false expose_headers = ["x-request-id", "x-trace-id"]
  • allow_origins: List of allowed origins, a single origin, or "*" for all origins
  • allow_methods: HTTP methods to allow (can be array or "*")
  • allow_headers: Headers that clients can send (can be array or "*")
  • allow_credentials: Whether to allow credentials in CORS requests (default: false)
  • max_age: How long browsers can cache CORS preflight responses (in seconds)
  • allow_private_network: Allow requests from private networks (default: false)
  • expose_headers: Headers to expose to the client (can be array or "*")

For allow_origins, allow_methods, allow_headers, and expose_headers, you can use:

  • An array of specific values: ["value1", "value2"]
  • A single value: "value"
  • Wildcard to allow all: "*"

Allow all origins during development:

[server.cors] allow_origins = "*" allow_methods = "*" allow_headers = "*" allow_credentials = false

Restrict to specific domains in production:

[server.cors] allow_origins = [ "https://app.yourdomain.com", "https://admin.yourdomain.com" ] allow_methods = ["GET", "POST", "OPTIONS"] allow_headers = ["authorization", "content-type"] allow_credentials = true max_age = 86400 # 24 hours expose_headers = ["x-request-id"]

Configuration for a typical SPA:

[server.cors] allow_origins = "https://spa.example.com" allow_methods = ["GET", "POST", "PUT", "DELETE", "OPTIONS"] allow_headers = ["authorization", "content-type", "x-csrf-token"] allow_credentials = true max_age = 3600 expose_headers = ["x-total-count", "x-page-number"]

Allow local development servers:

[server.cors] allow_origins = [ "http://localhost:3000", # Web dev server "http://localhost:8081", # React Native "http://10.0.2.2:8000", # Android emulator "capacitor://localhost", # Capacitor "ionic://localhost" # Ionic ] allow_methods = ["GET", "POST", "OPTIONS"] allow_headers = ["authorization", "content-type"] allow_credentials = true allow_private_network = true # For local network access

When allow_credentials = true:

  • Cannot use "*" for origins - must specify exact origins
  • Browser will reject responses if wildcard is used with credentials
  • Each origin must be explicitly listed

The allow_private_network option controls Chrome's Private Network Access:

[server.cors] allow_private_network = true # Allow requests from private IPs

Use this when:

  • Serving requests to local network clients
  • Development with local IP addresses
  • Internal corporate networks

Browsers send preflight OPTIONS requests for:

  • Custom headers
  • Non-simple methods (PUT, DELETE, etc.)
  • Requests with credentials

Ensure OPTIONS is included in allow_methods:

[server.cors] allow_methods = ["GET", "POST", "PUT", "DELETE", "OPTIONS"]

Symptoms: OPTIONS request fails with CORS error

Solution:

[server.cors] allow_methods = ["OPTIONS", "GET", "POST"] # Include OPTIONS allow_headers = ["authorization", "content-type"] # Include all headers used

Symptoms: Cookies/auth headers not sent

Solution:

[server.cors] allow_origins = ["https://specific-origin.com"] # Specific origin, not "*" allow_credentials = true

Symptoms: Can't read response headers in JavaScript

Solution:

[server.cors] expose_headers = ["x-custom-header", "x-another-header"]

Symptoms: Old CORS settings persist

Solution:

[server.cors] max_age = 0 # Disable preflight caching during debugging
fetch('http://localhost:8000/llm/v1/chat/completions', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer token' }, credentials: 'include', // Send cookies if allow_credentials = true body: JSON.stringify({ model: 'openai/gpt-4', messages: [{ role: 'user', content: 'Hello' }] }) });
import axios from 'axios'; const client = axios.create({ baseURL: 'http://localhost:8000', withCredentials: true, // If allow_credentials = true headers: { 'Content-Type': 'application/json' } });
  1. Be Specific in Production: Never use "*" for origins in production
  2. Minimize Exposed Headers: Only expose necessary headers
  3. Use HTTPS: Always use HTTPS origins in production
  4. Validate Origins: Keep origin list up-to-date
  5. Monitor CORS Errors: Log and monitor CORS failures
  6. Test Thoroughly: Test with actual browsers, not just tools
  7. Document Origins: Maintain documentation of allowed origins
© Grafbase, Inc.