From 593870c36e98f16bb8f27b58a769e2179962759f Mon Sep 17 00:00:00 2001 From: sdarbinyan Date: Thu, 27 Aug 2026 09:35:12 +0400 Subject: [PATCH] docs(backend): enrich CORS incident with root-cause detail from vitanovaPackages Pulled the fuller detail from vitanovaPackages/BACKEND-TODO.md (root-caused 2026-08-24, more precise than this file's original note): it's an origin allowlist gap specifically (novo.market works, gorbushka doesn't), plus the X-Marketplace-Domain header requirement, the qr.vitanova.network allowlist question, the Retry-After rate-limit contract, and ed25519's dead-export status. None of that was here before. Also documents that backend TODOs are NOT fully consolidated: this file is canonical for marketplaces, but vitanovaPackages/BACKEND-TODO.md is a separate file in a separate repo and stays the source of truth for package-level backend asks - mirrored here, not merged away. --- docs/backend/BACKEND-INTEGRATION.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/docs/backend/BACKEND-INTEGRATION.md b/docs/backend/BACKEND-INTEGRATION.md index 7319862..416f82c 100644 --- a/docs/backend/BACKEND-INTEGRATION.md +++ b/docs/backend/BACKEND-INTEGRATION.md @@ -48,9 +48,13 @@ Auth lives in `@marketplaces/auth` (published from vitanovaPackages; see `../PAC **The critical gap:** the session API has no concept of "admin." The frontend only chooses where to *store* the result. **Every admin endpoint must independently verify authorization server-side** — client-side guards are UI convenience, never security. Admin requests carry `AdminWebSessionID: ` (and `Authorization: Bearer ` once admin JWTs exist) on paths containing `/admin/`, `/backoffice/`, `/builder/`, `/media/`. -**🔴 LIVE INCIDENT — Telegram QR/session CORS blocks all admin and customer login (found 2026-08-26).** `POST https://users.vitanova.network:456/users/sessions` returns `403` for every origin tested — `https://gorbushka.market`, `https://admin.gorbushka.market`, `https://store1.gorbushka.market` — both on the actual request and on the `OPTIONS` preflight, with zero `Access-Control-Allow-*` headers in the response. This is the endpoint marked "live" above; it is not currently usable from any storefront or admin origin, so Telegram login (the *only* working admin auth method) is fully broken in production right now. Needs the CORS allowlist on that service updated to include the storefront/admin origins — same root cause already flagged in the `vitanovaPackages` PR `fix/auth-payment-origin-decouple`. +**🔴 LIVE INCIDENT — Telegram QR/session CORS blocks all admin and customer login (found 2026-08-26, root-caused 2026-08-24 in `vitanovaPackages/BACKEND-TODO.md` — fuller detail there, canonical copy here).** `POST https://users.vitanova.network:456/users/sessions` returns `403` for every gorbushka origin tested — `https://gorbushka.market`, `https://admin.gorbushka.market`, `https://store1.gorbushka.market` — both on the actual request and on the `OPTIONS` preflight, with zero `Access-Control-Allow-*` headers. This is a server-side **origin allowlist**, not a blanket CORS failure: `https://novo.market` gets a clean `204` with `Access-Control-Allow-Origin`, `-Headers: *`, `-Methods`, `-Credentials: true` — gorbushka's origins are simply not on the list. This is the endpoint marked "live" above; it is not currently usable from any gorbushka storefront or admin origin, so Telegram login (the *only* working admin auth method) is fully broken in production right now. -**Admin credential (login/password) auth — required, not yet built.** `admin.gorbushka.market` can authenticate via Telegram today (see incident above — currently broken); login/password is not implemented, so the frontend must not validate or embed admin credentials, and the Ed25519 `/admin-login` page is not production-ready (its challenge/verify endpoints don't exist). Tenant identity comes only from nginx's trusted `X-Storefront-Host` — never from the login body. **The frontend now calls this contract** (2026-08-26, admin login dialog, "Войти по логину и паролю" toggle) — every request 404s until the endpoint exists; the UI treats any failure uniformly as "something went wrong, try another way to sign in" and never surfaces the raw backend response, so this is safe to leave wired while the endpoint doesn't exist yet. +**Request:** (1) add `https://admin.gorbushka.market` and `https://gorbushka.market` (confirm subdomains/`www.` per actual topology) to the allowlist on `users.vitanova.network:456`; (2) confirm that allowlist entry grants `X-Marketplace-Domain` in `Access-Control-Allow-Headers` — `@marketplaces/auth`/`@marketplaces/payment` send it on every request as of 2026-08-23 with no fallback transport anymore, so a domain-allowlisted-but-header-blocked origin still fails; (3) check the same allowlist gap on `qr.vitanova.network` (payment) for gorbushka origins — not yet confirmed either way. + +**Admin credential (login/password) auth — required, not yet built.** `admin.gorbushka.market` can authenticate via Telegram today (see incident above — currently broken); login/password is not implemented, so the frontend must not validate or embed admin credentials, and the Ed25519 `/admin-login` page is not production-ready (its challenge/verify endpoints don't exist — as of 2026-08-23 `packages/auth/src/ed25519/` is also no longer exported from `@marketplaces/auth`'s public API at all, so it's dead code in the bundle until a backend exists and it's re-exported). Tenant identity comes only from nginx's trusted `X-Storefront-Host` — never from the login body. **The frontend now calls this contract** (2026-08-26, admin login dialog, "Войти по логину и паролю" toggle) — every request 404s until the endpoint exists; the UI treats any failure uniformly as "something went wrong, try another way to sign in" and never surfaces the raw backend response, so this is safe to leave wired while the endpoint doesn't exist yet. + +**Rate-limiting contract for admin credentials login.** `AdminAuthService.loginWithCredentials()` (`@marketplaces/auth` 0.3.0+) expects `429` with a `Retry-After` header (seconds) for rate-limited attempts, mapped client-side to a `rate_limited` failure code with `retryAfterSeconds`. Confirm the Auth API returns a standard `Retry-After` header on `429` for `POST {credentialsPath}` — if it uses a custom header or a response-body field instead, the frontend's parsing needs to match that shape, not this one. ```http POST /api/identity/v1/session { login, password } @@ -436,6 +440,7 @@ Write: `POST /companies/{id}/projects`, `/projects/{id}/stores`, `/stores/{id}/p Append here whenever a section changes. Newest first. +- **2026-08-27** — Enriched the 2026-08-26 CORS incident entry (§1.2) with detail pulled from `vitanovaPackages/BACKEND-TODO.md` (root-caused there 2026-08-24, more precise than this file's original note): confirmed it's an origin-allowlist gap specifically, not blanket CORS breakage (`novo.market` works, gorbushka doesn't), added the `X-Marketplace-Domain` header requirement and the `qr.vitanova.network` allowlist question. Also added the `Retry-After` rate-limit contract for admin credentials login and the ed25519 dead-export status — neither was in this file before. **Backend TODOs are not fully consolidated**: this file is canonical for the `marketplaces` repo per its own policy, but `vitanovaPackages/BACKEND-TODO.md` is a separate file in a separate repo and still holds the source-of-truth detail for package-level backend asks (this CORS finding, payment version-discipline, ed25519 status) — mirrored here, not merged away. - **2026-08-26** — Frontend now wires `POST /api/identity/v1/session` (§1.2 admin credential contract) from the admin login dialog, behind a "Войти по логину и паролю" toggle; every call 404s until the backend endpoint exists, surfaced to the user as one generic message, never the raw error. **Also found and logged a live incident** in the same section: the Telegram QR/session endpoint (`users.vitanova.network:456/users/sessions`) 403s every tested origin with no CORS headers at all — Telegram login, currently the only working admin auth path, is fully broken in production. Not a frontend fix; needs the backend CORS allowlist updated. - **2026-08-22** — Added `published: boolean` to the bootstrap response contract (§1.1): frontend now renders a built-in generic placeholder (all feature flags on) for any marketplace with no published revision, decided from this one field rather than HTTP status. See [Brand-bootstrap design](../superpowers/specs/2026-08-22-frontend-default-bootstrap-design.md). - **2026-08-22** — Consolidated the entire `docs/backend/` set into this one file per the single-doc rule; folded in the admin credential (login/password) auth handoff (§1.2). No contract content changed; the former per-phase files are removed.