API & webhooks
The CORS Origin Header: Compare Scheme, Host and Port
Understand the browser Origin header, compare exact origin identities, and avoid path-based, substring or blindly reflected allowlist decisions.
An origin is not a complete page URL
A browser origin identifies a scheme, host and effective port for ordinary HTTP and HTTPS URLs. It does not include the page's path, query or fragment. Two pages on the same origin can have very different paths while sharing the same origin identity.
For example, https://app.example.com/editor and https://app.example.com/settings belong to the same ordinary origin. Changing the scheme to http or using a different non-default port changes that identity. An allowlist intended for one origin should not accidentally accept those alternatives.
Normalize trusted URL configuration deliberately
function configuredOrigin(value) {
const url = new URL(value);
if (!/^https?:$/.test(url.protocol) || url.username || url.password) {
throw new Error("Use an HTTP(S) URL without credentials.");
}
return url.origin;
}
function exactOriginAllowed(origin, trustedOrigins) {
return typeof origin === "string" && trustedOrigins.has(origin);
}
The first helper is for trusted configuration when the application is deliberately given a URL and needs its origin. The second compares a supplied serialized origin against a Set of trusted serialized origins. Do not run arbitrary request text through permissive URL transformations and silently broaden what the policy accepts.
For a configured URL https://app.example.com:443/editor, the first helper returns https://app.example.com because 443 is the default HTTPS port. A configured URL using port 8443 retains that port. Test both cases rather than comparing raw configuration strings with inconsistent spelling.
Reject lookalike hosts instead of searching for a substring
A test such as origin.includes("example.com") is not an origin policy. It can match an unrelated hostname containing those characters. Likewise, accepting every host whose text begins with https://app.example.com can accidentally include a longer attacker-controlled hostname.
Use exact membership for a fixed list. If a service intentionally supports a domain pattern, define and test that pattern at the parsed host boundary with the required scheme and ports. Avoid turning a convenient string search into a broader permission than the owner intended.
Document who can update that configuration and review newly added origins as changes to the sharing policy.
The Origin header reference explains the serialized value and situations involving the literal null. It is distinct from Referer, which can contain different information under its own policy.
Treat null and missing origins as separate cases
Some browser contexts have an opaque origin and can serialize it as null. That text does not identify one trusted application. Allowing null broadly can cover multiple unrelated contexts, so do not add it to an allowlist merely to silence a local-file experiment.
A missing Origin field is another condition. It is not automatically the same as null, and it is not proof that a request is trusted. A service can have a policy for non-browser clients while still enforcing the endpoint's actual authentication and authorization rules.
Origin checking does not authenticate the caller
Browser JavaScript does not freely choose its Origin header in the same way it chooses a normal custom request field. However, a non-browser client can construct its own HTTP messages. A server must not treat an allowed origin string as a substitute for a valid session or token.
The forbidden request-header reference describes the browser-controlled boundary. Keep that restriction separate from the server's trust model and from any reverse proxy configuration that affects request processing.
Test the exact identities and response policy
Use fixtures for the allowed origin, a different scheme, a different port, a lookalike suffix, null and a missing value. Assert exact inclusion or rejection according to the policy. If generating Access-Control-Allow-Origin dynamically, also make the response's caching variation appropriate for that decision.
The CORS Header Checker can compare a pasted response token with an origin you supply. It cannot establish who sent a request or prove that an origin is authorized by your business rules. Verify those decisions in the service's own policy tests.


