Skip to content

fix: hand off setup sign-in via POST body, not URL token#66

Merged
andregoepel merged 1 commit into
mainfrom
bugfix/setup-login-handoff-post
Jul 4, 2026
Merged

fix: hand off setup sign-in via POST body, not URL token#66
andregoepel merged 1 commit into
mainfrom
bugfix/setup-login-handoff-post

Conversation

@andregoepel

Copy link
Copy Markdown
Owner

Closes #50 (F1 — admin credentials placed in the login handoff URL query string).

What

Setup.razor completed 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)

  1. Security (F1): a token in the URL leaks into reverse-proxy access logs, browser history, and Referer headers. Because the token embedded the password, anyone reading those sinks could recover it.
  2. It was already broken: the identity package's CookieLoginMiddleware (present in the pinned v1.1.3) accepts the handoff only as a same-origin POST with the handle in Request.Form["token"], and rejects the query string (their Migrate Marten-backed DataProtection key ring store from finance-app into the foundation #40). So the existing GET /login?token=… failed the handoff — the freshly created admin was redirected to /Account/Login instead 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 let SignInHandoff render 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.
  • No existing test renders Setup (it depends on identity services + JS interop), and SignInHandoff is 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.Blazor 1.1.3 — no package bump required.

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
@andregoepel
andregoepel merged commit 520b604 into main Jul 4, 2026
3 checks passed
@andregoepel
andregoepel deleted the bugfix/setup-login-handoff-post branch July 5, 2026 03:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Security] Admin credentials placed in login handoff URL query string (F1)

1 participant