DEV Community

Jeff
Jeff

Posted on Originally published at powerduck.com

The Embedded Try-It Console: CORS and Tokens in a Portal vs Static

Quick answer

An embedded try-it console looks like a simple convenience, but it makes real cross-origin requests and has to handle CORS, credential storage, and token attachment. When the API does not allow the docs origin, the console fails with a browser CORS error that has nothing to do with the API itself; when tokens are stored carelessly, the playground becomes a place users leak credentials. Static references that show example requests avoid the cross-origin problem entirely but cannot execute. Choose the interactive console only when you can configure the API's CORS policy and keep token handling explicit, and treat "it works in the hosted portal" as a deployment concern you must verify rather than assume.

Why CORS appears in a docs page

The console runs JavaScript in the browser on the docs origin, so a request to the API is a cross-origin call unless the two share an origin. The browser enforces a preflight and the API must answer with the right headers.

Required response Purpose
Access-Control-Allow-Origin Permits the docs origin specifically
Access-Control-Allow-Methods Allows the verbs the console uses
Access-Control-Allow-Headers Permits Authorization and custom headers
Access-Control-Allow-Credentials Needed when cookies carry the session

A missing or wildcard-with-credentials mismatch produces a browser error that hides the real response, which is why the console can appear broken while the API is healthy.

Token handling in the playground

Users paste a bearer token to authenticate an interactive request. The console should hold it in memory for the session, never persist it to storage, and never include it in telemetry. Prefer a login flow that obtains a short-lived token over asking users to paste a long-lived one.

Add a clear affordance to clear the token, and reset it when the page unloads so a later user on a shared machine does not inherit the prior session.

Interactive console versus static reference

Aspect Interactive console Static example
Executes real requests Yes No
CORS dependency Required None
Credential handling Real tokens at risk Example placeholders only
Best for Authenticated exploration Safe learning and copy/paste
Failure surface Browser policy and network Rendering only

A practical pattern is to keep static examples next to every operation and add an interactive console only for a sandbox or staging API that carries no production data, so the convenience exists without exposing real credentials or coupling to production CORS.

Using a sandbox origin safely

Point the console at a dedicated sandbox API with test credentials, and scope the CORS allowlist to the exact docs origin rather than reflecting any origin. Rotate the shared sandbox token and document that it is disposable. This gives users a real execution path while keeping production tokens out of the browser and making the CORS policy narrow and auditable. If a request must reach production, require an explicit per-session login and a short-lived token, never a stored credential.

Preflight caching and error visibility

Browsers cache preflight responses based on the Access-Control-Max-Age header, which normally reduces redundant requests but can hide a policy change during deployment. If you update the allowed headers or origin and the console keeps failing, the cached preflight may be stale; verify with a fresh session or a cache-disabled browser before concluding the API is wrong. Make error messages distinguish the two very different failures a user can hit: a CORS rejection means the browser blocked the request before it completed, while a 401 or 403 means the request reached the API and the credential or permission was rejected. Surfacing that distinction in the console prevents wasted debugging, because the fix for a missing CORS header is entirely different from the fix for an invalid token. In support tooling, capture the response headers and the failing origin so a policy problem can be diagnosed without asking the user to open a low-level network panel.

Verification before release

Test the console in a real browser against the deployed docs origin, not just in a local same-origin preview, because CORS only manifests across origins. Confirm the preflight succeeds, an authenticated request attaches the token correctly, an unauthenticated one fails with a clean 401 rather than a CORS error, and no token appears in logs or telemetry. These checks belong in the deployment gate for the docs site.

FAQ

Why does the console fail in the browser but curl works?

curl does not enforce the same-origin policy, so it bypasses the preflight the browser requires. The API may be perfectly healthy; the issue is the missing CORS headers that only the browser checks.

Is it safe to let users paste a token?

Only if it is held in memory, never persisted or logged, and can be cleared. A login that issues a short-lived token is safer than asking for a long-lived secret, which can be exposed through the browser or telemetry.

Can I avoid CORS by proxying through the docs server?

Yes, a same-origin server-side proxy can forward requests and attach credentials, which moves CORS off the browser, but the proxy then becomes a privileged component that must validate targets and protect credentials, so it needs the same security review.

Should the console call production by default?

No. Default to a sandbox or staging API with disposable data, and require explicit authentication for any production call. This keeps experimentation safe and limits the blast radius of a pasted token.

This is part of the Powerduck vs Redocly: OpenAPI Docs and Linting — start there for the full docs and portal comparison.

Top comments (0)