Request header
> Origin: https://app.example.comOrigin Header
Learn how the Origin header identifies where cross-origin requests come from. Essential for CORS security policies and preventing cross-site request forgery.
- Direction
- Request
- Category
- CORS
- Spec
- RFC 6454 §7
- JS can set it
- No: forbidden header name
On this page
TL;DR:
Originidentifies the initiating origin as scheme, host, and optional port, with no path or trailing slash. Browsers set it for CORS requests and many non-GET/HEAD requests, but not every cross-origin load.Origin: nullis not a trusted website identity.
What is Origin?
The header describes the origin that initiated a request, rather than the server receiving it. Origin: https://app.example.com and Host: api.example.com refer to different sides of a cross-origin API call. Fetch defines current browser Origin behavior; RFC 6454 describes the origin concept.
How Origin Works
Illustrative request header excerpt:
GET /api/profile HTTP/1.1
Host: api.example.com
Origin: https://app.example.com
If the API permits this origin, it can return Access-Control-Allow-Origin: https://app.example.com. If it does not, the browser prevents JavaScript from reading the response. That does not establish that the server never received or processed the request.
Origin Format
Origin: https://app.example.com
A non-default port is included, as in http://localhost:5173. A default HTTPS port is omitted from the serialized origin. Paths, queries, fragments, and user information are absent. An opaque origin is serialized as the literal null.
When Browsers Send Origin
CORS requests carry Origin, including their preflights. Browsers also add it to requests with methods other than GET or HEAD, with rules that can produce null. A cross-origin image loaded without crossorigin normally uses no-cors; cross-origin GET/HEAD in that mode need not send Origin. MDN documents the exceptions.
Redirects can change the value to null; they do not universally remove the header. Referrer policy can also affect Origin on some non-CORS, non-GET/HEAD requests.
Compare these elements from a page on another origin:
<img src="https://static.example.com/logo.png" alt="Plain image">
<img src="https://static.example.com/logo.png" crossorigin="anonymous" alt="CORS image">
The first is an ordinary no-cors image load. The second requests CORS and sends Origin; the image server must provide CORS permission. Adding crossorigin changes the loading contract, not just the headers you see in DevTools.
Real-World Examples
A page at https://app.example.com fetching https://api.example.com is cross-origin even though both hosts can be same-site. A page at http://localhost:5173 calling http://localhost:3000 is also cross-origin because the ports differ.
Illustrative local-development JSON request excerpt:
POST /api/orders HTTP/1.1
Host: localhost:3000
Origin: http://localhost:5173
Content-Type: application/json
Allow http://localhost:5173 explicitly when that is the frontend’s address. http://127.0.0.1:5173 is another origin; replacing the host in the address bar can explain why the same code suddenly fails CORS. Neither value is the backend’s Host: localhost:3000.
CORS and Origin Validation
For an existing Express app, use an explicit allowlist with the cors package:
const cors = require('cors')
app.use('/api', cors({
origin: ['https://app.example.com', 'http://localhost:5173'],
methods: ['GET', 'POST'],
allowedHeaders: ['Content-Type']
}))
This is an example development allowlist; remove the localhost entry for a production-only deployment. The middleware varies reflected responses by Origin. Avoid setting the response origin to an arbitrary caller-supplied string.
Security Implications
Origin is a forbidden request header for browser scripts. Curl and other non-browser clients can set it freely. Treat it as a browser security signal, never API authentication or evidence that a user is an administrator.
Common Patterns
When implementing CSRF checks, compare exact parsed origins rather than substring matches. https://example.com.attacker.example contains the string example.com but is not its origin. A missing Origin requires a deliberate route policy; do not turn it into an automatic authorization grant.
This middleware imposes a fail-closed origin check on a cookie-authenticated write route in an existing Express app:
const trusted = new Set(['https://app.example.com'])
app.use('/api/settings', (req, res, next) => {
if (req.method !== 'POST') return next()
const origin = req.get('Origin')
if (!trusted.has(origin)) return res.status(403).end()
next()
})
Place it before the POST handler and retain authentication and CSRF-token validation. This route intentionally rejects missing Origin as well as null; if non-browser clients need access, design their authentication path explicitly. A curl caller can supply an allowed Origin and therefore still needs independent authentication. OWASP describes origin checks and missing-header handling.
Testing Origin Headers
curl -i https://api.example.com/api/profile \
-H 'Origin: https://app.example.com'
Repeat with a disallowed origin and inspect the response. Then use browser Network to inspect the automatically generated Origin on the actual request. Curl demonstrates the server’s response policy, not browser enforcement.
Getting Origin right
Origin uses no trailing slash, whereas an origin-only Referer is a URL ending in /. For dynamically reflected CORS responses, preserve Vary: Origin so caches distinguish responses selected by request origin.
When setting CORS headers manually, Express’s res.vary() preserves other Vary fields:
const allowed = new Set(['https://app.example.com', 'https://admin.example.com'])
app.use('/api', (req, res, next) => {
res.vary('Origin')
const origin = req.get('Origin')
if (allowed.has(origin)) res.set('Access-Control-Allow-Origin', origin)
next()
})
This fragment selects the allowed-origin header only; add full preflight and credentials handling if required. Vary also belongs on responses for disallowed origins so a cache knows origin influenced the selection. Express documents res.vary.
Common Issues
A missing Origin on a normal cross-origin image load is not necessarily a browser defect. A missing CORS response header on a fetch is a different problem. Check the request mode and resource type before changing the allowlist.
The null Origin and Security Implications
A sandboxed iframe without allow-same-origin can initiate requests with Origin: null. Different unrelated opaque origins serialize identically, so allowing null does not identify a particular local file or trusted embed. MDN warns against allowing null for CORS.
For a controlled test, serve this iframe from an ordinary page:
<iframe sandbox="allow-scripts" title="Opaque-origin test"
srcdoc="<script>fetch('https://api.example.com/api/status').catch(console.error)</script>">
</iframe>
Inspect the API request in Network: the sandbox omits allow-same-origin, so the script runs with an opaque origin. Allowing null would grant the same serialized identity to other unrelated sandboxed documents. A response readable by this test frame is not proof that only this particular embed can access it.
Related Headers
Frequently asked questions
What is the Origin header?
Origin identifies the initiating origin using scheme, host, and an optional port, or the value null for an opaque origin. It does not contain a path.
When is Origin sent?
Browsers send it for CORS requests and many requests other than GET or HEAD. Cross-origin no-cors GET/HEAD loads can omit it, and redirects or some referrer policies can produce null.
What is the difference between Origin and Referer?
Origin has no path or trailing slash. Referer is a URL that may include a path and query, but referrer policy can reduce it to an origin or omit it entirely.
Can Origin be spoofed?
Browser scripts cannot set Origin, but non-browser clients can. CORS is a browser response-sharing mechanism, not API authentication.
Sources
Related
Sec-Fetch-Site Header: Block Cross-Site Requests
Sec-Fetch-Site says whether a request is same-origin, same-site, cross-site or user-initiated. Resource isolation policy for Express and nginx, plus CSRF use.
Origin (Scheme, Host, Port)
An origin is the scheme, host and port of a URL. See how browsers compare origins for the same-origin policy, CORS and the Origin header, with examples.
Same-Site vs Same-Origin
Site and origin are not the same. Learn how eTLD+1 and the Public Suffix List define same-site, and why it decides SameSite cookie and CORS behavior.
Access-Control-Request-Headers Header
Learn how Access-Control-Request-Headers tells servers which custom headers will be used in CORS requests. Essential for preflight request handling.