feat: dynamic per-site CORS for public banner endpoints
Some checks failed
CI / API Lint (push) Has been cancelled
CI / Detect changes (push) Has been cancelled
CI / API Tests (push) Has been cancelled
CI / Scanner Lint (push) Has been cancelled
CI / Scanner Tests (push) Has been cancelled
CI / Banner Lint & Typecheck (push) Has been cancelled
CI / Banner Tests (push) Has been cancelled
CI / Banner Build (push) Has been cancelled
CI / Admin UI Typecheck (push) Has been cancelled
CI / Admin UI Tests (push) Has been cancelled
CI / Admin UI Build (push) Has been cancelled

DynamicCORSMedium middleware resolves the calling site's registered
domains (Site.domain + Site.additional_domains) and returns the
appropriate Access-Control-Allow-Origin header for banner script
requests to public endpoints:

- GET /api/v1/config/sites/{site_id}
- GET /api/v1/translations/{site_id}/{locale}
- POST /api/v1/consent/

Instead of hardcoding ALLOWED_ORIGINS env var, each merchant website
automatically gets CORS access as long as its domain is registered
in the site configuration.
This commit is contained in:
Kunthawat Greethong
2026-06-15 18:36:23 +07:00
parent 683aa2379d
commit 7973cb321e
2 changed files with 127 additions and 1 deletions

View File

@@ -10,6 +10,7 @@ from src.config.settings import get_settings
from src.extensions.registry import discover_extensions, get_registry
from src.middleware.rate_limit import RateLimitMiddleware
from src.middleware.security_headers import SecurityHeadersMiddleware
from src.middleware.dynamic_cors import DynamicCORSMedium
from src.routers import (
auth,
compliance,
@@ -116,7 +117,10 @@ def create_app() -> FastAPI:
auth_requests_per_minute=10,
)
# CORS
# CORS — DynamicCORSMedium must come BEFORE CORSMiddleware so it can
# add per-site allowed origins for public banner endpoints
app.add_middleware(DynamicCORSMedium)
app.add_middleware(
CORSMiddleware,
allow_origins=settings.allowed_origins_list,