carlos / movement Public

A fresh session lands on the list, not the bill

auth's SignedInPath defaults to "/", so completing the Keymail ceremony
dropped an admin back on the public page they started from. Signing in here
has exactly one purpose.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Paul Campbell d3d546c1b7543c1125d3b3b2b46946685ab864dc parent 22fb41d
2 files changed, +32 −2
  • internal/movement/admin.go +6 −2
  • internal/movementtest/admin_test.go +26 −0
diff --git a/internal/movement/admin.go b/internal/movement/admin.go
index c70c9fb..b8cc4f7 100644
--- a/internal/movement/admin.go
+++ b/internal/movement/admin.go
@@ -41,8 +41,12 @@ func (a *app) mountAdmin(r chi.Router) error {
Mailer: a.mailer,
Authorize: a.env.IsAdmin,
SigninPath: "/signin",
- SessionTTL: adminSessionTTL,
- Logger: slogFor(),
+ // A fresh session lands on the list, not on the bill. Signing in here
+ // has exactly one purpose, and the default "/" sends an admin who
+ // just authenticated back to the public page they came from.
+ SignedInPath: "/admin",
+ SessionTTL: adminSessionTTL,
+ Logger: slogFor(),
})
if err != nil {
return err
diff --git a/internal/movementtest/admin_test.go b/internal/movementtest/admin_test.go
index ffb713b..56f9339 100644
--- a/internal/movementtest/admin_test.go
+++ b/internal/movementtest/admin_test.go
@@ -273,3 +273,29 @@ func TestRemovedAdminLosesAccessOnTheNextRequest(t *testing.T) {
t.Error("a removed admin still reached /admin with their old session")
}
}
+
+// Signing in has exactly one purpose here, so a fresh session lands on the
+// list. auth's default is "/", which would send an admin who has just
+// authenticated back to the public bill they started from.
+func TestSigningInLandsOnTheAdminList(t *testing.T) {
+ h := newAdminApp(t)
+
+ post(t, h, "/signin", url.Values{"address": {adminAddr}})
+ body := h.Mail.waitForMailTo(t, adminAddr, 1)
+ link := anyLink.FindString(body)
+ if link == "" {
+ t.Fatalf("no sign-in link in the message:\n%s", body)
+ }
+ u, err := url.Parse(link)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ req := httptest.NewRequest(http.MethodGet, u.RequestURI(), nil)
+ rec := httptest.NewRecorder()
+ h.ServeHTTP(rec, req)
+
+ if got := rec.Header().Get("Location"); got != "/admin" {
+ t.Errorf("a fresh session landed on %q, want /admin", got)
+ }
+}