@page "/login" @layout LoginLayout @using Microsoft.AspNetCore.Authorization @* Login MUST stay anonymously reachable — [AllowAnonymous] overrides the RequireAuthorization(ViewerPolicy) that MapRazorComponents() applies, so the cookie scheme's LoginPath="/login" redirect lands here for unauthenticated users. The card is the shared kit's : it renders a NATIVE static
(username/password + hidden returnUrl). A native form submit is not a Blazor event, so it reaches the minimal-API POST /auth/login endpoint regardless of this app's InteractiveServer render mode. supplies the token that PostLoginAsync's antiforgery.ValidateRequestAsync checks. NOTE: the POST target is /auth/login, NOT /login. This @page lives at "/login" and the Razor Components endpoint matches ALL methods, so a POST to /login collided with the minimal-API MapPost("/login") and threw AmbiguousMatchException (HTTP 500). Posting to a distinct /auth/login path (mirroring ScadaBridge) keeps the GET page and POST handler from sharing a route. *@ @attribute [AllowAnonymous] @code { /// Original protected URL the operator was bounced from; round-tripped to POST /login. [SupplyParameterFromQuery(Name = "returnUrl")] private string? ReturnUrl { get; set; } /// Failure message surfaced by POST /login after a failed authentication. [SupplyParameterFromQuery(Name = "error")] private string? Error { get; set; } }