oficina / home Public

Correct continuation audit date and navigation cookie lifetime description

Paul Campbell pushed by paul@keymail.dev 02c92722bbb7a41bb18762479aa4eff93beb1b4f parent 3bc2271
3 files changed, +4 −4
  • docs/superpowers/specs/{2026-09-08-credential-return.md => 2026-09-07-credential-return.md} +1 −1
  • internal/home/signin_return_factor_test.go +1 −1
  • internal/home/signin_return_test.go +2 −2
diff --git a/docs/superpowers/specs/2026-09-08-credential-return.md b/docs/superpowers/specs/2026-09-07-credential-return.md
similarity index 82%
rename from docs/superpowers/specs/2026-09-08-credential-return.md
rename to docs/superpowers/specs/2026-09-07-credential-return.md
index bea4718..b501134 100644
--- a/docs/superpowers/specs/2026-09-08-credential-return.md
+++ b/docs/superpowers/specs/2026-09-07-credential-return.md
@@ -4,7 +4,7 @@ Status: bounded draft, independent highest-model review pending; base651e5b3. No
Authority: Home design §4 credential-origin separation, §5.1 sign-in, §5.2 optional second factor/recovery and existing freshness-protected routes. No auth protocol, factor or freshness rule changes.
-RequireFresh already redirects stale enrol/codes GETs to /signin?return_to=... . The form discards that navigation intent and completeSignIn always redirects /. Carry only the exact compiled destinations /passkey/enrol and /passkey/codes in a host-only Secure HttpOnly SameSite=Lax cookie, Path=/, lifetime ten minutes. No address, identity, authority or content is stored. A hostile allowed target grants nothing: its existing RequireFresh still applies. No custom signing/encryption/session protocol.
+RequireFresh already redirects stale enrol/codes GETs to /signin?return_to=... . The form discards that navigation intent and completeSignIn always redirects /. Carry only the exact compiled destinations /passkey/enrol and /passkey/codes in a host-only Secure HttpOnly SameSite=Lax cookie, Path=/, browser MaxAge ten minutes. This bounds ordinary browser navigation retention, not a server-validated authentication lifetime. Replaying an allowed navigation target grants no authority; existing session and freshness validation remain authoritative. No address, identity, authority or content is stored. A hostile allowed target grants nothing: its existing RequireFresh still applies. No custom signing/encryption/session protocol.
GET /signin accepts one query return_to only when it matches the allowlist. Plain sign-in clears previous intent; the existing force=1 Keymail fallback preserves a validated existing intent. Invalid/duplicate query input clears it. POST body/query return_to never supplies intent. Verified magic-link or Keymail completion validates the cookie again and clears it. Missing/cross-browser cookie returns /. Failed first-factor completion never mints a session; ordinary Keymail failure preserves navigation through its force fallback.
diff --git a/internal/home/signin_return_factor_test.go b/internal/home/signin_return_factor_test.go
index 09036f0..c0f44ff 100644
--- a/internal/home/signin_return_factor_test.go
+++ b/internal/home/signin_return_factor_test.go
@@ -11,7 +11,7 @@ import (
"github.com/carlosframework/rastrillo/webauthn/authtest"
)
-// Mutation-checked 2026-09-08: bypassing Gate or passing the original
+// Mutation-checked 2026-09-07: bypassing Gate or passing the original
// request allows factor bypass or hostile FormValue precedence and fails.
func TestCredentialReturnSecondFactors(t *testing.T) {
for _, first := range []string{"magic", "keymail"} {
diff --git a/internal/home/signin_return_test.go b/internal/home/signin_return_test.go
index 21e9ef4..16cc2e8 100644
--- a/internal/home/signin_return_test.go
+++ b/internal/home/signin_return_test.go
@@ -33,7 +33,7 @@ func intentFrom(w *httptest.ResponseRecorder) *http.Cookie {
return nil
}
-// Mutation-checked 2026-09-08: discarding validated intent restores the
+// Mutation-checked 2026-09-07: discarding validated intent restores the
// original wrong destination; trusting cookie values fails hostile cases.
func TestCredentialReturnMagicLink(t *testing.T) {
for _, target := range []string{"/passkey/enrol", "/passkey/codes"} {
@@ -143,7 +143,7 @@ func TestCredentialReturnCookieGrantsNothing(t *testing.T) {
}
}
-// Mutation-checked 2026-09-08: replacing AuthTime with time.Now grants
+// Mutation-checked 2026-09-07: replacing AuthTime with time.Now grants
// access after an old gesture and fails this freshness check.
func TestCredentialReturnDoesNotRefreshOldKeymailGesture(t *testing.T) {
app := newTestApp(t)