Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

adds Related Origin Requests #2040

Merged
merged 32 commits into from
Jul 17, 2024
Merged
Changes from 2 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
0522807
initial text
timcappalli Mar 12, 2024
d48a18c
remaining draft text
timcappalli Mar 12, 2024
2a18351
s/webauthn-origins/webauthn
timcappalli Mar 13, 2024
689647c
MUST support 5 origin labels
timcappalli Mar 13, 2024
3aad054
s/member/property, s/list/array
timcappalli Mar 13, 2024
5187e72
use [=continue=]
timcappalli Mar 26, 2024
881ac8f
collapse multiple steps into one
timcappalli Mar 26, 2024
9062a15
s/vanity/alternative
timcappalli Mar 26, 2024
2315db8
capitalization
timcappalli Mar 26, 2024
8ea0303
s/relatedOriginRequests/relatedOrigins
timcappalli Mar 26, 2024
28a2b0f
attempt at using a procedure
timcappalli Mar 26, 2024
b51bd16
s/must/MUST
timcappalli Mar 26, 2024
a21babf
remove break
timcappalli Apr 29, 2024
7466f32
remove break for create
timcappalli Apr 29, 2024
e7d0c7c
s/originLabelsSeen/labelsSeen and set def
timcappalli Apr 29, 2024
b3bf34c
word order
timcappalli Apr 29, 2024
bdba742
Validation step optimization
timcappalli Apr 29, 2024
de25c37
use macros for true and false
timcappalli Apr 29, 2024
71e4e80
add period
timcappalli Jun 12, 2024
26d350c
text tweak
timcappalli Jun 12, 2024
a2ac319
clean up well-known JSON definition
timcappalli Jun 14, 2024
b120220
s/origin labels/labels
timcappalli Jun 14, 2024
bcec7fa
s/rpIdRequested/callerOrigin
timcappalli Jun 14, 2024
3ba2ff3
move set contains label check after origin match check
timcappalli Jun 14, 2024
a108a2c
add RP guidance around adding all origins with the same origin label …
timcappalli Jun 14, 2024
c0c40d1
remove check for label in labelsSeen, not necessary
timcappalli Jun 14, 2024
ebf03eb
fix indents
timcappalli Jun 14, 2024
e4f24d9
update RWO algo to support additional origins with the same label
timcappalli Jun 26, 2024
2e9bdcf
remove consideration text for RPs about RWO well-known ordering
timcappalli Jun 26, 2024
2462fd8
Emil's feedback
timcappalli Jul 17, 2024
9da2c4b
procedure dfn
timcappalli Jul 17, 2024
017a5e3
Editorial tweaks
timcappalli Jul 17, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 110 additions & 13 deletions index.bs
Original file line number Diff line number Diff line change
Expand Up @@ -1228,6 +1228,9 @@ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "S
: <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>Origin Label</dfn>
:: The portion of a domain name preceding the effective top-level domain, as defined in the Public Suffix List [[PSL]]. This is often referred to as the eTLD+1. For example, the origin label for example.co.uk and example.de is `example`.
timcappalli marked this conversation as resolved.
Show resolved Hide resolved

: <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 @@ -1824,11 +1827,37 @@ 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>.
emlun marked this conversation as resolved.
Show resolved Hide resolved

1. Let |maxLabels| be the number of maximum [=origin labels=] allowed by client policy.

1. Fetch the well-known URL for the RP ID (<code>https://|rpIdRequested|/.well-known/webauthn-origins</code>).
timcappalli marked this conversation as resolved.
Show resolved Hide resolved

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}}.
timcappalli marked this conversation as resolved.
Show resolved Hide resolved
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| member of the JSON object is missing, or is not a list of strings, then throw a "{{SecurityError}}" {{DOMException}}.
timcappalli marked this conversation as resolved.
Show resolved Hide resolved

1. Let |originLabelsSeen| be an empty set.
emlun marked this conversation as resolved.
Show resolved Hide resolved
1. [=set/For each=] string in |origins|:
1. Let |url| be the result of parsing the string as a URL. If that fails, continue with the next element in the list.
1. Let |domain| be the [=effective domain=] of |url|. If that is null, continue with the next element of the list.
1. Remove any [=public suffix=] from the end of |domain|, including private registries and unknown registries. If |domain| is now empty, continue with the next element of the list.
1. Split |domain| into [=origin labels|labels=] and let |label| be the right-most one.
timcappalli marked this conversation as resolved.
Show resolved Hide resolved
1. If |label| is not in |labelsSeen| and:
1. If the number of elements in |labelsSeen| is less than |maxLabels|, then insert |label| into |labelsSeen|.
1. Otherwise, continue with the next element of the list.
timcappalli marked this conversation as resolved.
Show resolved Hide resolved
1. If |rpIdRequested| and |url| are [=same origin=], then [=continue=].
emlun marked this conversation as resolved.
Show resolved Hide resolved

: 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|.
: 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 @@ -2314,19 +2343,47 @@ 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. Let |maxLabels| be the number of maximum [=origin labels=] allowed by client policy.

1. Fetch the well-known URL for the RP ID (<code>https://|rpIdRequested|/.well-known/webauthn-origins</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| member of the JSON object is missing, or is not a list of strings, then throw a "{{SecurityError}}" {{DOMException}}.

1. Let |originLabelsSeen| be an empty set.
1. [=set/For each=] string in |origins|:
1. Let |url| be the result of parsing the string as a URL. If that fails, continue with the next element in the list.
1. Let |domain| be the [=effective domain=] of |url|. If that is null, continue with the next element of the list.
1. Remove any [=public suffix=] from the end of |domain|, including private registries and unknown registries. If |domain| is now empty, continue with the next element of the list.
1. Split |domain| into [=origin labels|labels=] and let |label| be the right-most one.
1. If |label| is not in |labelsSeen| and:
1. If the number of elements in |labelsSeen| is less than |maxLabels|, then insert |label| into |labelsSeen|.
1. Otherwise, continue with the next element of the list.
1. If |rpIdRequested| and |url| are [=same origin=], then [=continue=].

: does not support [[#sctn-related-origins|related origin requests]]
:: throw a "{{SecurityError}}" {{DOMException}}.
</dl>

1. Set |rpId| to <code>|pkOptions|.{{PublicKeyCredentialRequestOptions/rpId}}</code>.
: 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()}}.
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 @@ -3963,6 +4020,7 @@ Note: The {{UserVerificationRequirement}} enumeration is deliberately not refere
"hybridTransport",
"passkeyPlatformAuthenticator",
"userVerifyingPlatformAuthenticator",
"relatedOriginRequests"
timcappalli marked this conversation as resolved.
Show resolved Hide resolved
};
</xmp>

Expand All @@ -3985,6 +4043,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>relatedOriginRequests</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 @@ -4046,7 +4107,38 @@ 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 vanity 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.
timcappalli marked this conversation as resolved.
Show resolved Hide resolved

[=[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=]
timcappalli marked this conversation as resolved.
Show resolved Hide resolved

Relying Parties MUST choose a common [=RP ID=] to use across all ceremonies from related origins.
timcappalli marked this conversation as resolved.
Show resolved Hide resolved

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

- the content type must be `application/json`
- JSON document MUST contain a single object named `origins`
- the `origins` object MUST contain an array of one or more web origins
timcappalli marked this conversation as resolved.
Show resolved Hide resolved

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://myexamplerewards.com"
]
}
</xmp>

To mitigate abuse, [=WebAuthn Clients=] SHOULD limit the number of related origins, with a recommended maximum of 5 [=origin labels=].
timcappalli marked this conversation as resolved.
Show resolved Hide resolved

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

# WebAuthn <dfn>Authenticator Model</dfn> # {#sctn-authenticator-model}

Expand Down Expand Up @@ -8616,6 +8708,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
Loading