Skip to content

Reauthentication members on the Identity UI SetPassword page model #69376

Description

@rolandVi

Background and Motivation

The Identity UI Manage/SetPassword page adds a password to an account that does not have one, which
is how someone who signed up with an external login gets a password. Right now the only thing it checks
is the sign-in cookie.

I want the page to ask the user to confirm with a credential the account already has before it accepts a
new password, the same gate the Blazor template got in #68522, reauthentication before adding a passkey
or setting a password. The views need somewhere to read the confirmation state from and two handlers to
post to, and in Identity UI that means the page model.

Proposed API

Identical additions in the V4 and V5 namespaces, since Identity UI ships both.

namespace Microsoft.AspNetCore.Identity.UI.V5.Pages.Account.Manage.Internal;

public abstract class SetPasswordModel : PageModel
{
    public SetPasswordModel.InputModel Input { get; set; }
    public string? StatusMessage { get; set; }
+   public bool IsReauthenticated { get; set; }
+   public IList<UserLoginInfo>? CurrentLogins { get; set; }

    public virtual Task<IActionResult> OnGetAsync();
    public virtual Task<IActionResult> OnPostAsync();
+   public virtual Task<IActionResult> OnPostReauthenticateAsync(string provider);
+   public virtual Task<IActionResult> OnGetReauthenticationCallbackAsync();
}
namespace Microsoft.AspNetCore.Identity.UI.V4.Pages.Account.Manage.Internal;

public abstract class SetPasswordModel : PageModel
{
    public SetPasswordModel.InputModel Input { get; set; }
    public string? StatusMessage { get; set; }
+   public bool IsReauthenticated { get; set; }
+   public IList<UserLoginInfo>? CurrentLogins { get; set; }

    public virtual Task<IActionResult> OnGetAsync();
    public virtual Task<IActionResult> OnPostAsync();
+   public virtual Task<IActionResult> OnPostReauthenticateAsync(string provider);
+   public virtual Task<IActionResult> OnGetReauthenticationCallbackAsync();
}

CurrentLogins is nullable to separate "this store cannot support the feature" from "this account has no
linked logins". The two need different messages: the first is something the app developer has to fix, the
second is something the user can fix.

Usage Examples

Nobody calls these from C#. They are reached from the view, which is the call site reviewers should judge:

@if (!Model.IsReauthenticated)
{
    @if (Model.CurrentLogins is null)
    {
        <p class="text-danger">Setting a password requires a user store that supports security stamps.</p>
    }
    else
    {
        <form asp-page-handler="Reauthenticate" method="post">
            @foreach (var login in Model.CurrentLogins)
            {
                <button type="submit" name="provider" value="@login.LoginProvider">
                    Confirm with @login.ProviderDisplayName
                </button>
            }
        </form>
    }
}

OnGetReauthenticationCallbackAsync is the return leg of the provider challenge, reached as
?handler=ReauthenticationCallback.

Risks

Behaviour change on an existing path: yes, two of them. A user store that does not support security
stamps can no longer set a password through this page, because the confirmation is bound to the stamp and
there is nothing to bind to. The page says so explicitly rather than failing as a refused confirmation.
Separately, an account whose linked provider is no longer configured in the app has nothing to confirm
with and cannot set a password here.

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

    api-proposalapi-suggestionEarly API idea and discussion, it is NOT ready for implementationarea-identityIncludes: Identity and providers

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions