diff --git a/index.bs b/index.bs
index 80717951e..6227bac49 100644
--- a/index.bs
+++ b/index.bs
@@ -1228,6 +1228,12 @@ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "S
: Non-Discoverable Credential
:: This is a [=credential=] whose [=credential ID=] must be provided in {{PublicKeyCredentialRequestOptions/allowCredentials}} when calling {{CredentialsContainer/get()|navigator.credentials.get()}} because it is not [=client-side discoverable credential|client-side discoverable=]. See also [=server-side credentials=].
+: Registrable Origin Label
+:: The first [=domain label=] of the [=registrable domain=] of a [=domain=],
+ or null if the [=registrable domain=] is null.
+ For example, the [=registrable origin label=] of both `example.co.uk` and `www.example.de` is `example`
+ if both `co.uk` and `de` are [=public suffixes=].
+
: Public Key Credential
:: Generically, a *credential* is data one entity presents to another in order to *authenticate* the former to the latter
[[RFC4949]]. The term [=public key credential=] refers to one of: a [=public key credential source=], the
@@ -1824,11 +1830,21 @@ a numbered step. If outdented, it (today) is rendered as a bullet in the midst o
: is present
:: If |pkOptions|.{{PublicKeyCredentialCreationOptions/rp}}.{{PublicKeyCredentialRpEntity/id}}
[=is not a
- registrable domain suffix of and is not equal to=] |effectiveDomain|, throw a "{{SecurityError}}" {{DOMException}}.
+ registrable domain suffix of and is not equal to=] |effectiveDomain|, and if the client
+
+
|pkOptions|.{{PublicKeyCredentialCreationOptions/rp}}.{{PublicKeyCredentialRpEntity/id}}
.
- : Is not present
- :: Set |pkOptions|.{{PublicKeyCredentialCreationOptions/rp}}.{{PublicKeyCredentialRpEntity/id}}
to
- |effectiveDomain|.
+ 1. Run the [$related origins validation procedure$] with arguments |callerOrigin| and |rpIdRequested|.
+ If the result is [FALSE], throw a "{{SecurityError}}" {{DOMException}}.
+
+ : does not support [[#sctn-related-origins|related origin requests]]
+ :: throw a "{{SecurityError}}" {{DOMException}}.
+ |pkOptions|.{{PublicKeyCredentialCreationOptions/rp}}.{{PublicKeyCredentialRpEntity/id}}
to |effectiveDomain|.
Note: |pkOptions|.{{PublicKeyCredentialCreationOptions/rp}}.{{PublicKeyCredentialRpEntity/id}}
represents the
@@ -2314,19 +2330,31 @@ When this method is invoked, the user agent MUST execute the following algorithm
PKI-based security.
|pkOptions|.{{PublicKeyCredentialRequestOptions/rpId}}
is not present, then set |rpId| to
- |effectiveDomain|.
+ If |pkOptions|.{{PublicKeyCredentialRequestOptions/rpId}}
+ |pkOptions|.{{PublicKeyCredentialRequestOptions/rpId}}
[=is not a
+ registrable domain suffix of and is not equal to=] |effectiveDomain|, and if the client
- 1. If |pkOptions|.{{PublicKeyCredentialRequestOptions/rpId}}
[=is not a registrable domain suffix of and is not
- equal to=] |effectiveDomain|, throw a "{{SecurityError}}" {{DOMException}}.
+ |pkOptions|.{{PublicKeyCredentialRequestOptions/rpId}}
+
+ 1. Run the [$related origins validation procedure$] with arguments |callerOrigin| and |rpIdRequested|.
+ If the result is [FALSE], throw a "{{SecurityError}}" {{DOMException}}.
- 1. Set |rpId| to |pkOptions|.{{PublicKeyCredentialRequestOptions/rpId}}
.
+ : does not support [[#sctn-related-origins|related origin requests]]
+ :: throw a "{{SecurityError}}" {{DOMException}}.
+ |pkOptions|.{{PublicKeyCredentialRequestOptions/rpId}}
when calling {{CredentialsContainer/get()}}.
+ : is not present
+ :: Set |pkOptions|.{{PublicKeyCredentialRequestOptions/rpId}}
to |effectiveDomain|.
+ |pkOptions|.{{PublicKeyCredentialRequestOptions/rpId}}
when calling {{CredentialsContainer/get()}}.
https://|rpIdRequested|/.well-known/webauthn
).
+ 1. If the fetch fails, the response does not have a content type of `application/json`, or does not have a status code (after following redirects) of 200, then throw a "{{SecurityError}}" {{DOMException}}.
+ 1. If the body of the resource is not a valid JSON object, then throw a "{{SecurityError}}" {{DOMException}}.
+ 1. If the value of the |origins| property of the JSON object is missing, or is not an array of strings, then throw a "{{SecurityError}}" {{DOMException}}.
+1. Let |labelsSeen| be a new empty [=set=].
+1. [=set/For each=] |originItem| of |origins|:
+ 1. Let |url| be the result of running the [=URL parser=] with |originItem| as the input. If that fails, [=continue=].
+ 1. Let |domain| be the [=effective domain=] of |url|. If that is null, [=continue=].
+ 1. Let |label| be [=registrable origin label=] of |domain|.
+ 1. If |label| is empty or null, [=continue=].
+ 1. If the [=set/size=] of |labelsSeen| is greater than or equal to |maxLabels| and |labelsSeen| does not [=set/contain=] |label|, [=continue=].
+ 1. If |callerOrigin| and |url| are [=same origin=], return [TRUE].
+ 1. If the [=set/size=] of |labelsSeen| is less than |maxLabels|, [=set/append=] |label| to |labelsSeen|.
+1. Return [FALSE].
# WebAuthn Authenticator Model # {#sctn-authenticator-model}
@@ -8616,6 +8703,11 @@ For example:
{{CollectedClientData/origin}} to exactly equal some element of a list of allowed origins,
for example the list ["https://example.org", "https://login.example.org"]
.
+- A web application leveraging [[#sctn-related-origins|related origin requests]] might also require
+ {{CollectedClientData/origin}} to exactly equal some element of a list of allowed origins,
+ for example the list ["https://example.co.uk", "https://example.de", "https://myexamplerewards.com"]
.
+ This list will typically match the origins listed in the well-known URI for the [=RP ID=]. See [[#sctn-related-origins]].
+
- A web application served at a large set of domains that changes often might parse
{{CollectedClientData/origin}} structurally and require that the URL scheme is https
and that the authority equals or is any subdomain of the [=RP ID=] - for example,