Skip to content

Support conditional passkey creation - #68194

Open
rolandVi wants to merge 2 commits into
dotnet:rolandVi/passkey-workfrom
rolandVi:passkeys/conditional-create
Open

Support conditional passkey creation#68194
rolandVi wants to merge 2 commits into
dotnet:rolandVi/passkey-workfrom
rolandVi:passkeys/conditional-create

Conversation

@rolandVi

@rolandVi rolandVi commented Aug 4, 2026

Copy link
Copy Markdown
Member

API proposal tracked by #68192.

A Blazor Identity app can now create a passkey for someone silently, right after they sign in with a password, so they get moved off passwords without seeing a prompt or having to find a button. Today a passkey only appears if the user goes looking for the "add a passkey" page, which almost nobody does.

Example usage

if (SignInManager.SupportsPasskeyConditionalCreation)
{
    creationOptionsJson = await SignInManager.MakePasskeyCreationOptionsAsync(
        userEntity,
        isConditionallyMediated: true);
}

Why the server needs telling

This needs new public API because the server cannot work it out for itself. Mediation is not in clientDataJSON, so it cannot be inferred, and taking it from the client at attestation time would let anyone switch off the user-presence check. It is supplied when the options are made and rides along in the data-protected attestation state.

Design notes

Two checks get relaxed. The spec's registration steps skip the user-presence check when mediation is conditional, and the client is required to report both presence and verification as false. Separately, UserVerificationRequirement is downgraded from "required" to "preferred" in the generated options, because the browser refuses the ceremony outright if a conditional create asks for verification, so without that downgrade nothing reaches the server to verify.

I used a bool overload rather than an options object because an options object is source-breaking here: it makes existing new() { ... } call sites ambiguous. Details in the proposal.

SupportsConditionalCreation is there so an app with a custom IPasskeyHandler can ask before calling instead of getting an exception on every sign-in.

Template changes

The Blazor template sends the user through a short /Account/PasskeyUpgrade page after a completed sign-in, which does the creation and then continues to wherever they were headed. It is a separate page rather than something inline on the login page because navigating away cancels the login page's in-flight conditional get(), which the browser wants aborted before a conditional create starts.

The options are created in the sign-in handler itself, on the password, two-factor and recovery-code paths, and carried to the upgrade page in protected TempData. The upgrade page has no code that can issue options: reached without them, it redirects and does nothing. That keeps the decision to relax the registration checks with the code that just checked a credential, rather than with any request carrying a session cookie. It gives up after 5 seconds, and any failure is logged and swallowed, since the user never asked for this and should not see it fail.

Adding a passkey with only a session cookie is wider than this page. #66865 tracks the same weakness on the existing passkey management page and is not addressed here.

Testing

Unit tests cover the verification downgrade, the flag round-tripping through the attestation state, a conditional create succeeding with both flags false, an ordinary create still rejecting a missing user-presence flag, and the NotSupportedException from the default interface method.

The template E2E test stubs getClientCapabilities and intercepts navigator.credentials.create, recording the mediation it was called with. It checks a conditional create is attempted after a password sign-in, after two-factor and after a recovery code, that none is attempted at the two-factor prompt itself, and that navigating straight to /Account/PasskeyUpgrade with a session cookie attempts nothing. The interception means the E2E does not exercise attestation for a conditional create; the server side is covered by the unit tests

Resolves #67298.

@rolandVi
rolandVi requested a review from a team as a code owner August 4, 2026 09:21
@dotnet-policy-service dotnet-policy-service Bot added the community-contribution Indicates that the PR has been added by a community member label Aug 4, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Thanks for your PR, @rolandVi. Someone from the team will get assigned to your PR shortly and we'll get it reviewed.

@snemeckayova snemeckayova added area-identity Includes: Identity and providers and removed community-contribution Indicates that the PR has been added by a community member labels Aug 4, 2026
@rolandVi
rolandVi requested review from rokonec and removed request for a team August 4, 2026 15:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-identity Includes: Identity and providers

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants