In the CORS protocol, what counts as a credential on a cross-origin request besides the session cookie?
answer
- ambient state, not code-supplied headers
- three kinds, not only cookies
- transport-layer identity counts too
- the authentication cache is one
- script-set Authorization governed elsewhere
basics
~20 sCORS counts three kinds of ambient client state as credentials: HTTP cookies, TLS client certificates, and cached HTTP authentication entries. All three travel without the calling code doing anything, which is why one grant field governs all of them.
solid answer
~40 sThe specification names three: HTTP cookies, TLS client certificates, and authentication entries held for HTTP authentication. What unites them is that the browser attaches them by itself, on the strength of who the user is rather than what the code asked for. That is why a single response field, `Access-Control-Allow-Credentials: true`, covers all three rather than one per kind. An `Authorization` header the page's own code sets is deliberately not in the list: it is not ambient, so it is governed as a request header name — it is the one CORS non-wildcard request-header name, which must be listed explicitly in `Access-Control-Allow-Headers` and forces a preflight. Whether the three ambient credentials are attached at all is decided by the request's credentials mode, and only the mode `"include"` attaches them on a cross-origin request.
code
http · 10 linesGET /maintenance-requests HTTP/1.1
Host: api.portal.example
Origin: https://portal.example
Cookie: tenant_session=8f2b9c
HTTP/1.1 200 OK
Content-Type: application/json
Access-Control-Allow-Origin: https://portal.example
Access-Control-Allow-Credentials: true
Vary: Origingo deeper
Remember the list: cookies, TLS client certificates, and cached HTTP authentication entries. The unifying idea is that the browser attaches all three by itself.
Be able to explain why a token the code writes into Authorization sits outside that list, and which field governs it instead. That distinction is the whole definition.
Show that you audit all three kinds when hardening a cross-origin API, not just the cookie path, and that you know the certificate never appears in a request dump.
The angle is blast radius: one grant field covers three identity mechanisms because the risk they create is the same, which is what keeps the decision reviewable across an estate of services.
## What the word means here A **credential**, in CORS, is client state the browser would attach on its own initiative because of who the user is — not something the calling code placed on the request. The specification lists exactly three kinds: 1. **HTTP cookies** — the everyday case, and the one every explanation reaches for first. 2. **TLS client certificates** — presented during the handshake that opened the connection. 3. **Authentication entries for HTTP authentication** — the browser's cache of credentials a user already supplied in answer to a challenge, replayed on later requests into the same protection space. What binds these three together is *ambience*. None of them is written by the page. Each is attached because the browser holds identity for that destination and decided, under its own rules, to use it. ## Why a tenant portal cares A property-management portal on one host calls a maintenance-request API on another. The tenant's session cookie is the obvious credential, and most teams stop there. But the same API may also be reached over a connection that presented a client certificate — used by the contractor-facing integration — and the same browser may hold an authentication entry for an internal administrative path. Every one of those makes a cross-origin request **credentialed**, and every one of them puts the response inside the scope of the same grant field. A team that hardens only the cookie path has hardened one of three. ## What is not a credential An `Authorization` header the page's own code sets is **not** a credential for CORS purposes, even though it plainly carries identity. The reason is the definition above: the code put it there, so it is not ambient. CORS therefore governs it as a **request header name** rather than as a credential: - it is the single **CORS non-wildcard request-header name**, meaning a `*` in `Access-Control-Allow-Headers` never covers it; - the server must name it explicitly in `Access-Control-Allow-Headers`; - adding it pushes an otherwise plain request into a preflight. So a call that authenticates with a bearer token in `Authorization` and no cookie is, in CORS terms, an **uncredentialed** request with one awkward header — a different configuration problem with different fields. | Kind of identity | How it reaches the server | What governs it in CORS | |---|---|---| | HTTP cookie | Browser attaches it from its own store | `Access-Control-Allow-Credentials` | | TLS client certificate | Offered during the handshake, not a header | `Access-Control-Allow-Credentials` | | HTTP authentication entry | Browser replays a cached answer to a challenge | `Access-Control-Allow-Credentials` | | `Authorization` set by script | The calling code writes it | `Access-Control-Allow-Headers`, and it forces a preflight | ## The credentials mode decides whether they travel A request carries one of three credentials modes: - **`"omit"`** — never attach any of the three. - **`"same-origin"`** — attach them only when the request is same-origin. This is the ordinary default for a cross-origin call, and it means nothing is attached. - **`"include"`** — attach them even cross-origin. Only this mode makes a request credentialed, and only this mode makes the server's `Access-Control-Allow-Credentials: true` necessary. The practical consequence is that **two conditions must both hold** before the personalised body ever exists: the calling code opted into `"include"`, *and* the browser's own cookie rules agreed to attach the cookie to a cross-site request. The grant field has nothing to say about either. It speaks only to what happens afterwards, on the reading side. ## Why one field, not three It is tempting to think each credential kind deserves its own grant. It does not, because the risk they create is identical: the response was computed for a signed-in user, and letting a second origin's script read it is the leak, regardless of which of the three identified that user. One field, one decision, one blast radius. ## What to carry away - Three credential kinds, not one. The certificate and the authentication cache are easy to forget precisely because they never appear as a header in a request dump. - Ambience is the test: *would the browser have attached this by itself?* - A token the code sets is not a credential; it is an unsafe request header name with its own rules. - The mode decides whether credentials are sent; the grant decides only whether script may read what comes back.
- Why does an `Authorization` header the page's own code sets not make a request credentialed?Because credentials in CORS are ambient — attached by the browser on its own. A header the code writes is data the code chose to send, so CORS governs it as a request header name: it is the one CORS non-wildcard request-header name, it must be listed by name in `Access-Control-Allow-Headers`, and it triggers a preflight. `Access-Control-Allow-Credentials` never covers it.
- A cross-origin request is sent with credentials mode `"same-origin"`. What reaches the server?No cookie, no client certificate and no authentication entry. That mode attaches credentials only when the request is same-origin, and this one is not, so the server sees an anonymous request. It will also not be checked for `Access-Control-Allow-Credentials`, because the browser only demands that grant when the mode is `"include"`.
saying these in an interview costs you the question
- Credentials in CORS means cookies and nothing else
- An Authorization header set by script is covered by Allow-Credentials
- A TLS client certificate is outside CORS, so credentials mode cannot affect it
- Credentials ride along on every cross-origin request by default
- Allow-Credentials decides whether the request is sent at all