RP ID and origins

Every demo so far has quietly relied on one fact: a passkey is scoped to an RP ID, not to the exact origin it was created on. RP ID must be the origin's hostname, or a registrable domain suffix of it — a less specific parent domain, never a more specific child. That single rule is both why passkeydemo.com and its subdomains can share credentials, and why nothing else on the internet can.

This site's server always uses passkeydemo.com as the RP ID (see shared/src/environments.ts's allowlist) whether a request arrives from the main site or from sandbox.passkeydemo.com — a subdomain that exists solely so this page has a second real origin to demonstrate with.

1. A credential registered here works from the sandbox subdomain too

This is the same discoverable-credential flow from the Discoverable credentials page — the point here isn't the ceremony, it's where it works. The credential is scoped to the RP ID, and the RP ID is the same on both origins.

Sign in (works on either origin)

2. A mismatched RP ID fails before the authenticator is even asked

The reverse direction — a subdomain claiming its parent's child as an RP ID — isn't a registrable suffix of the current origin, so navigator.credentials.create() rejects synchronously with a SecurityError. No network round trip, no authenticator prompt; the browser refuses before anything else happens.