diff --git a/README.md b/README.md index c5a0188..d159c50 100644 --- a/README.md +++ b/README.md @@ -224,7 +224,7 @@ Set the auth host in the admin panel's Domains section. One Paskia instance can serve several domains (rp-ids) from the same database: users, orgs and permissions are shared, while passkeys are registered per domain. The master admin adds domains in the admin panel's Domains section; no restart is needed. -A domain can also let *other* domain names use its passkeys via WebAuthn [Related Origin Requests](https://passkeys.dev/docs/advanced/related-origins/) — list them in the domain's allowed origins (they show as related domains), and paskia serves the required `/.well-known/webauthn` declaration on the domain's main site. In-domain entries of the same list restrict which sites of the domain's own name may authenticate (a new domain defaults to `*.{domain}` — the whole domain over https). +A domain can also let *other* domain names use its passkeys via WebAuthn [Related Origin Requests](https://passkeys.dev/docs/advanced/related-origins/) — list them in the domain's allowed origins (they show as related domains), and paskia serves the required `/.well-known/webauthn` declaration on the domain's main site. In-domain entries of the same list restrict which sites of the domain's own name may authenticate (a new domain defaults to `**.{domain}` — the apex and all subdomains over https). See [Multi-Site documentation](docs/MultiSite.md) for details. diff --git a/docs/API.md b/docs/API.md index 822ec0d..5686514 100644 --- a/docs/API.md +++ b/docs/API.md @@ -79,7 +79,7 @@ E.g. Org admin cannot see anything of the other orgs that he has no admin access Domain endpoints require the `auth:admin` permission; writes additionally require recent authentication (5 minutes). Changes are validated cross-domain and apply immediately. -`origins` is a single object keyed by all of the domain's sign-in sites. Entries *within* the rp-id domain are in-domain sites: bare hosts, `*.` wildcards under the rp-id (matching the base domain and subdomains over https only — any scheme and port under localhost), or full origins when not https; the plain `*` wildcard is not accepted. Entries *outside* the rp-id domain are related origins that may assert this domain's rp-id (WebAuthn Related Origin Requests, max 5, no wildcards); those are published at `/.well-known/webauthn` on the rp-id host. An empty object allows nothing of the domain itself. A value of `true` marks presence; `{"auth_host": true}` additionally marks an in-domain entry as the domain's authentication host. +`origins` is a single object keyed by all of the domain's sign-in sites. Entries *within* the rp-id domain are in-domain sites: bare hosts, wildcards under the rp-id following the shell-glob convention (`**.example.com` covers the apex and subdomains at any depth, `*.example.com` exactly one subdomain level — https only, any scheme and port under localhost; plain `*` is not accepted), or full origins when not https. Entries *outside* the rp-id domain are related origins that may assert this domain's rp-id (WebAuthn Related Origin Requests, max 5, no wildcards); those are published at `/.well-known/webauthn` on the rp-id host. An empty object allows nothing of the domain itself. A value of `true` marks presence; `{"auth_host": true}` additionally marks an in-domain entry as the domain's authentication host. ### WebSockets: /auth/ws/* diff --git a/docs/MultiSite.md b/docs/MultiSite.md index 71b0450..84d52f5 100644 --- a/docs/MultiSite.md +++ b/docs/MultiSite.md @@ -22,6 +22,16 @@ on every domain. A user active on two domains simply holds one passkey per domain. - A session is bound to the exact host that issued it. +## The simplest case: several sites on one domain + +Multi-site does not require several domains. Sites under one name — +`app1.company.com`, `app2.company.com` and so on — share the domain +`company.com`: one passkey works on all of them (WebAuthn natively allows +the domain and its subdomains), and the default `**.company.com` origin +entry already lets every one of them sign in. Add explicit entries only +to restrict which sites may sign in, and mark an auth host (see below) +if you want sign-in centralized on one site. + ## Managing domains The admin panel's **Domains** section (master admins only) lists every @@ -54,21 +64,38 @@ This list controls which sites may sign in with the domain's passkeys. Everything is explicit: an empty list allows nothing of the domain itself (related origins, below, still work — a domain can in principle run entirely on related origins). A new domain starts with one entry, -`*.{domain}`, which suits most deployments. +`**.{domain}`, which suits most deployments. Entry forms: -- `*.company.com` — the domain and all its subdomains, https only. Under - `localhost`, wildcards match any scheme and any port, as a development - convenience. +- `**.company.com` — the domain itself and its subdomains at any depth, + https only. The default entry of a new domain. +- `*.company.com` — exactly one subdomain level: `app.company.com` yes, + but neither the apex `company.com` nor `a.b.company.com`. Use this when + the apex or deeper subdomains should not serve sign-ins. - `app.company.com` — exactly this host, https only. - `http://localhost:8080` — a full origin with scheme, for non-https exceptions. -Wildcards must stay within the domain, and plain `*` is not accepted — it -would suggest "anything goes". An entry on a different domain name +Under `localhost`, both wildcard forms match any scheme and any port, as +a development convenience. An entry on a different domain name automatically becomes a related origin (🔗) instead — see below. +### Wildcard syntax + +Wildcards follow the shell-glob convention — the same one permission +scopes use (`*` within a segment, `**` across segments, see +[the perm argument](api/perm.md)): `**` spans any number of hostname +labels including none, `*` spans exactly one. Wildcards must stay within +the domain, and plain `*` is not accepted — it would suggest "anything +goes". + +Conventions elsewhere differ: DNS, TLS and nginx take `*.example.com` to +mean subdomains only (TLS: exactly one level), while browser-extension +match patterns take it as apex plus any depth. The `*`/`**` split +sidesteps that ambiguity, and the less obvious forms `*example.com` and +`.example.com` remain unsupported on purpose. + ## The auth host (🔑) Marking one allowed origin as the **auth host** (row menu ⋮ → "Set as @@ -167,7 +194,7 @@ model: databases, the positional argument selects one by name. Legacy wildcard origins convert as-is (https only, except any scheme and port under `localhost`); a legacy database without configured origins — where that - meant the whole domain was allowed — gets an explicit `*.{domain}` + meant the whole domain was allowed — gets an explicit `**.{domain}` entry. - Origins, auth hosts and related origins are no longer environment settings — they live in the database and are managed in the admin