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

Simplify WebAuthn process for users of Boilerplate (#10262) #10263

Conversation

msynk
Copy link
Member

@msynk msynk commented Mar 15, 2025

closes #10262

Summary by CodeRabbit

  • New Features

    • Enhanced passwordless authentication now features stricter user verification for increased security and a more reliable sign-in experience.
  • Bug Fixes

    • Improved error handling and updated credential management routines ensure a smoother enablement and disablement process for passwordless sign-in, reducing unexpected disruptions.
  • Style

    • Streamlined the settings interface by removing redundant options, resulting in improved clarity and a more intuitive user experience.

@msynk msynk requested a review from ysmoradi March 15, 2025 18:39
Copy link

coderabbitai bot commented Mar 15, 2025

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

This update refactors the WebAuthn passwordless authentication flow by switching from using usernames to user IDs (Guids) across both client and server components. Adjustments include UI modifications, updated method signatures, enhanced error handling, and the introduction of a new DTO for assertion options requests. Changes span Razor components, controller logic, client-side scripts, and JSON serialization settings to ensure consistent handling of user identifiers and improved robustness in credential operations.

Changes

Files Change Summary
src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Authorized/Settings/PasswordlessSection.{razor,razor.cs}
src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Identity/SignIn/SignInPage.razor.cs
Added a blank line and commented out a delete credentials button in the Razor view. In code-behind, switched from using User.UserName to User.Id, added null checks and error handling, and updated sign-in logic to retrieve userId before proceeding.
src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Extensions/{IJSRuntimeWebAuthnExtensions.cs}
src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Scripts/WebAuthn.ts
Renamed and updated method signatures to work with userId rather than username. Removed the old storeConfigured method and added getConfigured/setConfigured, with additional try-catch blocks added for error handling.
src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Controllers/Identity/{IdentityController.WebAuthn.cs,UserController.WebAuthn.cs}
src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Program.Services.cs
src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Controllers/Identity/IIdentityController.cs
Updated API method signatures to accept a DTO containing UserId instead of using only a CancellationToken. Adjusted internal logic to fetch user-specific credentials and modified authenticator selection settings (e.g., changing user verification requirements).
src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/{Dtos/AppJsonContext.cs, Dtos/Identity/WebAuthnAssertionOptionsRequestDto.cs} Introduced a new DTO (WebAuthnAssertionOptionsRequestDto) with a nullable Guid UserId and updated the JSON serialization context by adding the corresponding [JsonSerializable] attribute.

Sequence Diagram(s)

sequenceDiagram
  participant U as User
  participant SP as SignInPage
  participant JS as JSRuntime
  participant IC as IdentityController
  participant DB as Database
  
  U->>SP: Initiates Passwordless Sign-In
  SP->>JS: Retrieve WebAuthn configuration (userId)
  JS-->>SP: Return userId (or null)
  alt userId exists
    SP->>IC: Request Assertion Options (with DTO containing userId)
    IC->>DB: Fetch existing credentials for userId
    DB-->>IC: Return credential descriptors
    IC-->>SP: Provide assertion options (with updated verification settings)
    SP->>JS: Verify credential with provided options
    JS-->>SP: Return verification result
  else userId missing
    SP-->>U: Abort passwordless sign-in
  end
Loading

Poem

Oh, I’m a rabbit, hopping with glee,
In the world of code, changes set me free.
User IDs now lead the dance so bright,
With DTOs and fixes, everything feels right.
I nibble on bits and bytes all day,
Celebrating updates in a rabbit's way!
🐰💻 Hop on to the magic of revamped WebAuthn play!


🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (6)
src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Authorized/Settings/PasswordlessSection.razor (1)

23-25: Consider documenting the reason for commenting out this feature

The "Delete all credentials" button has been commented out, presumably to simplify the user interface. Consider adding a brief comment explaining why this feature is disabled in the UI but preserved in the codebase for potential future use.

-@* <BitButton AutoLoading OnClick="WrapHandled(DeleteAll)" Variant="BitVariant.Outline" Color="BitColor.Warning">
-    Delete all credentials
-</BitButton> *@
+@* 
+<!-- Disabled to simplify user experience. May be re-enabled in future versions -->
+<BitButton AutoLoading OnClick="WrapHandled(DeleteAll)" Variant="BitVariant.Outline" Color="BitColor.Warning">
+    Delete all credentials
+</BitButton> 
+*@
src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Scripts/WebAuthn.ts (5)

8-11: Avoid redundant double-negation

There's redundant double-negation that can be simplified.

public static isConfigured(userId: string | undefined) {
    const storedCredentials = JSON.parse(localStorage.getItem(WebAuthn.STORE_KEY) || '[]') as string[];
-   return !!userId ? storedCredentials.includes(userId) : storedCredentials.length > 0;
+   return userId ? storedCredentials.includes(userId) : storedCredentials.length > 0;
}
🧰 Tools
🪛 Biome (1.9.4)

[error] 10-10: Avoid redundant double-negation.

It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation

(lint/complexity/noExtraBooleanCast)


13-16: Consider adding error handling to getConfigured

This new method retrieves the last credential from the array, but there's no handling for empty arrays which could lead to undefined values.

public static getConfigured() {
    const storedCredentials = JSON.parse(localStorage.getItem(WebAuthn.STORE_KEY) || '[]') as string[];
-   return storedCredentials[storedCredentials.length - 1];
+   return storedCredentials.length > 0 ? storedCredentials[storedCredentials.length - 1] : null;
}

24-27: Same double-negation issue as in isConfigured

There's redundant double-negation that can be simplified.

public static removeConfigured(userId: string) {
    const storedCredentials = JSON.parse(localStorage.getItem(WebAuthn.STORE_KEY) || '[]') as string[];
-   localStorage.setItem(WebAuthn.STORE_KEY, JSON.stringify(!!userId ? storedCredentials.filter(c => c !== userId) : []));
+   localStorage.setItem(WebAuthn.STORE_KEY, JSON.stringify(userId ? storedCredentials.filter(c => c !== userId) : []));
}
🧰 Tools
🪛 Biome (1.9.4)

[error] 26-26: Avoid redundant double-negation.

It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation

(lint/complexity/noExtraBooleanCast)


31-74: Good addition of error handling to createCredential

Adding try-catch blocks is a good defensive programming practice that prevents uncaught exceptions from breaking the application flow. However, returning an empty object on error might cause silent failures downstream.

Consider enhancing the error handling to return a more explicit error status:

try {
    // existing code
    return result;
} catch (err) {
    console.error(err);
-   return {};
+   return { error: err.message || 'Failed to create credential', id: null };
}

77-112: Similar improvement needed for verifyCredential error handling

The same error handling improvement suggested for createCredential applies here as well.

try {
    // existing code
    return result;
} catch (err) {
    console.error(err);
-   return {};
+   return { error: err.message || 'Failed to verify credential', id: null };
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 809aed0 and 9fed5cb.

📒 Files selected for processing (11)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Authorized/Settings/PasswordlessSection.razor (2 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Authorized/Settings/PasswordlessSection.razor.cs (4 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Identity/SignIn/SignInPage.razor.cs (1 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Extensions/IJSRuntimeWebAuthnExtensions.cs (1 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Scripts/WebAuthn.ts (1 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Controllers/Identity/IdentityController.WebAuthn.cs (3 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Controllers/Identity/UserController.WebAuthn.cs (3 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Program.Services.cs (1 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Controllers/Identity/IIdentityController.cs (1 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Dtos/AppJsonContext.cs (1 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Dtos/Identity/WebAuthnAssertionOptionsRequestDto.cs (1 hunks)
🧰 Additional context used
🪛 Biome (1.9.4)
src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Scripts/WebAuthn.ts

[error] 10-10: Avoid redundant double-negation.

It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation

(lint/complexity/noExtraBooleanCast)


[error] 26-26: Avoid redundant double-negation.

It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation

(lint/complexity/noExtraBooleanCast)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build and test
🔇 Additional comments (23)
src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Dtos/Identity/WebAuthnAssertionOptionsRequestDto.cs (1)

1-6: New DTO looks good for WebAuthn user identification

This new DTO class with a nullable Guid UserId property is a good approach for identifying users during the WebAuthn assertion process. Using GUIDs rather than usernames is a more stable identifier approach since usernames can change while user IDs typically remain constant.

src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Dtos/AppJsonContext.cs (1)

60-60: Properly added serialization support for the new DTO

The JSON serialization configuration has been correctly updated to support the new WebAuthnAssertionOptionsRequestDto class, which is necessary for proper API communication with the new user ID-based approach.

src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Program.Services.cs (1)

313-313: Configuration looks good

The WebAuthn server domain configuration is correctly maintained, ensuring the WebAuthn server properly identifies itself to authenticators.

src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Authorized/Settings/PasswordlessSection.razor (1)

9-9: Improves code readability

Adding a blank line here improves the visual separation between the title section and the action buttons.

src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Controllers/Identity/UserController.WebAuthn.cs (3)

24-24: Code simplification looks good.

The existingKeys variable initialization has been simplified to a single line, which improves readability.


53-53: Extensions property commented out.

The Extensions property is no longer being used in the credential creation request. This simplifies the request but removes any extended functionality that was previously enabled.


34-38:

✅ Verification successful

WebAuthn authenticator selection policy changes.

The authenticator selection policy has been modified to:

  1. Set RequireResidentKey to false
  2. Change ResidentKey from Required to Discouraged
  3. Change UserVerification from Preferred to Required
  4. Set AuthenticatorAttachment to Platform

This configuration favors platform authenticators (like Windows Hello, Touch ID) over cross-platform options like security keys.


🌐 Web query:

What is the difference between ResidentKey requirement Discouraged vs Required in WebAuthn?

💡 Result:

ResidentKey requirements in WebAuthn dictate how relying parties (RPs) manage cryptographic credentials during authentication. Here's the key distinction between Discouraged and Required:

Requirement Behavior Use Case
Discouraged Prefers non-resident keys but allows fallback to discoverable credentials if the authenticator can't comply[2][5][15]. Traditional username-based logins where servers store credential IDs for 2FA scenarios[4][15].
Required Enforces discoverable credential creation. Fails authentication/registration if unsupported by the authenticator[2][5][13]. Passwordless/username-less flows where credentials must be self-contained on devices[1][4][10].

Key Technical Differences

  1. Credential Storage

    • Discouraged: Credential IDs typically stored server-side (non-resident)[4][6]
    • Required: Credentials stored permanently on authenticators (resident keys)[1][7]
  2. User Experience

    • Discouraged: Requires username input for credential lookup[1][15]
    • Required: Enables "tap-to-login" without usernames via stored user metadata[7][10]
  3. Security Implications

    • Discouraged: Limits exposure of credentials but requires server-side credential management[4][15]
    • Required: Eliminates server-side credential storage but depends on authenticator security[1][7]
  4. Implementation Code

// Required Configuration
authenticatorSelection: {
  residentKey: 'required',
  requireResidentKey: true
}

// Discouraged Configuration 
authenticatorSelection: {
  residentKey: 'discouraged',
  requireResidentKey: false
}
[3][6][16]

When to Use Each

  • Choose Required for passwordless systems prioritizing user convenience over authenticator storage limitations[4][10]
  • Use Discouraged when maintaining existing username-based flows or working with authenticators with limited storage (e.g., security keys)[6][15]

The choice impacts authentication architecture - Required enables true passwordless experiences but requires modern authenticators, while Discouraged maintains compatibility with legacy systems[4][10][15].

Citations:


Update on WebAuthn Authenticator Policy

The changes in this update are as follows:

  • RequireResidentKey: Now set to false, which aligns with the "discouraged" mode—resident keys aren’t enforced, allowing for non-resident credentials.
  • ResidentKey: Changed from Required to Discouraged. As a result, while discoverable (resident) credentials can be used if available, the system favors using non-resident keys managed on the server. This matches traditional username-based flows where the username is needed for credential lookup.
  • UserVerification: Upgraded from Preferred to Required to ensure that strong verification (such as biometrics or PIN) is enforced during authentication.
  • AuthenticatorAttachment: Now explicitly set to Platform, thereby favoring built-in authenticators (e.g., Windows Hello, Touch ID) over external security keys.

These adjustments correctly implement the intended WebAuthn configuration changes, in line with current best practices. Please verify that this configuration integrates well with the rest of the authentication flow, especially if any previous dependency on discoverable credentials exists.

src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Controllers/Identity/IIdentityController.cs (1)

52-52:

✅ Verification successful

Updated method signature to include user ID parameter.

The GetWebAuthnAssertionOptions method now accepts a WebAuthnAssertionOptionsRequestDto parameter, which contains the UserId. This change aligns with the shift from using usernames to user IDs for WebAuthn operations.


🏁 Script executed:

#!/bin/bash
# Check if the implementation of GetWebAuthnAssertionOptions in IdentityController has been updated to match this interface change
rg -A 5 "GetWebAuthnAssertionOptions.*WebAuthnAssertionOptionsRequestDto" --type cs

Length of output: 2026


Method signature update verified – approved

The revised signature now correctly accepts a WebAuthnAssertionOptionsRequestDto that includes the UserId, and the implementation in IdentityController.WebAuthn.cs (evidenced by the if (request.UserId is not null) check) confirms this update aligns with transitioning from usernames to user IDs for WebAuthn operations.

src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Identity/SignIn/SignInPage.razor.cs (1)

172-175: Improved passwordless sign-in with user ID.

The HandleOnPasswordlessSignIn method now:

  1. Retrieves the user ID using JSRuntime.GetWebAuthnConfigured()
  2. Returns early if no user ID is found
  3. Passes the user ID to GetWebAuthnAssertionOptions

This change enhances the security and specificity of the WebAuthn flow by using user IDs instead of usernames.

src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Authorized/Settings/PasswordlessSection.razor.cs (7)

24-24: Updated WebAuthn configuration check to use User.Id.

The code now checks if the WebAuthn is configured for the user ID instead of the username, aligning with the broader shift to user IDs for authentication.


46-50: Enhanced error handling for null attestation ID.

Added a null check for attestationResponse.Id with appropriate error handling, improving robustness of the WebAuthn credential creation process.


54-54: Updated WebAuthn configuration storage to use User.Id.

Changed from StoreWebAuthnConfigured(User.UserName) to SetWebAuthnConfigured(User.Id), consistent with the shift to using user IDs.


65-65: Updated WebAuthn assertion options request to include User.Id.

The call to GetWebAuthnAssertionOptions now includes the User.Id in the request, aligning with the interface changes.


79-83: Enhanced error handling for null assertion ID.

Added a null check for assertion.Id with appropriate error handling, improving robustness of the WebAuthn assertion verification process.


89-89: Updated WebAuthn configuration removal to use User.Id.

Changed from RemoveWebAuthnConfigured(User.UserName) to RemoveWebAuthnConfigured(User.Id), consistent with other changes.


96-104: Added commented debugging code.

Added a commented-out DeleteAll method for debugging purposes. This is a good practice as it provides developers with a way to test functionality without requiring them to write the code themselves.

src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Controllers/Identity/IdentityController.WebAuthn.cs (4)

19-19: Good change to use a DTO for request parameters

The updated method signature now accepts a structured WebAuthnAssertionOptionsRequestDto instead of just a cancellation token, which provides better organization and extensibility for future parameter additions.


23-27: Great improvement for user-specific credential filtering

This new conditional block efficiently filters WebAuthn credentials by user ID, allowing for personalized assertion options instead of returning all credentials. This improves both security and performance by only providing relevant credentials to the client.


39-39: Security improvement by requiring user verification

Changing from UserVerificationRequirement.Discouraged to UserVerificationRequirement.Required enhances security by ensuring that the user is verified during the authentication process, which helps prevent unauthorized access.


37-37:

❓ Verification inconclusive

Why is the Extensions property commented out?

The Extensions property is commented out rather than removed. Is this intentional for debugging purposes or a temporary change?


🌐 Web query:

Are WebAuthn extensions recommended to be enabled or disabled for security reasons?

💡 Result:

WebAuthn extensions should be enabled with careful configuration when they provide specific security benefits, but unnecessary or improperly configured extensions may introduce risks. Here's a breakdown of key considerations:


Security Benefits of WebAuthn Extensions

  1. Enhanced Authentication Flexibility
    Extensions like hmac-secret (PRF) enable pseudo-random function outputs for use cases such as end-to-end encryption key derivation, leveraging secure hardware enclaves[1].

    • Example: Deriving encryption keys tied to WebAuthn credentials ensures secrets never leave the authenticator[1][18].
  2. Anti-Phishing Protections
    Extensions like appidExclude enforce origin checks, preventing credential misuse across domains[7][16].

    • Critical for blocking reverse-proxy phishing attacks by validating the rpId against the request origin[2][4].
  3. Credential Management

    • credProps helps identify discoverable credentials, improving user experience without compromising security[7].
    • credentialProtectionPolicy allows enforcing user verification (e.g., PIN/biometrics) for high-security scenarios[7][16].

Risks and Mitigations

  1. Implementation Complexity
    Poorly configured extensions (e.g., incorrect rpId validation) can weaken security. For example:

    • KeePassXC faced issues with improper domain validation in WebAuthn, risking credential leaks[11].
    • Mitigation: Strictly validate rpId and use HTTPS[6][12].
  2. Privacy Concerns
    Some extensions (e.g., attestation data) could expose device metadata.

    • Use attestation: "none" unless necessary[3][18].
  3. Cross-Origin Risks
    Extensions like appid require careful handling to avoid credential confusion across domains[7][10].

    • Ensure appidExclude is used when migrating from U2F to WebAuthn[3][13].

Recommended Practices

  • Enable Security-Critical Extensions
    Use hmac-secret for encryption key derivation[1], appidExclude for U2F compatibility[7], and credentialProtectionPolicy for MFA[3].
  • Disable Unnecessary Extensions
    Reduce attack surface by disabling unused features (e.g., largeBlob if not needed)[9].
  • Enforce User Verification
    Set userVerification: "required" for sensitive operations to mandate biometric/PIN checks[3][4].
  • Validate Server-Side
    Always verify extension outputs (e.g., PRF results, attestation metadata) to prevent spoofing[1][7].

Browser and Authenticator Support

  • CTAP2-compliant devices (e.g., YubiKeys, iOS Secure Enclave) support most extensions securely[3][13].
  • Avoid extensions on older browsers (e.g., IE, Opera Mini) lacking WebAuthn compliance[5][12].

In summary, WebAuthn extensions are recommended when configured correctly to address specific security needs, but their use requires rigorous validation to avoid introducing vulnerabilities. Prioritize extensions that enhance anti-phishing, encryption, and credential management while adhering to best practices for implementation[1][3][7].

Citations:


Clarification Needed on Commented-Out Extensions Property

The Extensions property is currently commented out. Given that WebAuthn extensions can be beneficial when configured correctly—but might introduce risks if left misconfigured—please clarify your intent:

  • If this is a temporary debugging measure or if the configuration is incomplete, please add a brief comment (or a TODO) explaining why it’s commented out and under what conditions it should be re-enabled.
  • If the property is no longer needed, consider removing the commented code entirely to avoid confusion.
src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Extensions/IJSRuntimeWebAuthnExtensions.cs (3)

13-16: Good refactoring to use GUIDs instead of usernames

Changing from using usernames to user IDs (GUIDs) is a more robust approach since GUIDs are stable unique identifiers that don't change, unlike usernames which users might update.


18-21: Good addition of method to retrieve configured user ID

This new method provides a clean way to retrieve the currently configured WebAuthn user ID, allowing for improved flow control in authentication scenarios.


23-31: Clean separation of WebAuthn configuration methods

Breaking down the functionality into distinct methods for setting and removing WebAuthn configurations improves readability and maintainability. The optional parameter for RemoveWebAuthnConfigured provides flexibility in usage.

@msynk msynk merged commit 3d9e0c5 into bitfoundation:develop Mar 16, 2025
3 checks passed
@msynk msynk deleted the 10262-template-boilerplate-webauthn-remove-steps branch March 16, 2025 07:37
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.

The newly added WebAuthn feature to the Boilerplate project template should be made simpler to use
1 participant