Skip to content

Commit

Permalink
Merge pull request w3c#2040 from w3c/tc-related-origins
Browse files Browse the repository at this point in the history
adds Related Origin Requests
  • Loading branch information
timcappalli authored Jul 17, 2024
2 parents bb9f9bb + 017a5e3 commit 2b8e368
Showing 1 changed file with 105 additions and 13 deletions.
118 changes: 105 additions & 13 deletions index.bs
Original file line number Diff line number Diff line change
Expand Up @@ -1227,6 +1227,12 @@ BCP 14 [[!RFC2119]] [[!RFC8174]] when, and only when, they appear in all capital
: <dfn>Non-Discoverable Credential</dfn>
:: 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=].

: <dfn>Registrable Origin Label</dfn>
:: 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=].

: <dfn>Public Key Credential</dfn>
:: 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
Expand Down Expand Up @@ -1845,11 +1851,21 @@ a numbered step. If outdented, it (today) is rendered as a bullet in the midst o

: is present
:: If <code>|pkOptions|.{{PublicKeyCredentialCreationOptions/rp}}.{{PublicKeyCredentialRpEntity/id}}</code> [=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

<dl class="switch">
: supports [[#sctn-related-origins|related origin requests]]
:: 1. Let |rpIdRequested| be the value of <code>|pkOptions|.{{PublicKeyCredentialCreationOptions/rp}}.{{PublicKeyCredentialRpEntity/id}}</code>.

: Is not present
:: Set <code>|pkOptions|.{{PublicKeyCredentialCreationOptions/rp}}.{{PublicKeyCredentialRpEntity/id}}</code> 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}}.
</dl>

: is not present
:: Set <code>|pkOptions|.{{PublicKeyCredentialCreationOptions/rp}}.{{PublicKeyCredentialRpEntity/id}}</code> to |effectiveDomain|.
</dl>

Note: <code>|pkOptions|.{{PublicKeyCredentialCreationOptions/rp}}.{{PublicKeyCredentialRpEntity/id}}</code> represents the
Expand Down Expand Up @@ -2349,19 +2365,31 @@ When this method is invoked, the user agent MUST execute the following algorithm
PKI-based security.

<li id='GetAssn-DetermineRpId'>
If <code>|pkOptions|.{{PublicKeyCredentialRequestOptions/rpId}}</code> is not present, then set |rpId| to
|effectiveDomain|.
If <code>|pkOptions|.{{PublicKeyCredentialRequestOptions/rpId}}</code>
<dl class="switch">

Otherwise:
: is present
:: If <code>|pkOptions|.{{PublicKeyCredentialRequestOptions/rpId}}</code> [=is not a
registrable domain suffix of and is not equal to=] |effectiveDomain|, and if the client

1. If <code>|pkOptions|.{{PublicKeyCredentialRequestOptions/rpId}}</code> [=is not a registrable domain suffix of and is not
equal to=] |effectiveDomain|, throw a "{{SecurityError}}" {{DOMException}}.
<dl class="switch">
: supports [[#sctn-related-origins|related origin requests]]
:: 1. Let |rpIdRequested| be the value of <code>|pkOptions|.{{PublicKeyCredentialRequestOptions/rpId}}</code>

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 <code>|pkOptions|.{{PublicKeyCredentialRequestOptions/rpId}}</code>.
: does not support [[#sctn-related-origins|related origin requests]]
:: throw a "{{SecurityError}}" {{DOMException}}.
</dl>

Note: |rpId| represents the caller's [=RP ID=]. The [=RP ID=] defaults to being the caller's [=environment
settings object/origin=]'s [=effective domain=] unless the caller has explicitly set
<code>|pkOptions|.{{PublicKeyCredentialRequestOptions/rpId}}</code> when calling {{CredentialsContainer/get()}}.
: is not present
:: Set <code>|pkOptions|.{{PublicKeyCredentialRequestOptions/rpId}}</code> to |effectiveDomain|.
</dl>

Note: |rpId| represents the caller's [=RP ID=]. The [=RP ID=] defaults to being the caller's [=environment
settings object/origin=]'s [=effective domain=] unless the caller has explicitly set
<code>|pkOptions|.{{PublicKeyCredentialRequestOptions/rpId}}</code> when calling {{CredentialsContainer/get()}}.
</li>

1. Let |clientExtensions| be a new [=map=] and let |authenticatorExtensions| be a new [=map=].
Expand Down Expand Up @@ -4008,6 +4036,7 @@ Note: The {{UserVerificationRequirement}} enumeration is deliberately not refere
"hybridTransport",
"passkeyPlatformAuthenticator",
"userVerifyingPlatformAuthenticator",
"relatedOrigins"
};
</xmp>

Expand Down Expand Up @@ -4039,6 +4068,9 @@ Note: The {{ClientCapability}} enumeration is deliberately not referenced, see [

: <dfn>userVerifyingPlatformAuthenticator</dfn>
:: The [=WebAuthn Client=] supports usage of a [=user-verifying platform authenticator=].

: <dfn>relatedOrigins</dfn>
:: The [=WebAuthn Client=] supports [[#sctn-related-origins|Related Origin Requests]].
</div>

### User-agent Hints Enumeration (enum <dfn enum>PublicKeyCredentialHints</dfn>) ### {#enum-hints}
Expand Down Expand Up @@ -4100,7 +4132,62 @@ To override this default policy and indicate that a cross-origin <{iframe}> is a

[=[RPS]=] utilizing the WebAuthn API in an embedded context should review [[#sctn-seccons-visibility]] regarding [=UI redressing=] and its possible mitigations.

## Using Web Authentication across related origins ## {#sctn-related-origins}

By default, Web Authentication requires that the [=RP ID=] be equal to the [=determines the set of origins on which the public key credential may be exercised|origin=]'s [=effective domain=], or a [=is a registrable domain suffix of or is equal to|registrable domain suffix=] of the [=determines the set of origins on which the public key credential may be exercised|origin=]'s [=effective domain=].

This can make deployment challenging for large environments where multiple country-specific domains are in use (e.g. example.com vs example.co.uk vs example.sg), where alternative or brand domains are required (e.g. myexampletravel.com vs examplecruises.com), and/or where platform as a service providers are used to support mobile apps.

[=[WRPS]=] can opt in to allowing [=WebAuthn Clients=] to enable a credential to be created and used across a limited set of related [=origin|origins=].
Such [=[RPS]=] MUST choose a common [=RP ID=] to use across all ceremonies from related origins.

A JSON document MUST be hosted at the `webauthn` well-known URL [[!RFC8615]] for the [=RP ID=]. The JSON document MUST be returned as follows:

- The content type MUST be `application/json`.
- The top-level JSON object MUST contain a key named `origins` whose value MUST be an array of one or more strings containing web origins.

For example, for the RP ID `example.com`:

<xmp class="json" highlight="json">
{
"origins": [
"https://example.co.uk",
"https://example.de",
"https://example.sg",
"https://example.net",
"https://exampledelivery.com",
"https://exampledelivery.co.uk",
"https://exampledelivery.de",
"https://exampledelivery.sg",
"https://myexamplerewards.com",
"https://examplecars.com"
]
}
</xmp>

[=WebAuthn Clients=] supporting this feature MUST support at least five [=registrable origin labels=]. Client policy SHOULD define an upper limit to prevent abuse.

[=WebAuthn Clients=] supporting this feature SHOULD include {{ClientCapability/relatedOrigins}} in their response to [[#sctn-getClientCapabilities|getClientCapabilities()]].

### Validating Related Origins ### {#sctn-validating-relation-origin}

The <dfn abstract-op>related origins validation procedure</dfn>, given arguments |callerOrigin| and |rpIdRequested|, is as follows:

1. Let |maxLabels| be the maximum number of [=registrable origin labels=] allowed by client policy.
1. Fetch the `webauthn` well-known URL [[!RFC8615]] for the RP ID |rpIdRequested| (i.e., <code>https://|rpIdRequested|/.well-known/webauthn</code>).
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 <dfn>Authenticator Model</dfn> # {#sctn-authenticator-model}

Expand Down Expand Up @@ -8617,6 +8704,11 @@ For example:
{{CollectedClientData/origin}} to exactly equal some element of a list of allowed origins,
for example the list <code>["https://example.org", "https://login.example.org"]</code>.

- 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 <code>["https://example.co.uk", "https://example.de", "https://myexamplerewards.com"]</code>.
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 <code>https</code>
and that the authority equals or is any subdomain of the [=RP ID=] - for example,
Expand Down

0 comments on commit 2b8e368

Please sign in to comment.