Skip to content

Only require UV flag when userVerification is "required" per WebAuthn spec#263

Draft
Copilot wants to merge 4 commits into
masterfrom
copilot/fix-user-verification-uv-flag
Draft

Only require UV flag when userVerification is "required" per WebAuthn spec#263
Copilot wants to merge 4 commits into
masterfrom
copilot/fix-user-verification-uv-flag

Conversation

Copilot AI commented Mar 17, 2026

Copy link
Copy Markdown
Contributor

factor: "first" unconditionally required the UV flag, but WebAuthn spec step 16 says UV should only be verified when the RP sets userVerification: "required".

Changes

  • factorToFlags() — accepts optional userVerification param; UV is only added for factor: "first" when userVerification === "required"
  • assertionResult() / attestationResult() — forward expected.userVerification to factorToFlags()
  • JSDoc — documents the new optional userVerification parameter on both methods and factorToFlags(), and updates the factor: "first" description to reflect the new behavior
  • TypeScript declarations — adds userVerification?: UserVerification to ExpectedAttestationResult and ExpectedAssertionResult interfaces in types/main.d.ts

Usage

// Before: factor "first" always required UV — non-spec-compliant
await fido2.assertionResult(res, { factor: "first", ... });

// After: UV only enforced when explicitly required
await fido2.assertionResult(res, { factor: "first", userVerification: "required", ... }); // checks UV
await fido2.assertionResult(res, { factor: "first", ... }); // UP only, no UV check
Original prompt

This section details on the original issue you should resolve

<issue_title>User verification in assertionResult does not follow official webauthn spec</issue_title>
<issue_description>The official webauthn spec says that UV flag should be set only if userVerification is set to required: See point 16 here.

However the lib sets the UV flag not matter what for the first factor here</issue_description>

<agent_instructions>Have a look at this issue, keep the changes minimal and tested according to the current setup.</agent_instructions>

Comments on the Issue (you are @copilot in this section)

@JamesCullum A merge request would be great 👍

💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

…Authn spec

The WebAuthn spec (step 16) says the UV flag should only be verified
when the Relying Party explicitly requires user verification. Previously,
factor "first" always required UV. Now UV is only required when
userVerification is set to "required" in the expected options.

Co-authored-by: Hexagon <419737+Hexagon@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix user verification in assertionResult to follow webauthn spec Only require UV flag when userVerification is "required" per WebAuthn spec Mar 17, 2026
Copilot AI requested a review from Hexagon March 17, 2026 23:14
@Hexagon Hexagon requested a review from Copilot March 17, 2026 23:21

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Adjusts WebAuthn authenticator flag validation so the UV flag is only enforced when the RP explicitly requires user verification, aligning assertion verification with WebAuthn spec step 16.

Changes:

  • Extend factorToFlags() to accept userVerification and only require UV when userVerification === "required".
  • Forward expected.userVerification from assertionResult() / attestationResult() into factorToFlags().
  • Add/expand tests to cover assertion behavior for factor: "first" with and without userVerification: "required".

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.

File Description
lib/main.js Adds conditional UV enforcement based on expected.userVerification, and plumbs it through assertion/attestation verification paths.
test/main.test.js Adds assertionResult tests to confirm UV is not required unless userVerification is explicitly "required".

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread lib/main.js Outdated
Comment on lines +538 to +542
* If "first", this requires that the authenticator performed user verification (e.g. - biometric authentication, PIN authentication, etc.).
* If "second", this requires that the authenticator performed user presence (e.g. - user pressed a button).
* If "either", then either "first" or "second" is acceptable
* @param {String} [expected.userVerification] The expected user verification requirement. Valid values are "required", "preferred", or "discouraged".
* If "required", the authenticator must have performed user verification and the UV flag is checked.
Comment thread lib/main.js Outdated
Comment on lines +568 to +572
* If "first", this requires that the authenticator performed user verification (e.g. - biometric authentication, PIN authentication, etc.).
* If "second", this requires that the authenticator performed user presence (e.g. - user pressed a button).
* If "either", then either "first" or "second" is acceptable
* @param {String} [expected.userVerification] The expected user verification requirement. Valid values are "required", "preferred", or "discouraged".
* If "required", the authenticator must have performed user verification and the UV flag is checked.
Comment thread lib/main.js
Comment on lines 546 to 550
async attestationResult(res, expected) {
expected.flags = factorToFlags(expected.factor, ["AT"]);
expected.flags = factorToFlags(expected.factor, ["AT"], expected.userVerification);
delete expected.factor;
delete expected.userVerification;
return await Fido2AttestationResult.create(res, expected);
Comment thread lib/main.js
Comment on lines 581 to 585
async assertionResult(res, expected) {
expected.flags = factorToFlags(expected.factor, []);
expected.flags = factorToFlags(expected.factor, [], expected.userVerification);
delete expected.factor;
delete expected.userVerification;
return Fido2AssertionResult.create(res, expected);
Comment thread lib/main.js Outdated
Comment on lines +823 to +827
@@ -818,14 +824,15 @@ function setOpt(obj, prop, val) {
*/


function factorToFlags(expectedFactor, flags) {
// var flags = ["AT"];
function factorToFlags(expectedFactor, flags, userVerification) {
@Hexagon

Hexagon commented Mar 17, 2026

Copy link
Copy Markdown
Member

@copilot apply changes based on the comments in this thread

Copilot AI and others added 2 commits March 17, 2026 23:33
…ests

- Update factor JSDoc in attestationResult/assertionResult to clarify UV
  is only checked when userVerification is "required"
- Update factorToFlags JSDoc to document the userVerification parameter
- Add userVerification to TypeScript ExpectedAttestationResult and
  ExpectedAssertionResult interfaces
- Add attestation tests for factor "first" with/without userVerification

Co-authored-by: Hexagon <419737+Hexagon@users.noreply.github.com>
Co-authored-by: Hexagon <419737+Hexagon@users.noreply.github.com>

Copilot AI commented Mar 17, 2026

Copy link
Copy Markdown
Contributor Author

@copilot apply changes based on the comments in this thread

All review comments addressed in 5d5dec8 and eed9576:

  1. Updated JSDoc for attestationResult and assertionResult — factor "first" docs now clarify UV is only checked when userVerification === "required"
  2. Updated factorToFlags JSDoc to document the new userVerification parameter
  3. Added userVerification?: UserVerification to both ExpectedAttestationResult and ExpectedAssertionResult in types/main.d.ts
  4. Added 2 attestation tests covering factor: "first" with and without userVerification: "required"

All 866 tests passing.

@JamesCullum

Copy link
Copy Markdown
Member

As this has security impact to existing users, we should either keep the old behavior as default or make the new release a major version bump

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

User verification in assertionResult does not follow official webauthn spec

4 participants