## Problem Builder page navigation, Authentication, and HTTP response headers used different path matchers from published Remix pages. For example, Builder did not select a `/docs/*` page at `/docs`, and a request for `/%64ocs` could reach the `/docs` page without matching its Authentication rule. ## Change - Use Remix's framework-independent router for page selection and project path rules. Adapt Webstudio named splats and preserve encoded static path segments. - Keep Authentication's first matching rule and Headers' ordered application of every matching rule. - Preserve previously saved encoded literals such as `/%2A`, `/%3F`, and `/%3Aid`. They match only their literal encoded pathname and cannot become wildcards or parameters. Previously accepted malformed encoding remains a literal path. - Replace Builder's separate route ranking and URLPattern matcher. URLPattern remains for page path validation and path editing. - Use the request URL for the project-domain authentication exemption instead of trusting `x-forwarded-host`. Generated HTML, XML, and text routes share one authentication helper. - Extend the HTTP headers guide and shared path pattern reference with matching behavior, an iframe example, and verification steps. ## Validation - Authentication package: 88 tests. New regression cases cover saved Authentication and Headers rules, literal matching, route ranking, parameter values, and a marker collision attempt. The regressions failed before the fix and pass now. - Project build: 2,484 tests, including 214 route and redirect checks. SDK: 636 tests. CLI: 1,165 tests. Builder system: 5 tests. - Typechecks: Authentication, project build, Builder, SDK, and CLI. Lint, package boundaries, formatting, and diff checks pass. - The fixture pipeline completed and made no additional changes. The generated fixture files already changed by this PR remain included. - Staging project build 196 published successfully using the companion published-site Worker branch. The edge dispatcher was deployed from its staging branch to normalize forwarded hosts. Live HTTP checks covered base and child routes, dynamic pages, redirects, 404s, global headers, and route-scoped headers. The generated site challenged protected base and child paths, accepted the route password, and left public routes accessible. The project domain intentionally skips route-specific auth and has a separate staging Basic Auth gate, so the successful route-password request was checked in the generated production runtime. A forged `x-forwarded-host` no longer changes the hosted project-domain auth decision. - An initial CLI run alongside two other full suites timed out in one fixture API test; that test passed alone, and the full CLI suite passed when rerun alone. ## Compatibility - [x] Preserve previously accepted percent-encoded route literals before merging. - The old URLPattern test asserting that `/docs/*` does not match `/docs` was intentionally changed because the published Remix router does match the base path. Tests for the removed custom route sorter were replaced with router-selection tests. ## Rollout - [x] Migrate matching in this repository. - [x] Update user documentation. - [x] Verify package consumers and related code. - [ ] Merge [webstudio-saas#665](https://github.com/webstudio-is/webstudio-saas/pull/665) before releasing this PR. The current published-site Worker template imports the removed `matchesPathnamePattern` export; without the companion change, a published site fails at Wrangler build. - [ ] After publishing the new `@webstudio-is/wsauth` version, update the published-site Worker template’s pinned `0.301.0` dependency, remove the temporary fallback, and deploy the hosted Worker. Replaces #6482 so the review tracks the deployed `headers.staging` branch.
@webstudio-is/wsauth
wsauth is Webstudio's generic authentication package.
It owns shared authentication types, validators, route matching, build-time resource generation, and runtime enforcement helpers used by Builder-generated sites. The package is structured around auth methods so Webstudio can add methods beyond Basic Auth without changing the route auth model.
The first implemented method is HTTP Basic Auth.
Auth Config
Webstudio sync writes route authentication config at:
.webstudio/auth.json
Version 1 uses JSON with route strings as keys:
{
"version": 1,
"routes": {
"/my/page": {
"method": "basic",
"login": "me",
"password": "idiot"
},
"/bla/*": {
"method": "basic",
"login": "bla",
"password": "blubb"
}
}
}
Routes use Webstudio's path pattern syntax. The guide covers validation, matching, and the differences between page paths and project rules. Authentication keeps the first matching rule when several rules cover one URL.
Basic Auth
Version 1 supports Basic Auth:
{
"method": "basic",
"login": "admin",
"password": "secret"
}
Rules:
- Login is required.
- Password is required.
- Login must not contain
:. - Login must not contain whitespace.
- Password must not contain whitespace.
- Password may contain
:.
The colon rule follows HTTP Basic Auth's user-id ":" password credential
structure from RFC 7617.
Build Semantics
Build tools generate .webstudio/auth.json from Webstudio project data. The
file is treated as build output and is overwritten on sync.
Generated auth sources are applied in this order:
- Project-level auth config from Webstudio project settings
- Page-level auth generated by Webstudio page settings
If both sources define the same route, the later source wins. Because routes are JSON object keys, the generated config file cannot represent duplicate routes.
Runtime
At runtime, protected requests without valid credentials receive:
new Response("Authentication required", {
status: 401,
headers: {
"WWW-Authenticate": 'Basic realm="Webstudio"',
"Cache-Control": "private, no-store",
},
});