Skip to content

Rotate security stamp on passkey removal - #69394

Merged
Youssef1313 merged 5 commits into
mainfrom
copilot/update-removepasskeyasync
Oct 8, 2026
Merged

Youssef1313 merged 5 commits into
mainfrom
copilot/update-removepasskeyasync

Conversation

Copilot AI commented Sep 18, 2026 •

Copy link
Copy Markdown
Contributor

This hardens passkey removal to rotate the security stamp.

Security stamp is documented in https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.identity.identityuser-1.securitystamp?view=aspnetcore-10.0#microsoft-aspnetcore-identity-identityuser-1-securitystamp as:

A random value that must change whenever a users credentials change (password changed, login removed)

We already do it for removing an external login, but we don't do that for passkey removal. A passkey is technically a "credentials change" similar to removing an external login.

Copilot AI and others added 3 commits September 18, 2026 14:02
Co-authored-by: Youssef1313 <31348972+Youssef1313@users.noreply.github.com>
Co-authored-by: Youssef1313 <31348972+Youssef1313@users.noreply.github.com>
Co-authored-by: Youssef1313 <31348972+Youssef1313@users.noreply.github.com>

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.

🟡 Changes recommended

The newly added unit test incorrectly verifies a store call (GetSecurityStampAsync) that does not occur, so it will fail even when the implementation is correct.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Updates ASP.NET Core Identity passkey removal to rotate a user’s security stamp before persisting the user record, and adds a regression test to validate the behavior when the backing store supports security stamps.

Changes:

  • Rotate the security stamp during RemovePasskeyCoreAsync before calling UpdateUserAsync.
  • Add a unit test intended to verify RemovePasskeyAsync updates the security stamp when IUserSecurityStampStore is supported.
File summaries
File Description
src/Identity/Extensions.Core/src/UserManager.cs Rotates the security stamp as part of passkey removal before persisting the user update.
src/Identity/test/Identity.Test/UserManagerTest.cs Adds a regression test for security stamp rotation on passkey removal.
Review details
  • Files reviewed: 2/2 changed files
  • Comments generated: 1
  • Review effort level: Lite

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

}
}

private async Task<IdentityResult> RemovePasskeyCoreAsync(TUser user, byte[] credentialId)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This method can be inlined, and the UpdateUserAsync along with the metrics update could be merged into a single call to UpdateUserAndRecordMetricAsync for consistency with the rest of the class, but I'm only making the minimal change here.

We can follow with code cleanup later as needed.

@github-actions github-actions Bot added the area-identity Includes: Identity and providers label Sep 18, 2026

@rokonec rokonec left a comment •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I’m concerned that rotating the security stamp here may be too broad. It invalidates all active Identity sessions for the user, even when they are only cleaning up a stale or unused passkey.

The documentation and Identity UI templates could explain that, if the passkey was lost or potentially compromised, the user should also choose “Log out everywhere” to invalidate existing sessions. This would distinguish routine credential management from account-compromise recovery while still giving users a clear secure path. Is global logout on every passkey removal an intentional requirement?

@Youssef1313

Copy link
Copy Markdown
Member

Researched a little bit, we could keep the current session active by refreshing sign-in, which removing an external login actually does.

@copilot Update the passkey removal callsites to match the same behavior as external login removal with regards to refreshing sign-in.

Co-authored-by: Youssef1313 <31348972+Youssef1313@users.noreply.github.com>
Copilot AI requested a review from a team as a code owner September 23, 2026 08:28
Co-authored-by: Youssef1313 <31348972+Youssef1313@users.noreply.github.com>

Copilot AI commented Sep 23, 2026

Copy link
Copy Markdown
Contributor Author

Researched a little bit, we could keep the current session active by refreshing sign-in, which removing an external login actually does.

@copilot Update the passkey removal callsites to match the...

Updated the passkey deletion flow in the Blazor Web template to call SignInManager.RefreshSignInAsync(user) after a successful removal, matching ExternalLogins.razor. That keeps the current session signed in while other sessions are invalidated by the rotated stamp. (a5ac83d)

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Looks like this PR hasn't been active for some time and the codebase could have been changed in the meantime.
To make sure no conflicting changes have occurred, please rerun validation before merging. You can do this by leaving an /azp run comment here (requires commit rights), or by simply closing and reopening.

@dotnet-policy-service dotnet-policy-service Bot added the pending-ci-rerun When assigned to a PR indicates that the CI checks should be rerun label Sep 30, 2026
@Youssef1313 Youssef1313 removed the pending-ci-rerun When assigned to a PR indicates that the CI checks should be rerun label Oct 6, 2026
@PureWeen

PureWeen commented Oct 7, 2026 •

Copy link
Copy Markdown
Member

@copilot Please continue this PR's passkey-removal stamp-consistency fix and its existing call-site feedback.

First confirm current main still differs from the documented credential-change stamp contract and that this PR remains applicable. If it is already fixed or a human design decision is needed, report that rather than inventing unrelated changes. Otherwise bring this PR up to date with main as needed, resolve conflicts, and address valid outstanding review feedback and PR-caused CI failures within the existing functional scope.

Use faithful regression coverage for the actual removal and sign-in-refresh paths, demonstrating failure without the fix and success with it. Preserve existing valid behavior; do not weaken tests or suppress warnings just to make CI green. Report unrelated or infrastructure failures with evidence and no code change.

Preserve the PR's current non-draft status. Do not merge, close, relabel, or work on other issues or PRs. Do not assess or discuss security implications. Use GPT models only, with no subagents; report if you cannot honor this request.

Please reply with what changed, exact validation results, and any remaining blockers.

@halter73 halter73 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We could consider expanding the passkey-deletion flow in TestBasicInteractionAsync to verify the RefreshSignInAsync bit keeps a valid session even after the security stamp update. We'd probably want to update it to use a fake clock and zero validation interval like this Identity functional test, but I don't think it's necessary.

Copilot AI commented Oct 7, 2026

Copy link
Copy Markdown
Contributor Author

@copilot Please continue this PR's passkey-removal stamp-consistency fix and its existing call-site feedback.

First confirm current main still differs from the documented credential-change stamp co...

Current main (4f8bb2b672) still removes and persists the passkey without calling UpdateSecurityStampInternal, so this PR remains applicable against the documented credential-change stamp contract. The existing branch already contains the stamp update and success-only template sign-in refresh.

Acceptance criteria: faithful removal/persistence and sign-in-refresh regressions fail for the expected reason without each fix and pass with it; stores without stamp support and failed-removal behavior remain valid; relevant existing tests pass unchanged.

CI evidence: the latest product CI and template CI checks passed (Azure builds 1608513 and 1608515). The newer failed Copilot run stopped before implementation with Model "claude-opus-5" is not available, not a product test failure.

No edits, merge, commits, or new test runs were performed. I stopped because the available publishing tool updates the PR description, and automated review offers no GPT-only model selector. I cannot guarantee your unchanged-body and GPT-only/no-subagent constraints with those tools. The PR remains open and non-draft with its title and body unchanged. Red/green behavioral validation remains outstanding.

@Youssef1313
Youssef1313 merged commit 2dd4d9d into main Oct 8, 2026
37 of 38 checks passed
@Youssef1313
Youssef1313 deleted the copilot/update-removepasskeyasync branch October 8, 2026 11:24
@dotnet-milestone-bot dotnet-milestone-bot Bot added this to the 12.0-preview1 milestone Oct 9, 2026
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.

7 participants