Skip to content

Support signaling unknown passkey credentials - #68513

Open
rolandVi wants to merge 9 commits into
dotnet:rolandVi/passkey-workfrom
rolandVi:passkeys/signal-unknown-credential
Open

Support signaling unknown passkey credentials#68513
rolandVi wants to merge 9 commits into
dotnet:rolandVi/passkey-workfrom
rolandVi:passkeys/signal-unknown-credential

Conversation

@rolandVi

Copy link
Copy Markdown
Member

Tracked by #68128, API proposal in #68511.

If someone deletes a passkey from their account, their browser carries on offering it at sign-in forever. The sign-in fails every time and there is no way for them to clear it up from the website. This adds the server side of PublicKeyCredential.signalUnknownCredential, so the app can tell the browser to delete a passkey the server has never heard of.

Example usage

var result = await SignInManager.PasskeySignInAsync(credentialJson);

if (!result.Succeeded)
{
    // null means don't signal
    UnknownCredentialSignalOptions = await SignInManager.MakeUnknownPasskeySignalOptionsAsync(credentialJson);
}

The JSON is { "rpId": "...", "credentialId": "..." }, ready to hand to PublicKeyCredential.signalUnknownCredential().

What changed

MakeUnknownPasskeySignalOptionsAsync on IPasskeyHandler<TUser>, PasskeyHandler<TUser> and SignInManager<TUser>, plus an UnknownPasskeySignalOptionsResult to carry the payload.

The handler returns null, do not signal, whenever it is not certain: no passkey support in the store, unparseable JSON, no credential ID, or any user found. Only a clean miss produces a payload.

The credential JSON is parsed into a one field internal type (PublicKeyCredentialId) rather than the full assertion model, so attestation shaped JSON parses too. The assertion model marks AuthenticatorData and Signature as required and would throw.

Testing

7 handler tests covering each null path and the success case, 3 on SignInManager, and an E2E template test for the ordering. The E2E one holds the signalUnknownCredential promise pending, asserts autofill has not started, then resolves it and waits for autofill to begin, so the ordering is pinned as a real dependency rather than a timing coincidence.

Resolves #68128.

@rolandVi
rolandVi requested a review from rokonec August 14, 2026 08:17
@rolandVi
rolandVi requested a review from a team as a code owner August 14, 2026 08:17
@rolandVi rolandVi added the area-identity Includes: Identity and providers label Aug 14, 2026
@rolandVi
rolandVi requested a balanced review from Copilot and removed request for a team August 14, 2026 08:17

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds safe signaling for unknown passkey credentials after failed sign-in. The diff also introduces known-passkey synchronization APIs and template behavior.

Changes:

  • Adds Identity APIs and serialization models for passkey signals.
  • Integrates unknown and known signals into Blazor templates.
  • Adds unit and browser coverage for signal generation and ordering.

Reviewed changes

Copilot reviewed 22 out of 22 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
Components/App.razor Loads the passkey signals module.
Shared/PasskeySubmit.razor.js Signals unknown credentials before autofill.
Shared/PasskeySubmit.razor Exposes unknown-signal options.
Shared/PasskeySignals.razor.js Sends known-passkey signals.
Shared/PasskeySignals.razor Builds known-passkey options.
Manage/Passkeys.razor Signals updated passkey state.
Login.razor Generates unknown-credential options.
ConfirmEmailChange.razor Signals updated user details.
template-baselines.json Registers new template files.
BlazorTemplateTest.cs Tests signal behavior and ordering.
SignInManagerTest.cs Tests signal API delegation.
PasskeyHandlerSignalTest.cs Tests signal option generation.
UnknownPasskeySignalOptionsResult.cs Adds the unknown-signal result API.
SignInManager.cs Exposes signal generation APIs.
PublicAPI.Unshipped.txt Records new public APIs.
UnknownPasskeySignalOptions.cs Defines unknown-signal payloads.
PublicKeyCredentialId.cs Adds minimal credential parsing.
KnownPasskeysSignalOptions.cs Defines known-signal payloads.
PasskeyHandler.cs Implements signal generation.
KnownPasskeysSignalOptionsResult.cs Adds the known-signal result API.
IPasskeyHandler.cs Adds signal handler contracts.
IdentityJsonSerializerContext.cs Registers signal serialization types.
Suppressed comments (1)

src/Identity/Core/src/SignInManager.cs:620

  • The API returns JSON text, while signalUnknownCredential expects an options object. The example omits JSON.parse, unlike the correct example on UnknownPasskeySignalOptionsResult, so consumers copying this code will pass the wrong type.
    /// await PublicKeyCredential.signalUnknownCredential?.(signalOptions);

💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/Identity/Core/src/PasskeyHandler.cs Outdated
Comment thread src/Identity/Core/src/SignInManager.cs Outdated
Comment thread src/Identity/Core/src/SignInManager.cs
Comment thread src/Identity/Core/src/PublicAPI.Unshipped.txt
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
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