You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 1af2903
Browse filesBrowse the repository at this point in the historyBrowse files
docs(cors): state the transport's CORS default and the one variable an operator sets
HARDENING.md § CORS, the deployment pages and the plugin README now state
what the CORS answer admits with and without an origin list, that '*' with
credentials is refused at boot, and that OS_TRUSTED_ORIGINS is auth's list,
not CORS's. Changeset for @objectstack/plugin-hono-server.
Claude-Session: https://claude.ai/code/session_01LmjU2x1faLZ39DVTFyVca6
Co-authored-by: Claude <noreply@anthropic.com>
fix(plugin-hono-server)!: the CORS default admits no cross-origin caller, and `'*'` with credentials is refused at boot
6
+
7
+
Clause-②: no (narrowing)
8
+
9
+
<!-- adr-0087: not-required (no-migration-prescription) a narrowing of the transport's CORS admission default plus a boot refusal of one configuration: no authorable metadata key, spelling, export, type or stored shape moves, so `objectstack migrate meta` has nothing to rewrite. The remedy is a deployment variable, which no ledger entry can derive. The other categories are closed on facts: the package publishes (not unpublished); no ADR-0087 id covers this door (not already-registered); and the change is an admission verdict, not an interface, a type or an export (not runtime-interface-only, type-surface-only or runtime-export-retired). -->
10
+
11
+
**BREAKING** — an admission narrowing of the transport's CORS answer, shipped as `minor` under the launch-window convention for accept-set narrowings. The governing text is `docs/HARDENING.md` § CORS: never `'*'` with credentials, and an explicit origin list.
12
+
13
+
-**Before.** With no origin list configured (no `cors.origins` option and no `OS_CORS_ORIGIN`), the CORS middleware admitted every origin for credentialed cross-origin requests. A configured `'*'` with credentials on was accepted and answered the same way.
14
+
-**Now.** With no list, no cross-origin caller is admitted. A loopback origin (`localhost`, `127.0.0.1`, `[::1]`, any port) is admitted on a development boot only: `NODE_ENV` exactly `development`, which `os dev` and `os serve --dev` set. A list that contains `'*'` while credentials are on is refused in `init()`, so the boot fails, and the message names both remedies.
15
+
-**Unchanged.** Same-origin requests need no CORS answer, so the Console under `/_console` and every page the server itself serves work as before. A configured list, exact origins or wildcard patterns, is admitted exactly as before, credentials included. `'*'` with credentials off still boots. `cors: false` and `OS_CORS_ENABLED=false` still disable the middleware. Allowed and exposed headers, methods and max-age are unchanged.
16
+
17
+
**What an operator does.** A front-end served from another origin that calls this server is now named: `OS_CORS_ORIGIN=https://app.example.com` (comma-separated for several), or the plugin's `cors.origins` option. A boot that now refuses `'*'` either names its origins or sets `OS_CORS_CREDENTIALS=false` to keep serving `'*'` without credentials. `OS_TRUSTED_ORIGINS`, auth's callback and CSRF list, admits nothing to CORS: a cross-origin front-end that signs in belongs in both lists.
|`OS_CORS_ORIGIN`| csv |—|Origins admitted to cross-origin requests: exact origins or patterns such as `https://*.example.com`, comma-separated. Unset, no cross-origin caller is admitted (loopback origins excepted on a development boot); same-origin requests, the Console included, need no entry. `*` is refused at boot unless `OS_CORS_CREDENTIALS=false`. |
127
+
|`OS_CORS_CREDENTIALS`| boolean |`true`| Allow credentialed cross-origin requests from the admitted origins. Must be `false` to serve `OS_CORS_ORIGIN=*`. |
128
128
|`OS_CORS_MAX_AGE`| number |`86400`| Preflight cache TTL in seconds. |
CORS is intentionally **not** opinionated by the runtime — it's an
196
-
app-level policy that depends on which origins host your front-end.
197
-
Configure it on the Hono adapter:
195
+
Which cross-origin callers are admitted is an app-level decision — it
196
+
depends on which origins host your front-end — so the server that
197
+
`os serve` / `os start` mount (`HonoServerPlugin`) admits only the
198
+
origins you name:
199
+
200
+
| Configuration | What is admitted |
201
+
| --- | --- |
202
+
| No origin list (neither `OS_CORS_ORIGIN` nor the plugin's `cors.origins`) |**No cross-origin caller.** On a development boot (`NODE_ENV=development`, which `os dev` and `os serve --dev` set), loopback origins (`localhost`, `127.0.0.1`, `[::1]`, any port) are admitted too. |
203
+
| A list (`OS_CORS_ORIGIN=https://app.example.com`, comma-separated; exact origins or patterns such as `https://*.example.com`) | Those origins, with credentials unless `OS_CORS_CREDENTIALS=false`. Loopback origins are admitted alongside any list. |
204
+
|`*` while credentials are on |**Refused at boot** — the process exits naming the two remedies. |
205
+
206
+
Same-origin requests need no CORS answer, so the Console under
207
+
`/_console` and any page the server itself serves work with no list at
208
+
all. A front-end served from **another origin** needs exactly one
209
+
variable:
210
+
211
+
```bash
212
+
OS_CORS_ORIGIN=https://app.example.com
213
+
```
214
+
215
+
`OS_TRUSTED_ORIGINS` is a different list — the origins auth accepts for
216
+
its callbacks and CSRF checks — and admits nothing to CORS. A
217
+
cross-origin front-end that signs in belongs in both.
218
+
219
+
Composing the Hono adapter yourself, name the origins there as well:
198
220
199
221
```ts
200
222
import { createHonoApp } from'@objectstack/hono';
@@ -209,9 +231,10 @@ const app = createHonoApp({
209
231
});
210
232
```
211
233
212
-
Do **not** use `origin: '*'` with `credentials: true` — the
213
-
combination is rejected by every modern browser anyway, but the
214
-
misconfiguration is a common red flag in audits.
234
+
Do **not** use `origin: '*'` with `credentials: true`: together they
235
+
admit every origin for credentialed requests. `HonoServerPlugin`
236
+
refuses the combination at boot; `*` is accepted only with credentials
237
+
off (`OS_CORS_CREDENTIALS=false`), for an API that takes no cookies.
0 commit comments