oficina / docs Public

Specify bounded single-use pending account links

Paul Campbell pushed by paul@keymail.dev 4cb40cb9f4e3b874e521e432eeccabfe517e5ae9 parent 5dc526f
1 file changed, +1 −1
  • implementation/home-account-link.md +1 −1

CI passed — run details

diff --git a/implementation/home-account-link.md b/implementation/home-account-link.md
index 6621b9e..91ec3c7 100644
--- a/implementation/home-account-link.md
+++ b/implementation/home-account-link.md
@@ -8,7 +8,7 @@ Use the reviewed shared handoff module for exact issuer/audience verification, b
An additive identity-link table records exact issuer, opaque subject and existing person_id. Unique constraints cover both (issuer, subject) and (issuer, person_id). A link is created only after fresh authentication of both identities and an explicit same-origin confirmation POST. Concurrent identical requests are idempotent; conflicting links fail without replacing either row. No unlink or reassignment in this stage. Linking itself grants no new team standing or document permission.
-A completed Home exchange first produces a short-lived, sealed pending identity proof in this browser, rather than immediately replacing any existing Docs session. The proof contains verified subject, issuer, actual auth_time and expiry, never the raw assertion. The shared consumer consumes the assertion before creating that proof. An unlinked user then verifies their existing Docs account using local authentication; confirmation requires both actual authentication times within five minutes and not in the future. A stale Home proof requests fresh authentication from Home. A stale local session uses the existing fresh-session gate. A new ordinary session is not fresh evidence when its original AuthTime is old.
+A completed Home exchange first produces a short-lived, sealed pending identity proof in this browser, rather than immediately replacing any existing Docs session. The proof contains verified subject, issuer, actual auth_time and expiry, never the raw assertion. Store it sealed in a pending-link row addressed by the hash of a random 32-byte host-only Secure/HttpOnly/Lax cookie. Keep it at most five minutes, sweep on boot and new starts, and refuse new rows at a hard 10,000-row cap. Confirmation atomically consumes this row with the unique mapping write, so replaying a copied cookie cannot perform another link. Bind sealed payload to its row hash and the exact local origin. The shared consumer consumes the assertion before creating that proof. An unlinked user then verifies their existing Docs account using local authentication; confirmation requires both actual authentication times within five minutes and not in the future. A stale Home proof requests fresh authentication from Home. A stale local session uses the existing fresh-session gate. A new ordinary session is not fresh evidence when its original AuthTime is old.
The confirmation page must clearly identify the local Docs account being connected. A fresh POST binds the proof to that authenticated local person in one transaction and consumes the pending proof. An already signed-in different account never gets silently replaced. Preserve the intended safe local resource path in bounded sealed browser state; default missing or malformed paths to the app root. Do not use query parameters or plaintext cookies for identity proof, raw assertions or resource paths. Local signin callback returns to the confirmation continuation only while a valid pending link exists; preserve normal signin otherwise.