What exact value does a browser put in the `Origin` request header for a page at `https://board.example.org/embed/arrivals?stop=42`?
answer
- three parts, nothing more
- not a copy of the address bar
- path and query never travel
- default port is omitted
- scheme and host lower-cased
basics
~10 sThe Origin request header carries only scheme, host and a non-default port: https://board.example.org. The path, the query, the fragment and any trailing slash are absent, and scheme and host are ASCII-lower-cased.
solid answer
~40 sThe browser serializes the page's origin and sends nothing else: `Origin: https://board.example.org`. The grammar is `serialized-origin = serialized-scheme "://" serialized-host [ ":" serialized-port ]` — scheme, `://`, host, and a port **only when it differs from the scheme's default** (80 for http, 443 for https). There is no path, no query string, no fragment and therefore no trailing slash, because a serialized origin has no path component for a slash to introduce. Scheme and host are ASCII-lower-cased regardless of how they were written. So a departures host serving many embedded boards learns *which security context* is calling, and never *which screen* of it was open.
code
http · 4 linesGET /v1/departures?stop=42 HTTP/1.1
Host: api.departures.example
Origin: https://board.example.org
Accept: application/jsongo deeper
Recall the shape: scheme, host, and a port only when it is not the scheme's default. Nothing after the host. If you can say why the path is missing, you have the whole answer.
Explain the serialization as a rule rather than an example: which three components exist, which one is conditional and on what, and that scheme and host are lower-cased. Name the defaults, 80 and 443.
Show that you know the value is compared as bytes on the other side, so every dropped component and every case fold is a place where a hand-written configuration entry silently stops matching what actually arrives.
Frame it as an interface question: this header is the only caller identity the browser offers, it is deliberately coarse, and any design that wants finer granularity than a security context has to carry that itself rather than hoping the header grows.
An arrivals board is embedded in dozens of host pages, and every one of those copies calls the same departures host for data. Before each call leaves the machine, a conforming browser stamps one request header on it — `Origin` — and the value is produced by a single small serialization, never by copying the address bar. ## The grammar ```http GET /v1/departures?stop=42 HTTP/1.1 Host: api.departures.example Origin: https://board.example.org ``` The value is a **serialized origin**, defined as `serialized-origin = serialized-scheme "://" serialized-host [ ":" serialized-port ]`. Three components, in a fixed order, and the third is conditional: - **scheme** — `http` or `https` for a page fetched over the network, written in lower-case ASCII and followed by the literal `://`. - **host** — the registrable host of the document, also ASCII-lower-cased. No user information, no credentials, no authentication material of any kind travels here. - **port** — written as `:` plus the number **only when it differs from the scheme's default**. The default is `80` for `http` and `443` for `https`. A page served from `https://board.example.org:443/embed` therefore sends `https://board.example.org`, with no port at all. ## What is deliberately absent The serialization is defined by what it drops as much as by what it keeps: - **No path.** `/embed/arrivals` never appears. The departures host cannot tell which route of the board is on screen. - **No query.** `?stop=42` is part of the request target on the request line, not of the origin. - **No fragment.** A fragment is never sent on the wire in any request, and it is not part of an origin either. - **No trailing slash.** This one catches people because a browser's address bar renders `https://board.example.org/` for a root document. A serialized origin has no path component, so there is nothing a slash could separate — the value ends at the host or at the port. - **No case as typed.** An operator who writes the host in mixed case somewhere in a configuration file will still see the lower-cased form arrive. ## The same site, four URLs | The document's URL | The `Origin` value sent | |---|---| | `https://board.example.org/` | `https://board.example.org` | | `https://board.example.org/embed/arrivals?stop=42` | `https://board.example.org` | | `https://board.example.org:443/embed` | `https://board.example.org` | | `http://board.example.org:8080/embed` | `http://board.example.org:8080` | The first three are one value, because scheme, host and effective port are identical in all three; only the fourth differs, and it differs in two components at once — a different scheme and a port that is not that scheme's default. ## Why the value is this narrow The header exists to answer exactly one question for the receiving host: **which security context initiated this request?** That is a coarse-grained identity by design. Anything finer — which page, which route, which user — would turn a header that every cross-context request carries into a channel that leaks browsing activity to every host a page touches. Keeping the value to scheme, host and non-default port also makes it a short, fixed byte sequence that can be compared without parsing, which is what a grant decision needs. The practical consequences follow directly: 1. **The value is stable across navigation inside the embed.** Moving from an arrivals view to an alerts view changes the URL and changes nothing in the header. 2. **The value identifies a context, not a person.** No cookie, no token and no user identity is carried by this field. 3. **The value is a byte sequence someone wrote down on the other side.** Whatever a receiving host compares it against has to be spelled the same way, character for character, or the comparison fails even though a human reading the two strings would call them the same site. ## What the value does not tell you It does not say what the page was doing, and it does not on its own say that the caller is somewhere else: the header also appears on requests that never left the sending origin, so the *presence* of the field and the *content* of the field carry different information. Read the value; the field's mere existence is not the signal.
- The board is served from `https://board.example.org:443/embed`. Does the `Origin` header spell out the port?No. The port component is serialized only when it differs from the scheme's default, and `443` is the default for `https`, so the value is `https://board.example.org`. The same page reached as `http://board.example.org:80/embed` would send `http://board.example.org`. A non-default port such as `8080` is written out in full.
- The embed navigates from `/embed/arrivals` to `/embed/alerts`. What changes in the `Origin` header?Nothing. Only scheme, host and non-default port are serialized, and all three are unchanged, so both views send the identical value. A receiving host cannot distinguish the two screens from this header — if it needs to, that distinction has to be carried somewhere it is actually allowed to appear, such as the request target.
- An operator has the host recorded as `Board.Example.ORG`. What arrives in the header from a page on that host?`https://board.example.org`. Scheme and host are ASCII-lower-cased during serialization, so the case a human wrote is not preserved on the wire. That matters because anything the receiving host compares the value against is compared as bytes, and a mixed-case entry written by hand will not equal the lower-cased bytes that arrive.
It is a return address written to the building, not to the desk: enough to say which office is calling, never enough to say what was on the paper in front of them.
saying these in an interview costs you the question
- Thinks the Origin request header carries the full page URL
- Says the path is included so the server can see the route
- Assumes an https origin always spells out port 443
- Believes the host arrives with whatever case was typed
- Expects a trailing slash because the address bar shows one