ADR 0047 — Track B: CORS origin allowlist for raxx.app on raxx-api-prod
Status: Accepted
Date: 2026-05-03
Deciders: software-architect
Context doc: raxx-app-track-b.md §4
Parent epic: #94
Context
raxx-api-prod (Heroku) already reads FRONTEND_ORIGIN env var to populate flask_cors.CORS(origins=...). The fallback is http://localhost:3000. On production, if FRONTEND_ORIGIN is not set, every cross-origin request from https://raxx.app is rejected by the browser before it reaches Raptor, because the CORS preflight response does not include Access-Control-Allow-Origin: https://raxx.app.
The code is correct. The config-var is missing.
Decision
Set FRONTEND_ORIGIN=https://raxx.app on the raxx-api-prod Heroku app.
Set FRONTEND_ORIGIN=https://raxx-app.pages.dev on the raxx-api-staging Heroku app.
No code change is required. The existing CORS init in backend_v2/api/__init__.py handles this correctly via _frontend_origins_raw.split(',').
Consequences
Positive
- Customers visiting
raxx.appcan make cross-origin API calls toapi.raxx.appwithout CORS rejection. - The comma-separated multi-origin pattern already supported allows future addition of preview-deployment origins without code changes.
supports_credentials=Trueis already set, which is required for cookie-based session auth across origin boundaries.
Negative / risks
- Setting
FRONTEND_ORIGINonraxx-api-prodimmediately opens CORS for that origin. If any other Track B items (CF Access removal, auth flag, env vars) are not also completed, customers will reach a partially-wired API. The rollout plan in Track B §11 gates these steps sequentially to prevent a half-open state from reaching real traffic.
Alternatives considered
A: Wildcard CORS (origins='*')
Rejected. Wildcard CORS is incompatible with supports_credentials=True (browsers reject credentialed requests with a wildcard origin header). It also removes the ability to scope which domains can call the API. The 2026-04-24 security review flagged this as finding C1; it was already fixed.
B: Hard-code https://raxx.app in source
Rejected. The FRONTEND_ORIGIN env var pattern is already established and rotatable without redeploy. Putting the origin in source would make staging/prod parity a code branch rather than a config-var difference.
C: Use CF Access to restrict cross-origin calls instead of CORS
Rejected. CF Access is a surface-gating mechanism, not a browser-facing CORS mechanism. The browser performs CORS preflight before CF Access has any involvement. CF Access cannot substitute for CORS headers.