Fetch Metadata Adds Request Context to Server-Side Policy

A server often sees the same authenticated cookie on requests created by very different browser actions. A form submitted from another site, a same-origin API call, an image load, and a top-level navigation can all reach the same host. Cookies alone do not describe that request context.

Fetch Metadata adds browser-generated request headers that describe where a request came from and how the browser intends to use the response. A server can incorporate those signals into an isolation policy before application logic handles a sensitive route.

Sec-Fetch-Site: cross-site
Sec-Fetch-Mode: no-cors
Sec-Fetch-Dest: image

These headers do not authorize a principal. They provide context for a separate server-side decision.

The four core headers describe different dimensions

The Fetch Metadata request headers are Sec-Fetch-Site, Sec-Fetch-Mode, Sec-Fetch-Dest, and Sec-Fetch-User.

Sec-Fetch-Site describes the relationship between the initiator and target. Its common values are same-origin, same-site, cross-site, and none. The none value covers requests without a requesting site, such as some direct user navigations.

Sec-Fetch-Mode reports the request mode, including values such as navigate, cors, no-cors, same-origin, and websocket.

Sec-Fetch-Dest describes the intended destination. Values such as document, image, script, and empty let a server distinguish a document navigation from a subresource or API-style fetch.

Sec-Fetch-User is present with ?1 when a navigation is associated with user activation. Its absence is not equivalent to a failed authentication check; it simply means that signal is not present for the request.

Because these names use the Sec- prefix, browser page scripts cannot freely set or modify them as ordinary request headers.

A policy starts with endpoint intent

A useful policy is based on what an endpoint is meant to accept. Consider an authenticated JSON route that is only called by same-origin application code. A cross-site image load has no legitimate reason to reach that route, even if the browser attaches cookies.

A compact rule can reject that mismatch:

if Sec-Fetch-Site == cross-site
and route is not explicitly cross-site:
    reject

Production rules usually need more detail. Public resources, federated login callbacks, webhook endpoints, CORS APIs, and top-level links can intentionally receive traffic from outside the site. A blanket rejection of every cross-site request would break valid flows.

The policy therefore belongs beside an endpoint inventory, not as an isolated middleware switch.

Same-site is not always the same trust boundary

same-site is broader than same-origin. Two sibling subdomains can be same-site while running software with different operators, deployment controls, or exposure.

An application that treats every same-site request as trusted effectively places those sibling origins inside one browser-facing trust boundary. That can be appropriate for tightly controlled infrastructure, but it should be a deliberate decision.

For sensitive routes, allowing same-origin and evaluating same-site separately creates a narrower default.

Cross-site navigation is normal web behavior. A user can click a link on one site and arrive at another. A policy that rejects all cross-site requests would block that basic path.

For routes intended to serve pages, a policy can distinguish a top-level navigation from a subresource request by combining metadata fields. For example, a GET request with Sec-Fetch-Mode: navigate and Sec-Fetch-Dest: document has a different purpose from a no-cors image request aimed at the same URL.

Method checks still matter. Treating every navigation as safe would be a mistake if an application performs state changes on GET. Safe HTTP semantics remain part of the boundary.

Missing headers require an explicit compatibility choice

Not every client is a browser that sends Fetch Metadata. Command-line clients, server-to-server integrations, older clients, and specialized user agents can omit the headers.

A deployment must define what omission means. One service may permit missing metadata only on documented machine endpoints. Another may allow it temporarily while measuring browser coverage. A high-risk browser-only route may choose a stricter fallback.

The important property is that absence is handled intentionally. Silently treating a missing header as same-origin converts a compatibility fallback into a trust grant.

Fetch Metadata complements CSRF controls

Fetch Metadata can reject many requests whose browser context conflicts with an endpoint’s intended use, including cross-site requests involved in CSRF patterns. It should not be treated as a replacement for every CSRF control.

Applications can still need SameSite cookie settings, anti-CSRF tokens, Origin or Referer validation, reauthentication for sensitive actions, and correct authorization. The exact set depends on the request model.

Fetch Metadata is especially useful as an additional server-side gate because the decision can happen before parsing a large request body or invoking sensitive application logic.

Cache behavior must match the policy

If a response can differ according to request metadata and a shared cache sits in front of the application, cache behavior deserves review. A cache that ignores the relevant request headers can reuse a response in a context the origin server would have treated differently.

Where responses vary on Fetch Metadata, the cache key or Vary behavior must match the deployment architecture. This is not a reason to add every metadata header to every response. It is a reason to align cache configuration with the fields that actually affect response selection.

Rollout works best in observation first

A new isolation rule can expose hidden integrations. Before enforcing rejection, log the metadata tuple, route, method, decision, and a bounded amount of diagnostic context. Do not log session secrets or full authorization credentials.

The observation period can reveal endpoints that legitimately accept cross-site navigations, CORS traffic, embedded resources, or non-browser clients. Those exceptions can then be made explicit.

After enforcement starts, rejected requests should remain observable. A sudden rise in denials can indicate an attack pattern, a client regression, or an incomplete route inventory; the status code alone cannot distinguish them.

Request context is a gate, not identity

Fetch Metadata gives the server browser-supplied context about a request. It does not prove which user is entitled to an object, whether a session is still valid, or whether a state transition is permitted.

That separation keeps the control precise. Authentication establishes identity. Authorization governs access. CSRF defenses protect state-changing browser requests. Fetch Metadata lets the server reject browser contexts that should never have reached a route in the first place.

A strong deployment keeps those roles separate, documents intentional cross-site paths, treats same-site as a conscious trust decision, and defines a safe fallback for clients that do not send the headers.