Web Security / Intermediate: browser and data interpretation defenses / Lesson 10
CORS, origins, and credentialed browser access
Define cross-origin response sharing without treating browser policy as authentication, CSRF protection, or a server-to-server boundary.
On this page
Lesson goals
- Explain actual requests, preflight, credentials, and response exposure.
- Use explicit origin policy and cache-aware headers.
CORS governs a browser sharing decision
The same-origin policy limits how browser scripts access resources across origins. CORS lets a server declare which cross-origin response sharing the browser may permit. It does not authenticate an account, authorize a record, or prevent every request from reaching the server. Nonbrowser clients do not become trusted merely because they send an Origin header. Define why one frontend origin needs a resource and which credential model applies. Keep same-site cookie behavior distinct from same-origin response rules. A readable response, an executed action, and a valid session are separate properties requiring separate evidence.
Read explicit sharing headers in context
The fictional response permits one exact origin and credentialed sharing. A wildcard Allow-Origin is not accepted as a substitute for a specific origin in credentialed browser access under current documented rules. The headers are not installed or sent anywhere. If a response chooses an origin dynamically, Vary: Origin helps caches distinguish that decision; private data still needs appropriate cache policy and authorization. Do not reflect every incoming origin as if reflection were an allowlist. The configured origin includes scheme and any nondefault port, and does not include an arbitrary path or trailing route.
Access-Control-Allow-Origin: https://portal.example.invalid
Access-Control-Allow-Credentials: true
Vary: Origin
These are illustrative fields for one fictional origin, not a complete server configuration. They do not validate a user or permit every method/header. No browser, proxy, cache, or request behavior is tested by displaying this text.
Keep capability negotiation separate from the action
Some browser requests require a preflight that asks about method and header permissions before the actual operation. Its handling, cache lifetime, and credentials have documented fetch/browser rules and should not be guessed from the application’s normal route behavior. Allowing a preflight does not complete authorization for the actual request. A preflight failure can be an integration or policy issue, while a response-hidden error can occur after a server already processed a request. Diagnose the phase with approved existing evidence. Do not repeatedly send state-changing traffic to a real service while trying to make a console warning disappear.
Model exact allowlist membership offline
The pure function accepts one declared origin string and refuses an unlisted origin. It does not normalize arbitrary URLs, inspect DNS, or prove that the header was generated by a browser. A production CORS implementation should use maintained middleware with reviewed parsing and response rules. Keep the accepted set minimal and owned, including how development, staging, and production differ. An opaque or missing origin needs an explicit product policy, not an accidental wildcard. Separate CORS decisions from authentication and resource permission, and test response variations under the actual cache and proxy path.
APPROVED_ORIGINS = {"https://portal.example.invalid"}
def shared_origin(origin):
return origin if isinstance(origin, str) and origin in APPROVED_ORIGINS else None
assert shared_origin("https://portal.example.invalid") == "https://portal.example.invalid"
assert shared_origin("https://other.example.invalid") is None
assert shared_origin(None) is None
The strings are reserved fictional destinations and no request is made. The result is an allowlist decision only, not an identity claim or full CORS implementation. Actual middleware/browser behavior remains separately untested.
Verify success, refusal, and cache variation together
In an authorized isolated environment, verify the intended frontend origin, credential mode, methods, request headers, actual response fields, and relevant redirects. Check the actual operation’s authentication and unchanged state for denied mutations independently. A request that works through a command-line client does not establish browser CORS behavior. Preserve minimal diagnostics without credentials or private bodies. Review policy changes with an owner rather than disabling browser security or allowing every origin to repair one integration. The goal is a narrow documented sharing contract whose successful and refused paths are both understood.
Common errors and fixes
Every Origin is reflected as approved
- Why it happens
- Reflection is mistaken for a reviewed allowlist.
- How to fix it
- Use a narrow explicit origin policy.
- Prevent it next time
- Test unlisted, missing, and intended origins.
CORS success is called authorization
- Why it happens
- Browser response sharing is confused with data permission.
- How to fix it
- Enforce authentication and resource scope on the server.
- Prevent it next time
- Verify direct requests independently.
A cache mixes origin-dependent response policy
- Why it happens
- Variation and private response handling are incomplete.
- How to fix it
- Review Vary and cache policy with the actual deployment path.
- Prevent it next time
- Include cross-origin cache cases in testing.
Check your understanding
1. Why can a command-line request succeed while browser script cannot read the response?
Show worked solution
CORS is a browser sharing policy, so a nonbrowser client does not exercise the same enforcement. Check intended origin, credentials, preflight, and response fields in an authorized browser harness while keeping server permission separate.
2. Does Access-Control-Allow-Credentials authorize every signed-in user from the allowed origin?
Show worked solution
No. It participates in the browser’s credentialed sharing decision. The actual service must still validate the session and authorize the requested resource and action.
Key takeaways
- CORS is browser response-sharing policy.
- Credentialed access needs an explicit compatible origin contract.
- Preflight, actual action, and caches need separate evidence.