fix: hand off setup sign-in via POST body, not URL token#66
Merged
Conversation
Setup completed by navigating to /login?token=<protected LoginInfo>, so the handle — which wraps the admin's plaintext password — travelled in the URL, leaking into access logs, browser history, and Referer headers. The identity package's CookieLoginMiddleware already accepts the handoff only as a same-origin POST with the handle in the request body (and rejects the query string), so the GET handoff was also silently broken: the new admin was bounced to the login page instead of being signed in. Use the package's SignInHandoff component (as LoginForm does): set the single-use handle and let it POST it in the body. The credential never enters the URL. Closes #50
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #50 (F1 — admin credentials placed in the login handoff URL query string).
What
Setup.razorcompleted by navigating to/login?token=<protected LoginInfo>— where the handle wraps the admin's plaintext password. It now sets a single-use handle and renders the identity package's<SignInHandoff Action="/login" Handle="@_handle" />component, which POSTs the handle in the request body. The credential never enters the URL.Why (two problems, one fix)
Refererheaders. Because the token embedded the password, anyone reading those sinks could recover it.CookieLoginMiddleware(present in the pinned v1.1.3) accepts the handoff only as a same-origin POST with the handle inRequest.Form["token"], and rejects the query string (their Migrate Marten-backed DataProtection key ring store from finance-app into the foundation #40). So the existingGET /login?token=…failed the handoff — the freshly created admin was redirected to/Account/Logininstead of being signed in. This restores the intended "created → signed in" flow.How
Mirrors the package's own
LoginForm.razor: validate/create, set_handle = LoginTokens.Protect(new LoginInfo(...)), and letSignInHandoffrender a hidden form and submit it as a top-level POST (body, not URL;Referrer-Policy: no-referrer; single-use handle; same-origin enforced by the middleware).Verification
dotnet build -c Release— 0 errors;dotnet test -c Release— 80/80.Setup(it depends on identity services + JS interop), andSignInHandoffis the package's own tested component, so this relies on mirroring the canonical pattern + a build. Runtime sign-in is best confirmed in a host (andregoepel.dev).Note
This unblocks the last medium+ audit finding. The server-side rework it depends on is already released in the pinned
AndreGoepel.Marten.Identity.Blazor1.1.3 — no package bump required.