Which values may Access-Control-Allow-Origin carry in one response, and why can it never list three allowed hosts?
answer
- one grant, one caller
- not a comma-separated list
- three permitted forms of the value
- its neighbours are list-valued, this is not
- choose per response, do not enumerate
basics
~20 sAccess-Control-Allow-Origin carries exactly one value: one serialized origin, the literal null, or the wildcard. Its grammar defines no list, so a feed serving several caller origins emits the one value that fits the current request rather than enumerating them.
solid answer
~40 s`Access-Control-Allow-Origin` is defined as `origin-or-null / wildcard` - a single serialized origin such as `https://charts.example.net`, or the literal `null`, or `*`. There is no list construct in that grammar, which is what separates it from its neighbours: `Access-Control-Allow-Methods = #method`, `Access-Control-Allow-Headers = #field-name` and `Access-Control-Expose-Headers = #field-name` are all comma-separated lists, and this one is not. A response that carries `https://a.example, https://b.example` has produced a value that matches no caller, so the CORS check fails and script gets a network error instead of the response. A feed read by three charting hosts therefore states one grant per response, chosen for that request; how a server computes that choice is a separate subject.
code
http · 8 linesGET /stations/42/readings HTTP/1.1
Host: gauges.example.org
Origin: https://charts.example.net
HTTP/1.1 200 OK
Content-Type: application/json
Access-Control-Allow-Origin: https://charts.example.net
Access-Control-Allow-Methods: GET, POST, PUTgo deeper
Remember the shape before the theory: this grant holds one value, and a response that tries to name two callers at once grants neither of them.
Explain the grammar and the contrast with the list-valued grant fields, and say what the browser does with a value that matches no origin: the check fails and script gets a network error.
Show the diagnostic instinct. A server log full of 200s beside callers reporting failures points straight at a malformed or mismatched grant, because the server only grants and the browser only enforces.
The judgement is about the grant surface across an estate: a value that varies per caller is data with an owner, not a string each service assembles its own way.
`Access-Control-Allow-Origin` is the field by which a server states that one other origin may read one response. Its grammar is short, and reading it precisely answers most of what interviewers ask about CORS grants. ## One value, and only one The field's value is `origin-or-null / wildcard`, where `origin-or-null = serialized-origin / null` and `wildcard = *`. Three permitted forms, one value each: - **one serialized origin** - the scheme, host and port of a single caller, written exactly as that caller's `Origin` request header serialises it; - **the literal `null`** - a value, matched case-sensitively, which is not the same thing as sending no grant at all; - **`*`** - the wildcard, discussed below. Nothing in that grammar is a list. The field cannot hold two origins, comma-separated or otherwise, it has no pattern or suffix syntax, and repeating the field does not make it a list either. ## Why the contrast with its neighbours matters The other grant fields *are* lists, and the mismatch is what makes the mistake feel plausible: | field | grammar | shape | |---|---|---| | `Access-Control-Allow-Origin` | `origin-or-null / wildcard` | exactly one value | | `Access-Control-Allow-Methods` | `#method` | comma-separated list | | `Access-Control-Allow-Headers` | `#field-name` | comma-separated list | | `Access-Control-Expose-Headers` | `#field-name` | comma-separated list | A candidate who has written `Access-Control-Allow-Methods: GET, POST, PUT` naturally reaches for the same shape one line above it. The specification does not define that shape there, so nothing parses it. ## What happens when a list is sent anyway The browser compares the granted value against the origin it stamped on the request. A value like `https://charts.example.net, https://flood.example.com` is not that origin - it is a longer string that happens to contain it - so the comparison does not succeed, the CORS check fails, and script receives a network error rather than the response. The server, meanwhile, ran the request, wrote the body and logged a perfectly ordinary success. That gap between a happy server log and a failing caller is the characteristic signature of a malformed grant, and it follows from who does what: **the server grants, the browser enforces**. ## A feed with several callers The consequence is structural rather than procedural. A river-gauge feed charted by pages on three different hosts cannot publish one static response that names all three. It states one grant per response, matching the caller of that request - so the response body may be identical for every caller while this one header differs. Two subjects sit right next to that fact and are not this one: how a server decides which value to write belongs to server-side middleware, and what a shared cache must be told about a response that varies this way is its own topic. What belongs here is the field's grammar and its consequence: choose one, do not enumerate. ## The wildcard and the literal null `*` is the third permitted form and means the response may be read by any origin. It is the right answer for a genuinely public feed read without credentials, and the wrong one the moment the response is not meant for everybody - a judgement that belongs with the misconfiguration material, not with the grammar. The literal `null` deserves its own sentence, because **a missing grant is not `null`**. If the response carries no `Access-Control-Allow-Origin` at all, there is no grant and the check fails. If it carries the four characters `null`, that is a value, and it matches a caller whose origin serialises to exactly that. Confusing the two produces answers that sound right and describe different mechanisms. ## What the grant does not do 1. **It does not stop the request.** The request was sent, reached the server and took effect; only the *read* of the response is withheld. 2. **It is not access control.** Any client that is not a browser ignores the field entirely, so a grant is never an API's protection. 3. **It does not authenticate anyone.** It names an origin, not a user. 4. **It grants the response, not its headers.** Which fields of that response script may read is decided separately. Hold those four and the field stops being mysterious: it is one value, written by the server, read by the browser, deciding one thing.
- Is a missing Access-Control-Allow-Origin the same as sending the literal value null?No. An absent field means no grant was made at all, so the CORS check fails for every caller. The literal `null` is a value, matched case-sensitively, and it grants a caller whose origin serialises to exactly that. One is silence, the other is a statement, and only the second can ever match anything.
- Which of the CORS grant fields are comma-separated lists?`Access-Control-Allow-Methods` is `#method`, and `Access-Control-Allow-Headers` and `Access-Control-Expose-Headers` are both `#field-name`, so all three take comma-separated lists. `Access-Control-Allow-Origin` is the odd one out with a single value. Getting that asymmetry the right way round is most of what this field is asked about.
saying these in an interview costs you the question
- Writes several origins into Access-Control-Allow-Origin separated by commas
- Thinks the field takes the same list grammar as Access-Control-Allow-Methods
- Says an absent grant header means the same as the literal null
- Believes the browser picks a matching entry out of a granted list
- Claims the field is what stops a non-browser client reading the feed