Skip to content

fix(api): add Access-Control-Max-Age 86400 to CORS preflight (BUG-API-303)#187

Merged
mastermanas805 merged 1 commit into
masterfrom
fix/api-ratelimit-policy-header-2026-05-30
May 30, 2026
Merged

fix(api): add Access-Control-Max-Age 86400 to CORS preflight (BUG-API-303)#187
mastermanas805 merged 1 commit into
masterfrom
fix/api-ratelimit-policy-header-2026-05-30

Conversation

@mastermanas805
Copy link
Copy Markdown
Member

Summary

  • BUG-API-303: OPTIONS preflight responses had no Access-Control-Max-Age, so browsers re-issue a preflight before every CORS request — every authed call from instanode.devapi.instanode.dev paid the extra roundtrip
  • Set MaxAge: 86400 (24h) on the fiberCORS middleware. Chrome clamps to 2h, Firefox 24h, Safari 7d — we ask for the max standard value and let each browser apply its clamp
  • Vary: Origin is already emitted so per-origin caches stay safe

Rule-17 coverage block

  • Symptom: OPTIONS preflight missing Access-Control-Max-Age
  • Enumeration: rg -F 'fiberCORS' internal/ — 1 emit site (router.go)
  • Sites touched: 1
  • Coverage test: TestCORSPreflight_HasMaxAgeHeader (new file internal/router/cors_maxage_test.go) — drives an OPTIONS preflight through a config that mirrors router.New verbatim and asserts Access-Control-Max-Age=86400 on the response. Fails today before the router.go change.
  • Live verified: pending merge + auto-deploy + curl -X OPTIONS -H "Origin: https://instanode.dev" -H "Access-Control-Request-Method: POST" https://api.instanode.dev/api/v1/whoami | grep access-control-max-age

Test plan

  • go build ./... / go vet ./...
  • go test ./internal/router/... -short -count=1 (all pass including the new test)
  • Post-merge: curl -X OPTIONS -H "Origin: https://instanode.dev" ... returns access-control-max-age: 86400

@mastermanas805 mastermanas805 force-pushed the fix/api-ratelimit-policy-header-2026-05-30 branch 2 times, most recently from a3f57b0 to 7f82288 Compare May 30, 2026 06:00
…-303)

Without Access-Control-Max-Age the browser re-issues an OPTIONS preflight
before every CORS request. An SPA making 5 cross-origin API calls fires
5 extra preflight roundtrips. 24h (86400) is the modern browsers' clamp
ceiling — Chrome caps at 2h, Firefox at 24h, Safari at 7d — so we ask
for the maximum standard value and let each browser apply its own clamp.

The dashboard SPA is the main beneficiary: every authed call from
instanode.dev → api.instanode.dev used to pay the preflight cost. After
this change cooperative browsers cache the preflight result for up to
2h (Chrome) / 24h (Firefox).

Coverage block:
  Symptom:        OPTIONS preflight responses missing Access-Control-Max-Age
  Enumeration:    rg -F "fiberCORS" internal/ — 1 emit site in router.go
  Sites found:    1
  Sites touched:  1
  Coverage test:  TestCORSPreflight_HasMaxAgeHeader (new file
                  cors_maxage_test.go) — drives an OPTIONS preflight
                  through a fiberCORS-mirrored config and asserts
                  Access-Control-Max-Age=86400 on the response. Fails
                  today before the router.go change.
  Live verified:  pending merge + auto-deploy + curl -X OPTIONS -H
                  "Origin: https://instanode.dev" -H "Access-Control-
                  Request-Method: POST" https://api.instanode.dev/api/v1/whoami
                  | grep access-control-max-age

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@mastermanas805 mastermanas805 force-pushed the fix/api-ratelimit-policy-header-2026-05-30 branch from 7f82288 to 685f4cf Compare May 30, 2026 06:16
@mastermanas805 mastermanas805 merged commit c63951a into master May 30, 2026
14 checks passed
@mastermanas805 mastermanas805 deleted the fix/api-ratelimit-policy-header-2026-05-30 branch May 30, 2026 06:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant