A page sometimes needs to read a response from another origin. An origin combines scheme, host and port. Cross-Origin Resource Sharing, or CORS, is the browser mechanism through which a server permits certain cross-origin access. It is separate from authenticating a caller or authorizing an action.
For some requests, the browser first sends an OPTIONS preflight asking whether the intended origin, method and headers are permitted. Access-Control-Allow-Origin names a permitted origin in the response. Credentialed response access has additional requirements; an allow-origin header does not grant a user permission to alter records.
Before you begin
- Recommended first
- Notes: scope, command, result, time, HTTP methods, headers, status codes, cookies, How a web app is put together, Same-origin policy, Cross-site request forgery
- Estimated time
- 16 min reading, 12 min activity. Setup and optional practice may take longer.
- Where you work
- Use the fictional page source, requests and policy models printed here in any current desktop or mobile browser. No server, login, framed account page or socket connection is required.
- Without a lab
- Read each source fragment or model and predict its result in notes. Identify the boundary, the supporting fact and one limit, then compare with the activity rubric. This does not reproduce a browser exchange. Reading works without JavaScript. Checking requires JavaScript and a secure context; saving additionally requires usable browser storage.
After this lesson you can:
- Read the requested origin and the allow-origin value as different names.
- Say that a shell client does not consult the browser policy.
- Name the side that still has to authorize the change.
01Example
Worked policy: notes is listed and other is not. The activity transcript is the OPTIONS model.
Listed origin: https://notes.club.invalid
Unlisted origin: https://other.club.invalid
Allow-origin for a listed origin is that origin, not a star.02A browser rule is not a permission
The synthetic request comes from other.club.invalid while the response names notes.club.invalid. Those are different hosts and therefore different origins. Listing PATCH in allowed methods cannot fix the origin mismatch. Under this model, the browser does not proceed with the requested cross-origin operation after that failed preflight.
The trust decision here is whether a browser may expose the cross-origin response and proceed with a preflighted call. Enforce a narrow CORS policy where cross-origin browser access is intended, while still checking identity and resource permission on the server. Some cross-origin requests do not need preflight, and a non-browser client does not enforce browser CORS, so CORS cannot be the application's general access control.
Read a synthetic preflight as a browser rule, and keep the server's permission check on the server.Model. A teaching model drawn by hand. It shows the idea, not real tool output.
Read the full explanation below.
| Field | Listed origin | Unlisted origin |
|---|---|---|
| Request origin | https://notes.club.invalid | https://other.club.invalid |
| Explicitly listed | Yes | No |
| Allow-origin response role | https://notes.club.invalid | No allowed origin supplied for this host |
| Server record access rule | Separate server policy | Separate server policy |
The listed origin receives its exact origin value, not a star.
The listed origin receives its exact origin value, not a star.
Follow the explanation
- The listed origin receives its exact origin value, not a star.
- A browser read rule does not decide the server’s access decision for either origin.
Read every state and value
1. The listed origin receives its exact origin value, not a star.
- Selected Comparison
- listed-origin
- Highlighted Field
- Request origin · Listed origin · Allow-origin response role
2. A browser read rule does not decide the server’s access decision for either origin.
- Selected Comparison
- permission
- Highlighted Field
- permission
03Read the transcript
Read the evidence before comparing with the activity rubric. Send nothing.
Response policy model. No browser request was sent.
Origin https://notes.club.invalid is listed.
Origin https://other.club.invalid is not listed.
The card's allow-origin value for a listed origin is that origin, not a star.
This policy does not permit credentialed cross-origin response access for an unlisted origin. Cookie sending follows separate browser rules.
A shell client does not consult this browser policy.
The server must independently authorize an action regardless of which client sends it.
Synthetic preflight model. Not a captured browser exchange.
Request
OPTIONS /notes/7
Origin: https://other.club.invalid
Access-Control-Request-Method: PATCH
Response
204
Access-Control-Allow-Origin: https://notes.club.invalid
Access-Control-Allow-Methods: GET, PATCH
The requested origin is other. The allow-origin value is notes.
The model does not treat those as the same origin.
The server's permission check is a separate decision and is not shown on this transcript.
- Write the Origin on the request and the allow-origin value on the response.
- Say whether the model treats them as the same origin.
- Check: the request origin is other and the allow-origin value is notes. They are not the same. A shell client is outside this browser policy.
- Stop. Do not send the OPTIONS request.
04Optional challenge
Say what the transcript shows and what it does not show. The rubric is: it shows an origin mismatch in a model, and it does not show the server's permission decision. About ten minutes.
05Fresh cases for the checks
Use these fictional cases for the checks below. They have different inputs from the worked examples. Read them here or make notes; no installation or external service is needed.
Origin case A: fresh synthetic preflightsOwned fixture. An original file made for this course. Follow the activity's instructions in your own lab.
Each proposed browser request uses PATCH. All response method lists include PATCH.
P request Origin https://reader.lab.invalid; response allow-origin https://reader.lab.invalid.
Q request Origin https://archive.lab.invalid; response allow-origin https://reader.lab.invalid.
R request Origin http://reader.lab.invalid; response allow-origin https://reader.lab.invalid.
Compare full origins including scheme. No exchange occurred; server action permissions are not shown.
Origin case B: independent client comparisonOwned fixture. An original file made for this course. Follow the activity's instructions in your own lab.
Browser client and shell client propose the same state-changing request.
Response policy allows only https://reader.lab.invalid.
Caller permission to change the selected note has not been established.
The shell client does not enforce browser CORS.
06Explain your evidence
Optional written self-check: explain one decision using the supplied case. No tool run is required.
Check your explanation: compare complete requested and allowed origins; separate method matching from origin matching; distinguish browser enforcement from shell behavior; name the missing server resource/action check.
07Common mistakes
If you treat other and notes as one site because both end in club.invalid, you skipped the host. The model says they differ.
If you treat the allow-methods list as permission for a shell client, the transcript is a browser model.
If you call this a captured browser exchange, the file says it is synthetic.
References
- RFC 6454: The Web Origin Concept
An origin is scheme, host, and port. A browser's reading limit is not a server authorization check, and curl is not bound by it. The transcript is synthetic.
- PortSwigger: CORS
Explains this mechanism, its impact and defenses. Required reasoning uses the original evidence printed on this page.