Skip to content

Respect AllowRefresh in SecurityStampValidator cookie renewal#65803

Open
matantsach wants to merge 3 commits intodotnet:mainfrom
matantsach:fix/64301-allow-refresh-security-stamp
Open

Respect AllowRefresh in SecurityStampValidator cookie renewal#65803
matantsach wants to merge 3 commits intodotnet:mainfrom
matantsach:fix/64301-allow-refresh-security-stamp

Conversation

@matantsach
Copy link

Summary

SecurityStampValidator.SecurityStampVerified() unconditionally sets context.ShouldRenew = true after verifying the security stamp. This means the authentication cookie gets rewritten on every validation cycle — even when AllowRefresh is explicitly set to false on the authentication properties.

This is inconsistent with CookieAuthenticationHandler.CheckForRefreshAsync(), which guards its renewal logic behind var allowRefresh = ticket.Properties.AllowRefresh ?? true. A user who sets AllowRefresh = false expects fixed-lifetime sessions that don't get extended by background activity, but the security stamp validator silently overrides that intent.

The fix mirrors the handler's pattern:

context.ShouldRenew = context.Properties.AllowRefresh ?? true;

The in-memory principal is still replaced regardless — ReplacePrincipal is not gated — so the user's claims stay fresh within the request. Only the cookie rewrite (session extension) is suppressed.

The IssuedUtc recalculation for non-sliding expiration is also gated on ShouldRenew, since it serves the renewal path and has no effect when the cookie isn't rewritten.

Test plan

  • OnValidateIdentityDoesNotRenewWhenAllowRefreshIsFalse — explicit AllowRefresh = false produces ShouldRenew == false, principal still replaced
  • OnValidateIdentityRenewsWhenAllowRefreshIsNotSet — null AllowRefresh (the common case) defaults to ShouldRenew == true, preserving existing behavior
  • Existing OnValidateIdentityDoesNotExtendExpirationWhenSlidingIsDisabled still passes — IssuedUtc adjustment unaffected when AllowRefresh is not set

Fixes #64301

SecurityStampValidator.SecurityStampVerified() unconditionally sets
context.ShouldRenew = true, which extends the session even when
AllowRefresh is explicitly set to false. This is inconsistent with
CookieAuthenticationHandler.CheckForRefreshAsync(), which respects
AllowRefresh for sliding expiration.

Guard ShouldRenew with the same AllowRefresh check. The in-memory
principal is still replaced (claims updated) regardless — only the
cookie rewrite is gated.

Fixes dotnet#64301
Copilot AI review requested due to automatic review settings March 17, 2026 13:02
@github-actions github-actions bot added the area-identity Includes: Identity and providers label Mar 17, 2026
@dotnet-policy-service dotnet-policy-service bot added the community-contribution Indicates that the PR has been added by a community member label Mar 17, 2026
@dotnet-policy-service
Copy link
Contributor

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

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This pull request fixes ASP.NET Core Identity’s security-stamp validation behavior so that cookie renewal respects AuthenticationProperties.AllowRefresh, aligning it with CookieAuthenticationHandler refresh semantics and enabling fixed-lifetime sessions when AllowRefresh = false.

Changes:

  • Update SecurityStampValidator<TUser>.SecurityStampVerified() to set context.ShouldRenew based on context.Properties.AllowRefresh ?? true instead of always renewing.
  • Gate the non-sliding-expiration IssuedUtc recalculation behind context.ShouldRenew.
  • Add tests covering AllowRefresh = false (no renewal) and AllowRefresh unset (default renewal behavior preserved).

Reviewed changes

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

File Description
src/Identity/Core/src/SecurityStampValidator.cs Stops unconditional cookie renewal after successful security-stamp validation; renewal now honors AllowRefresh, and IssuedUtc adjustment only happens on actual renewal.
src/Identity/test/Identity.Test/SecurityStampValidatorTest.cs Adds coverage ensuring ShouldRenew is suppressed when AllowRefresh = false, and remains enabled by default when AllowRefresh is not set.

You can also share your feedback on Copilot code review. Take the survey.

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 community-contribution Indicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Validating the security stamp is extending the session if allowRefresh is false

2 participants