Skip to content

Replace in-field string metadata with resource-level default fields #2280

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

Open
wants to merge 9 commits into
base: main
Choose a base branch
from

Conversation

emlun
Copy link
Member

@emlun emlun commented Apr 9, 2025

This addresses #1643:

We request that you do the following:

  • Remove the in-field encoding of language metadata using Unicode tag characters
  • Remove the in-field encoding of string direction using strongly directional marks
  • Add a document-level field for the document language and a document-level field for default direction; such fields would be optional, since you have an installed base

New language and direction attributes on PublicKeyCredentialUserEntity seems like the most appropriate implementation of a "document-level field", since these are the only natural language string parameters we have. The new attributes won't work with currently existing CTAP authenticators, but their processing is specified as "best-effort" (at least that's the intent) so RPs should be aware that they might not work.


The following tasks have been completed:

  • Modified Web platform tests (link)

Implementation commitment:

Documentation and checks

  • N/A Affects privacy
  • N/A Affects security
  • N/A Updated explainer

Preview | Diff

Copy link

@aphillips aphillips left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. Thank you for this!

I made a few comments.

Copy link

@aphillips aphillips left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. Thanks!!!

Comment on lines +1774 to +1775
1. If <code>|pkOptions|.{{PublicKeyCredentialCreationOptions/user}}.{{PublicKeyCredentialUserEntity/language}}</code> is present
and is not a [=well-formed language tag=], throw a "{{SyntaxError}}" {{DOMException}}.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One final thought: this requirement feels like it might push implementations that don't support the language field to do extra work. The field is optional and supporting the value is optional, but this clearly says that implementations need to check the tag's structure if the field is present.

String-Meta recommends but does not require that you emit an error here. I'd suggest handling language similar to direction and ignoring the field if the tag is not well-formed.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see what you mean, but I'm still more inclined to keep the error in the interest of "fail faster". Of course no error will be thrown here if the client implementation predates WebAuthn L3, so there will always be that possibility, but I still think that clients that know the field exists should verify its well-formedness when present - even if the client otherwise ignores the value.

I think this position is also supported by the W3C priority of consituencies: "[...] the needs of web page authors [...] come before the needs of user agent implementors, [...]".

@emlun
Copy link
Member Author

emlun commented Apr 11, 2025

From 2025-04-11 face-to-face WG meeting:

  • It's unclear what clients would do differently for different language values, especially considering these values (user.name and user.displayName) are likely chosen by the user in some way. Is the language field needed here?

<td>|userLanguage|</td>
<td>
The [=resource-wide default=] language tag for the {{PublicKeyCredentialUserEntity|user}} entity associated to the credential.
This property may not be defined.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
This property may not be defined.
Note that this property might not be present.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, but I'm going to reject this proposal as "This property may not be defined" is the formulation already used for userHandle and largeBlob:

webauthn/index.bs

Lines 8003 to 8006 in 6507c4c

<td>|userHandle|</td>
<td>
The [=public key credential source/userHandle=] associated to the credential encoded using
[=Base64url Encoding=]. This property may not be defined.

webauthn/index.bs

Lines 8016 to 8019 in 6507c4c

<td>|largeBlob|</td>
<td>
The [=large, per-credential blob=] associated to the [=public key credential source=], encoded using [=Base64url Encoding=].
This property may not be defined.

<td>|userDirection|</td>
<td>
The [=resource-wide default=] [=string direction=] for the {{PublicKeyCredentialUserEntity|user}} entity associated to the credential.
This property may not be defined.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
This property may not be defined.
Note that this property might not be present.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Co-authored-by: Michael B. Jones <michael_b_jones@hotmail.com>
@nadalin
Copy link
Contributor

nadalin commented Apr 30, 2025

@selfissued can you review to make sure your issues have been resolved

@@ -1767,6 +1771,9 @@ When this method is invoked, the user agent MUST execute the following algorithm

1. If the length of <code>|pkOptions|.{{PublicKeyCredentialCreationOptions/user}}.{{PublicKeyCredentialUserEntity/id}}</code> is not between 1 and 64 bytes (inclusive) then throw a {{TypeError}}.

1. If <code>|pkOptions|.{{PublicKeyCredentialCreationOptions/user}}.{{PublicKeyCredentialUserEntity/language}}</code> is present
and is not a [=well-formed language tag=], throw a "{{SyntaxError}}" {{DOMException}}.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WebAuthn typically raises TypeError's when there's an issue with a malformed value, as documented in L3:

We should probably maintain this behavior for this exception too.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm. I see what you mean, but TypeError is not semantically correct for this error case. The user.id error ideally should have been a SyntaxError too, but that's probably too late to change now. SyntaxError is also used by the PRF extension when base64 decoding fails. So I'd prefer to keep this as SyntaxError rather than TypeError.

Comment on lines +2234 to +2237
: {{SyntaxError}}
:: <code>{{PublicKeyCredentialCreationOptions/user}}.{{PublicKeyCredentialUserEntity/language}}</code>
was present and was not a [=well-formed language tag=].

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we agree to keep things consistent with TypeError as I call out above, we'll want to take this out.


Upon invocation of {{PublicKeyCredential/signalCurrentUserDetails(options)}}, the
[=client=] executes these steps:

1. If the result of [=base64url encoding | base64url decoding=]
<code>|options|.{{CurrentUserDetailsOptions/userId}}</code> is an error,
then return [=a promise rejected with=] a {{TypeError}}.
1. If <code>|options|.{{CurrentUserDetailsOptions/language}}</code> is present
and is not a [=well-formed language tag=],
then return [=a promise rejected with=] a "{{SyntaxError}}" {{DOMException}}.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tagging another SyntaxError pending a decision about sticking with TypeError as called out above.

index.bs Outdated

So the string “حبیب الرحمان” could have two different DOMString values, depending on whether the language was encoded or not. (Since the direction is unambiguous a directionality marker is not needed in this example.)
Instead, the Level 3 [=Web Authentication API=] provides [=resource-wide default=] fields for encoding language and direction metadata
which SHOULD be used when supported by the [=client=] and [=authenticator=].
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does a relying party know if the client/authenticator support the new language tags?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't... but I think I see what you mean. When I wrote "SHOULD be used" I meant "[the client] should use them [when provided by the RP and supported by the authenticator]", but your reading was "[the RP] should use them [when supported by the client and authenticator]"? That's definitely an ambiguity I need to fix.

Anything else to do here after fixing that ambiguity?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does 5d2e401 resolve this ambiguity?

@@ -1767,6 +1771,9 @@ When this method is invoked, the user agent MUST execute the following algorithm

1. If the length of <code>|pkOptions|.{{PublicKeyCredentialCreationOptions/user}}.{{PublicKeyCredentialUserEntity/id}}</code> is not between 1 and 64 bytes (inclusive) then throw a {{TypeError}}.

1. If <code>|pkOptions|.{{PublicKeyCredentialCreationOptions/user}}.{{PublicKeyCredentialUserEntity/language}}</code> is present
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we require language and direction be present if the other one is? i.e. if language is present, direction cannot be undefined.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so, String-Meta specifically describes these as separate values. It doesn't look like either should require the other.

@@ -240,6 +240,10 @@ spec: RFC8610; urlPrefix: https://tools.ietf.org/html/rfc8610
type: dfn
text: group sockets; url: section-3.9

spec: String-Meta; urlPrefix: https://www.w3.org/TR/2024/NOTE-string-meta-20241017
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

General comment:

I understand this is the i18n wg proposal, but this approach feels strictly worse, since authenticators have to support it for browsers to take advantage of it.

@@ -2926,6 +2938,8 @@ value and terminate the operation.
required Base64URLString id;
required DOMString name;
required DOMString displayName;
DOMString language;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was it decided whether we needed language or not?

@nadalin nadalin added this to the L3 Candidate Recommendation milestone May 7, 2025
Copy link
Contributor

@MasterKale MasterKale left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A language map might be a better pattern here:

https://www.w3.org/TR/2024/NOTE-string-meta-20241017/#language-maps

For example, if we added a new "user.localizedName" property, that looked like this...

localizedName: {
  "en-US": {
    value: "...",
    dir: "ltr"
  }
}

...then processing rules could say clients should use a value in user.localizedName when present, otherwise fall back to user.name.

The same could be done with a "user.localizedDisplayName" too.

Copy link
Contributor

@selfissued selfissued left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ready to go, as far as I'm concerned

@MasterKale
Copy link
Contributor

From WG meeting @ May 28: We'll wait till next week's meeting when we can have a more direct discussion on the "best" path forward

@dwaite
Copy link
Contributor

dwaite commented May 28, 2025

Question since I don't quite understand from conversation - is there a reason the UserEntity fields (language, direction and value) can't be encoded by the client into a single string behind the API using STRINGPREP, and decoded by the client when read? (theoretically read - I don't believe we expose displayName back into the API today)

This would mean that we are using STRINGPREP internally only, otherwise banning its use on the web-facing API. This allows for improvements on a more arbitrary schedule to the backing CTAP and platform specifications.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants