Skip to content

Profile ETag changes on a failed sign-in, so an open profile form gets a false 412 #1398

Description

@marcelo-maciel

Since #1387, GET /identity/profile publishes the user's ConcurrencyStamp as the ETag, and PUT /identity/profile answers 412 when If-Match does not match it. The stamp is not a profile version, though: ASP.NET Identity rotates it on every write to the AspNetUsers row, and some of those writes have nothing to do with the profile.

What rotates it

Measured against the Docker Compose stack built from main plus the open i18n PRs (which don't touch sign-in or the stamp), reading the ETag between steps:

Step ETag changed
Two reads, nothing in between no
One sign-in with a wrong password yes
Token refresh no
A clean successful sign-in no
A successful sign-in right after a failed one yes (it resets AccessFailedCount)

A failed sign-in goes through UserManager.AccessFailedAsync, which increments AccessFailedCount and saves the user, and the save rotates the stamp.

Effect

A user has Settings > Profile open. Anyone types a wrong password for that account: a bot, a colleague, or the user themselves on another device. The user presses Save, gets 412, and sees "Profile changed elsewhere", but nothing in the profile changed. The dashboard handles 412 correctly by re-reading and asking for a deliberate re-save, so no data is lost. The false conflict is still wrong, and anyone who can guess the email can cause it on demand.

Options

  1. Derive the ETag from the profile fields the PUT actually writes (first name, last name, phone, image, and locale once i18n lands), e.g. a hash, instead of from ConcurrencyStamp. Writes that don't touch the profile then leave the tag alone. The precondition check would compare that hash, and the store's own ConcurrencyStamp check still catches a lost race at save time.
  2. Keep ConcurrencyStamp and document that security-counter writes cause a spurious 412. This is the smallest change, but the behaviour stays surprising.

I'd go with option 1. Happy to send the PR if you agree.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions