cswork / libraryOpen practice workspace

Articles

CORS Interview Questions: Preflight Requests, Credentials, and Debugging

Understand CORS interview questions through preflight traces, credentials, browser debugging, security boundaries, and practical request-response examples.

CORS interview questions test whether you can reconstruct what the browser sent, what the server allowed, and why JavaScript could or could not read the response. Cross-Origin Resource Sharing is a browser-enforced response-sharing protocol. It is not authentication, and a CORS error does not always mean the underlying request never reached the server.

The fastest useful explanation starts with an origin: scheme, host, and port. https://app.example.com and https://api.example.com are different origins even though they share a parent domain. This guide follows an original request trace and then changes one condition at a time to expose the common traps.

Here, the goal is a precise debugging answer, not a collection of headers to paste into every response.

What problem does CORS solve?

The same-origin policy limits how scripts from one origin access resources from another. CORS provides a controlled way for a server to permit cross-origin response sharing. The browser evaluates the relevant request and response conditions before exposing the response to the requesting script.

That distinction explains a familiar puzzle: an API works in a command-line client but fails from a web page. The command-line client is not enforcing the browser's same-origin policy. Its success proves reachability and perhaps authentication, not that the API's browser-facing CORS policy is correct.

Nor does a successful CORS check prove the user has permission to access the resource. The server still needs authentication, authorization, input validation, and ordinary security controls. An allowed origin is not a user identity.

A concise interview answer is: "CORS decides whether a browser may share a cross-origin response with this script; the API independently decides whether the request is authorized." Keep those two decisions separate throughout the discussion.

When does the browser send a preflight request?

Some cross-origin requests require a preliminary OPTIONS request. The browser describes the intended method and relevant request headers, and the server responds with the permissions it allows. If that check fails, the browser does not proceed with that preflight-dependent actual request.

Not every cross-origin request needs preflight. Requests meeting the CORS-safelisted conditions can be sent directly. A POST is not automatically preflight-free: a JSON content type or an Authorization header commonly changes the request into one requiring preflight.

Request shapeTypical preflight?Key reason
GET with only safelisted headersNoMeets the basic safelisted conditions
POST with application/jsonYesContent type is not safelisted
Request with Authorization headerYesHeader is not safelisted
PUT requestYesMethod is not safelisted
Safelisted request with cookiesNot solely because of cookiesCredentials and preflight are separate checks

This table assumes an ordinary CORS fetch without additional browser or network policies that alter the situation. An interview answer should inspect the actual request rather than infer everything from the method name.

Also remember caching. A missing OPTIONS row on a later attempt does not prove the request never required preflight; a valid preflight permission can be cached. Reproduce with awareness of the browser's preflight cache and the server's configured maximum age.

Can you walk through a JSON POST from start to finish?

Suppose a page at https://app.example.com sends JSON to https://api.example.com/orders. These are illustrative domains, not instructions to contact a real service. Assume no cookies or authentication for this first trace.

OPTIONS /orders HTTP/1.1
Origin: https://app.example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type

An allowed preflight response could include:

HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Content-Type
Vary: Origin

The browser can then send the JSON POST. Crucially, the actual response also needs the appropriate CORS response headers. A valid OPTIONS response does not give the application permission to omit them from the POST response.

Now change only the actual response: the server creates the order but forgets Access-Control-Allow-Origin. The browser may reject access to the response while the order already exists. Retrying blindly can create a duplicate unless the application has an idempotency design.

This is the central debugging question: did the actual request happen, or did the preflight stop it first? The answer changes both the server investigation and whether retrying is safe.

What changes when cookies or credentials are involved?

For a credentialed cross-origin fetch, the request's credentials mode and the server's CORS response must agree. The server cannot use wildcard Access-Control-Allow-Origin: * to expose a response to a request whose credentials mode is include. It needs an allowed explicit origin and Access-Control-Allow-Credentials: true.

fetch("https://api.example.com/profile", {
  credentials: "include"
});

This option does not force every cookie to be sent. Cookie attributes, same-site rules, browser privacy policy, and other conditions still apply. Cross-origin and cross-site are related but different concepts; subdomains can be different origins while belonging to the same site.

A useful test matrix separates three questions: was a cookie eligible and sent, did the server accept the session, and did the browser expose the response? A login failure, a missing cookie, and a CORS-sharing failure can look similar to a user but require different fixes.

Preflight requests are generally sent without credentials. Requiring a session cookie on OPTIONS can therefore block the permission check before the actual authenticated request is attempted. Configure the preflight route deliberately while retaining authentication on the actual protected endpoint.

Why is reflecting any Origin header dangerous?

A server should validate an incoming origin against a deliberate policy before returning it as allowed. Blindly echoing arbitrary origins, especially with credentials enabled, can grant untrusted websites access to sensitive responses when other conditions permit the request.

Do not implement an allowlist with a loose substring check. The string trusted.example appearing somewhere inside a hostname is not proof that the origin belongs to that domain. Compare parsed origins against exact intended values, including scheme and port where relevant.

Avoid treating the literal origin null as a harmless default. Various sandboxed or opaque-origin contexts can produce it. Allowing it needs a specific security rationale, not a desire to silence a development error.

When a response varies by Origin, include appropriate cache variation so one origin's response policy is not incorrectly reused for another. Check the CDN or reverse proxy as well as application middleware; headers can be added, removed, or duplicated at multiple layers.

How do CORS, CSRF, XSS, and authentication differ?

These terms describe different boundaries. CORS governs browser response sharing. CSRF involves unwanted authenticated actions induced from another site. XSS involves untrusted script executing in a trusted origin. Authentication establishes identity; authorization decides what that identity may do.

MechanismMain questionWhat it does not replace
CORSMay this origin read the response?Authentication or authorization
CSRF protectionIs this state-changing request legitimate?Output encoding and XSS defenses
XSS defensesCan untrusted input become executable script?Server-side access checks
AuthorizationMay this caller perform this action?Browser origin policy

Some cross-origin requests can be sent without preflight, even when the browser will not expose their response. That is why "we block CORS, so CSRF is impossible" is not a safe general claim.

Likewise, if malicious script already runs in an allowed origin through XSS, a CORS allowlist does not restore the trust that origin has lost. Explain the threat model before recommending a header. Security controls should complement one another rather than being treated as interchangeable switches.

How would you debug a real CORS error?

Start in the browser's Network panel. Record the page origin, target URL, method, request headers, credentials mode, and whether an OPTIONS request appears. Inspect the actual response status and headers, not only the console's abbreviated error text.

If OPTIONS fails, check route handling, allowed method, allowed headers, redirects, and any middleware that demands authentication too early. If OPTIONS succeeds but the actual request fails, inspect the actual response's CORS headers and application error path.

A common failure is inconsistent middleware placement: successful responses receive CORS headers, but a 401, 403, or 500 response does not. The visible browser error then conceals an authentication or server failure. Server logs can identify that underlying status without assuming the CORS message is the root cause.

Check every hop. A proxy might generate its own error response before the application runs. A CDN might cache an origin-specific response incorrectly. Two components might add duplicate allow-origin headers that are not a valid single-origin value.

Change one variable at a time and preserve a minimal reproduction. A command-line request with an Origin header can help inspect server behavior, but it does not simulate browser enforcement. Finish by retesting the same request from the browser origin that originally failed.

Why is mode: no-cors usually not the fix?

no-cors does not ask the browser to ignore CORS restrictions and expose the response. It restricts the request and generally produces an opaque response for cross-origin fetches, so JavaScript cannot read its body or ordinary status details as if it were a normal API response.

If the application needs JSON from the API, making the response opaque does not solve the requirement. Nor should you tell users to disable browser security. That changes the testing environment and leaves the real deployment broken.

The right fix belongs at an authorized server, gateway, or architectural boundary: return a correct policy for approved origins, use a same-origin backend when appropriate, or choose an API intended for browser access. A public third-party CORS proxy is not a safe default for private tokens or user data.

In an interview, state the legitimate constraint. If you do not control the target server and it does not permit browser sharing, there may be no purely frontend header change that grants access. Client code cannot award itself server permission.

What follow-up cases distinguish a strong answer?

Can JavaScript read every response header after CORS succeeds? No. Non-safelisted response headers may need Access-Control-Expose-Headers. For example, an application reading a custom request-ID header should check that exposure policy separately from allow-origin.

Does allowing an origin mean allowing every HTTP method? No. Preflight evaluates the intended method and relevant headers. Keep policy aligned with actual endpoint needs instead of granting broad permissions by habit.

Why does development work but production fail? Compare the complete origin, including scheme and port, and the actual proxy path. An allowlist for http://localhost:3000 says nothing about https://app.example.com.

Can a CORS error still accompany a successful server-side write? Yes, when the actual request was sent but response sharing failed. Inspect the sequence and use application-level idempotency for retryable writes.

These answers work because they distinguish sending, authorizing, executing, and reading. Keep those verbs separate and the problem becomes much easier to reason about.

Practice one request until you can explain every hop

Create an original test matrix for a local frontend and API you control. Vary JSON versus a safelisted content type, an extra request header, credentials mode, explicit versus wildcard origin, and an application error response. Predict both network activity and JavaScript visibility before testing.

For each failure, write a one-line diagnosis naming the layer: preflight permission, actual response sharing, cookie eligibility, authentication, or application logic. Do not accept "CORS issue" as a complete explanation.

A useful answer ends with a narrow server-side policy and a verified browser trace, not a blanket wildcard or a disabled security setting.

Sources and Further Reading

Checked September 23, 2026. Examples use illustrative domains and ordinary Fetch/CORS behavior; browser privacy policies can impose additional constraints.