Decide whether the browser needs cross-origin access
A partner says its dashboard cannot call your customer API because the browser reports a CORS error. Start by drawing the actual request: which page origin runs the JavaScript, which API origin receives it, which data is returned, and whether the request carries a cookie or other credential. An origin consists of scheme, host and port; a different subdomain or port is a different origin. CORS is the browser mechanism that decides whether script at one origin may read a response from another. It is not a way to identify the partner, grant an account permission, or prove that the requested record belongs to that account. Those decisions still belong in the API.
Ask whether a browser call is necessary at all. If the partner operates a trusted server that already exchanges tokens with your server, a server-to-server call does not depend on browser CORS. If its own staff must interact with your API directly from a dashboard, browser access may be appropriate, but the token exposure, request scope and user permissions need explicit design. Document the exact production dashboard origin and any controlled test origin. Do not start from a wildcard merely because it makes a demonstration work; deciding the intended readers first makes the response policy intelligible to both businesses.
Separate public catalogue data from private customer or order data before configuring headers. A genuinely public, anonymous endpoint can sometimes allow any origin to read its response, with its availability and abuse controls assessed separately. A response tied to an authenticated user is a different decision. Allowing a known origin does not make every request from that origin trustworthy, and a script can be changed or a user account compromised. Keep server authentication, record-level authorization, input validation and operational limits in place. The useful handoff to the developer is an endpoint-by-endpoint access matrix, not a single switch for the entire domain.
Choose response headers that match the request
For one approved dashboard, return its exact origin in Access-Control-Allow-Origin on the relevant API responses. When the server chooses a value from an allowlist according to the incoming Origin, also send Vary: Origin so an intermediary cache knows the response differs by requester. Reject an unknown origin rather than reflecting whatever string arrived. An absent Origin on a direct server call has a different meaning from an approved browser origin; do not treat it as a secret bypass route. Review success and error responses, since a partner needs to handle an authorized 404 or validation error without an opaque browser failure.
If the browser must include credentials, the response needs a specific allowed origin and Access-Control-Allow-Credentials: true. The wildcard origin does not work with credentialed browser requests. The client must also make its credentials choice deliberately; cross-origin fetch does not include credentials by default. Even correct CORS headers cannot override browser third-party cookie restrictions. For an API using bearer tokens in an Authorization header, avoid assuming cookie advice applies unchanged: map the actual credential path and make the authorization check independent of CORS. Never put a secret API key in downloadable JavaScript simply to avoid a proxy or server exchange.
A request using certain methods or headers triggers a browser preflight: an OPTIONS request asks which method and headers are allowed before the actual operation. Its Access-Control-Request-Method and Access-Control-Request-Headers describe the proposed call. Respond only with the methods and headers this endpoint accepts; do not copy a global allow-all list. The preflight itself is not the order update and normally has no application credential, so do not demand the normal authenticated business operation from OPTIONS. The subsequent request must still authenticate and authorize, and must receive the proper CORS response headers in its own response.
Consider what the browser is allowed to read when an endpoint exposes custom response headers. The body may be readable while a header needed for pagination or diagnostics is not available to partner JavaScript unless it is exposed appropriately. Decide whether that header is part of the public API contract, then list only the needed header names. Do not expose internal trace identifiers, cookies or debugging details merely because the integration asks for every header. Have the partner show the precise JavaScript field it needs and test that field in a browser; this separates a response-sharing problem from an application parsing problem.
Walk through a partner dashboard example
Imagine an SME exposes a read-only stock lookup to a partner dashboard at https://dashboard.partner.example, while its API lives at https://api.shop.example. These names are illustrative, not real approved origins. The dashboard requests JSON with an Authorization header. The browser may preflight that header, so the team tests both the OPTIONS exchange and the actual GET. The response permits that one dashboard origin, the required method and header, and varies on Origin. The API still checks that the token may see the requested stock group. A second, unrelated website receives no permission to read the response, even if it knows the URL.
Now imagine the partner adds a preview site on a different subdomain. Its exact origin is a new entry to review, not an automatic extension of the production approval. Determine who owns it, whether it serves real customer data, and when its access ends. A pattern that matches every subdomain can silently include forgotten or user-controlled hosts. If the preview needs only sample records, use an isolated test API or test identities rather than making production data broadly readable. Record the expiry of temporary origins and remove them during the integration handover, with a named owner for the allowlist.
A successful command-line request is insufficient proof. Tools that are not browsers do not enforce browser CORS, and an OPTIONS response that looks correct may be followed by a GET with missing headers. Conversely, a blocked response may still indicate that a state-changing request reached the server; CORS does not substitute for request forgery protection. Test from the actual partner page or a controlled page at the same origin, watch the browser network panel, and compare what the server logged. Distinguish a preflight rejection, an authentication failure, a redirect and a blocked readable response before changing settings.
Test the boundaries and maintain them
Build a small test matrix with the approved production origin, any temporary test origin, an unknown origin, and a credentialed versus anonymous request. For each, record the expected browser result, the actual status and relevant response headers. Include an authorized response, a denied record, an expired token and a server error. Inspect Vary: Origin through any CDN or proxy that caches API responses; if caching mixes allowed origins, the right application logic can still produce confusing or unsafe delivery. Keep this test in the release checklist whenever API gateways, authentication or partner domains change.
Do not diagnose every browser failure as CORS. A DNS mistake, TLS failure, network timeout, rejected authentication and unhandled preflight are separate failures with different fixes. The browser console and network panel show which exchange failed, while the API logs show whether any request arrived. If JavaScript reports a generic network error, inspect the actual HTTP exchange rather than loosening headers until the error disappears. Ask the partner to provide the page origin, request method, request headers, credentials setting, time and response status without sending live tokens or customer data through an informal support channel.
The operational decision is a narrow, documented grant of browser readability for named endpoints and origins. Name who can approve a new origin, who tests it, and who removes access when the partnership ends. Keep an example request and expected headers next to the API contract. When a new feature changes from public lookup to personalized data, review the CORS rule together with authentication, authorization and cache behavior. That small review prevents a convenient integration setting from quietly becoming the security policy for unrelated customer records.
Treat a change to the allowlist like an access change with a rollback plan. Before deployment, capture the current approved origins and a known working browser request. After deployment, check both that the new partner works and that an unrelated origin remains blocked from reading the response. If the gateway adds headers while the application also adds them, inspect the final response for contradictory values rather than guessing which layer wins. When rolling back, restore the previous narrow list and repeat the negative test. This sequence is especially useful when a rushed partner launch overlaps a proxy or CDN configuration change.
Before you proceed
- List exact page and API origins and the endpoints that need browser reads.
- Verify preflight, actual response, authentication and authorization separately.
- Test allowed and unknown origins through the real browser and intermediary cache.


