diff --git a/.env.example b/.env.example index 75adb4e..98878b4 100644 --- a/.env.example +++ b/.env.example @@ -56,7 +56,6 @@ APP_URL=http://localhost:3000 # Public-facing app URL (emails, links) # ─── Ingest API ────────────────────────────────────────────────────────────── # PORT=3001 # Ingest server port (default: 3001) -# CORS_ORIGINS=http://localhost:3000,http://localhost:3002 # Comma-separated (default: *) # ─── Yavio Cloud Only (never set by self-hosters) ──────────────────────────── # YAVIO_CLOUD=true diff --git a/.specs/07_error-catalog.md b/.specs/07_error-catalog.md index 19af8b1..ff88260 100644 --- a/.specs/07_error-catalog.md +++ b/.specs/07_error-catalog.md @@ -572,7 +572,6 @@ Errors related to platform infrastructure, deployment, health checks, and cross- | Code | HTTP | Message | Description | Recovery | |------|------|---------|-------------|----------| -| `YAVIO-7400` | 403 | CORS origin not allowed | Widget request `Origin` header is not in the allowed origins list. | Add the origin to `YAVIO_CORS_ORIGINS` or project settings in the dashboard. | | `YAVIO-7401` | 405 | CORS method not allowed | Request method is not in `Access-Control-Allow-Methods`. | Only `POST` and `OPTIONS` are allowed on ingestion endpoints. | ### Catch-All (7999) diff --git a/.specs/sdk/react-widget-sdk.md b/.specs/sdk/react-widget-sdk.md index d595215..40b772d 100644 --- a/.specs/sdk/react-widget-sdk.md +++ b/.specs/sdk/react-widget-sdk.md @@ -152,7 +152,7 @@ The ingestion API must accept cross-origin requests from widget iframes. CORS he | `https://claude.ai` | Claude | | `https://cursor.sh` | Cursor | -Additional origins can be configured per project via the dashboard settings or the `YAVIO_CORS_ORIGINS` environment variable (comma-separated list). This allows developers to add custom domains for self-hosted or development environments while keeping the default restrictive. +The ingestion API reflects all origins (`origin: true`) with credentials support, so no additional CORS configuration is needed. Auth is enforced via API keys and JWTs, not origin restrictions. ## 4.5 Security Model diff --git a/docker-compose.yml b/docker-compose.yml index 3feda8d..6410814 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -72,7 +72,6 @@ services: API_KEY_HASH_SECRET: ${API_KEY_HASH_SECRET} JWT_SECRET: ${JWT_SECRET} PORT: "3001" - CORS_ORIGINS: ${CORS_ORIGINS:-http://localhost:3000} ports: - "${INGEST_PORT:-3001}:3001" networks: diff --git a/packages/docs/content/docs/04-self-hosting/02-configuration.mdx b/packages/docs/content/docs/04-self-hosting/02-configuration.mdx index 3620d04..ea88e1a 100644 --- a/packages/docs/content/docs/04-self-hosting/02-configuration.mdx +++ b/packages/docs/content/docs/04-self-hosting/02-configuration.mdx @@ -84,8 +84,6 @@ DASHBOARD_PORT=8080 docker compose up -d | --- | --- | --- | | `NEXTAUTH_URL` | `http://localhost:3000` | Auth callback URL (set to your public domain in production) | | `APP_URL` | `http://localhost:3000` | Public-facing URL used in emails and links | -| `CORS_ORIGINS` | `http://localhost:3000` | Allowed CORS origins for the ingestion API (comma-separated) | - ## OAuth Providers (Optional) Enable social login by setting provider credentials. Omit to disable. diff --git a/packages/ingest/src/__tests__/api/events-cors.test.ts b/packages/ingest/src/__tests__/api/events-cors.test.ts index 86685f3..fcd51f2 100644 --- a/packages/ingest/src/__tests__/api/events-cors.test.ts +++ b/packages/ingest/src/__tests__/api/events-cors.test.ts @@ -51,6 +51,7 @@ describe("CORS", () => { }); expect(r.statusCode).toBe(204); expect(r.headers["access-control-allow-origin"]).toBe("https://example.com"); + expect(r.headers["access-control-allow-credentials"]).toBe("true"); expect(r.headers["access-control-allow-methods"]).toContain("POST"); expect(r.headers["access-control-allow-headers"]).toContain("Authorization"); }); diff --git a/packages/ingest/src/config.ts b/packages/ingest/src/config.ts index e066c68..0d489dc 100644 --- a/packages/ingest/src/config.ts +++ b/packages/ingest/src/config.ts @@ -6,7 +6,6 @@ export interface AppConfig { clickhouseUrl: string; apiKeyHashSecret: string; jwtSecret: string; - corsOrigins: string[]; } export function loadConfig(): AppConfig { @@ -49,9 +48,5 @@ export function loadConfig(): AppConfig { }); } - const corsOrigins = process.env.CORS_ORIGINS - ? process.env.CORS_ORIGINS.split(",").map((o) => o.trim()) - : ["*"]; - - return { port, databaseUrl, clickhouseUrl, apiKeyHashSecret, jwtSecret, corsOrigins }; + return { port, databaseUrl, clickhouseUrl, apiKeyHashSecret, jwtSecret }; } diff --git a/packages/ingest/src/index.ts b/packages/ingest/src/index.ts index ff3a300..21a3acd 100644 --- a/packages/ingest/src/index.ts +++ b/packages/ingest/src/index.ts @@ -37,8 +37,6 @@ export interface CreateAppOptions { toolRegistryWriter?: BatchWriter; /** Pre-built rate limiter (for testing). */ rateLimiter?: RateLimiter; - /** Allowed CORS origins. Defaults to `["*"]` (all origins). */ - corsOrigins?: string[]; /** Enable Fastify request logging. Defaults to true. */ logger?: boolean; } @@ -58,13 +56,10 @@ export async function createApp(options: CreateAppOptions): Promise { - const origins = app.corsOrigins; await app.register(cors, { - origin: origins.includes("*") ? true : origins, + origin: true, + credentials: true, methods: ["GET", "POST", "OPTIONS"], allowedHeaders: ["Content-Type", "Authorization"], }); diff --git a/packages/ingest/src/server.ts b/packages/ingest/src/server.ts index 6b098c9..8594259 100644 --- a/packages/ingest/src/server.ts +++ b/packages/ingest/src/server.ts @@ -48,7 +48,6 @@ async function main() { clickhouseUrl: config.clickhouseUrl, apiKeyHashSecret: config.apiKeyHashSecret, jwtSecret: config.jwtSecret, - corsOrigins: config.corsOrigins, clickhouse, batchWriter, toolRegistryWriter, diff --git a/packages/ingest/src/types.ts b/packages/ingest/src/types.ts index e7d1166..582e475 100644 --- a/packages/ingest/src/types.ts +++ b/packages/ingest/src/types.ts @@ -20,7 +20,6 @@ declare module "fastify" { clickhouse: ClickHouseClient; apiKeyResolver: ApiKeyResolver; jwtSecret: string; - corsOrigins: string[]; batchWriter?: BatchWriter; toolRegistryWriter?: BatchWriter; rateLimiter?: RateLimiter; diff --git a/turbo.json b/turbo.json index 2de76fc..56595cf 100644 --- a/turbo.json +++ b/turbo.json @@ -19,7 +19,6 @@ "SMTP_PASSWORD", "SMTP_FROM", "PORT", - "CORS_ORIGINS", "NODE_ENV" ], "tasks": {