docs(auth): what reviewing the register's side settled
ADR 0017: the account's reset without the phrase waits 72 hours, as the developer confirmed; adding an authenticator takes a code from one confirmed before; a password set up for good stays through resets; and per-network limits count by the visitor's address behind a trusted proxy. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
4e425cb17f
commit
40e902bd4e
1 changed files with 20 additions and 7 deletions
|
|
@ -92,7 +92,9 @@ through `AccountRegister`, the session being theirs.
|
|||
- **Sign-up** (`password.set`) needs an address: the person's own, or one a mailed code
|
||||
proves in the same call, which makes an anonymous person identified under their ID.
|
||||
The password signs in only once an authenticator is confirmed; until then a new setup
|
||||
replaces it. The register checks what it can: salt 16 bytes, Argon2id `argon2id13` at
|
||||
replaces it, but never once one was, also while a reset leaves the account without
|
||||
one (a reset's row stays until a new authenticator is confirmed): a session got
|
||||
another way would skip the reset's 72 hours. The register checks what it can: salt 16 bytes, Argon2id `argon2id13` at
|
||||
3–16 passes and 64 MiB–1 GiB, the verifier 1 < v < N padded to N, public keys 32 bytes,
|
||||
each wrapping a 24-byte nonce and 112 bytes.
|
||||
- **SRP's identity I is the sign-in's challenge ID**, not the account's: x comes from
|
||||
|
|
@ -106,11 +108,21 @@ through `AccountRegister`, the session being theirs.
|
|||
`setupIncomplete` (no confirmed authenticator) and `notDue` (a reset waiting) only
|
||||
after a right password. Begun sign-ins are limited to 10 an hour per address and 30
|
||||
per network; challenges last two minutes and are taken once.
|
||||
- **Per-network limits count by the visitor's address** (`networkOf`): behind a
|
||||
reverse proxy every connection is the proxy's, so for a connection from a proxy the
|
||||
operator trusts (`TRUSTED_PROXIES`, Caddy's fixed address in `deploy/compose.yaml`) the
|
||||
last address of `X-Forwarded-For`, the one the proxy saw itself; never the `Forwarded`
|
||||
header, which Caddy passes on as sent. Serverpod's own limit on anonymous accounts
|
||||
counts by the connection and is off; the anonymous endpoint counts them itself.
|
||||
(Found reviewing this step: until then every per-network limit, anonymous sign-ups'
|
||||
included, was the whole instance's.)
|
||||
- **TOTP secrets** are sealed with XChaCha20-Poly1305 (pub.dev's `cryptography`, pure
|
||||
Dart, pinned) under a key derived from `totpKey`, bound to the row's account and ID;
|
||||
each step's code passes once (a conditional update of the last step). At most 10
|
||||
authenticators; one not confirmed within a day is pruned; the last confirmed stays;
|
||||
removing one, or new recovery codes, takes a code (10 tries an hour per account).
|
||||
removing one, or new recovery codes, takes a code (10 tries an hour per account), and
|
||||
so does adding one while a confirmed one exists (a code from that one too, decided by
|
||||
the developer on 20 Oct): a session alone adds no second factor of its own.
|
||||
- **Resets** (D3): an authenticator reset takes effect 72 hours after the password and
|
||||
a mailed code or the recovery phrase ask, with a mail to the address at once (none
|
||||
sent, none started); a sign-in with a code calls off every reset waiting. Once due,
|
||||
|
|
@ -121,21 +133,22 @@ through `AccountRegister`, the session being theirs.
|
|||
phrase, or an account reset, ends the account's sessions on the register's server.
|
||||
- **The account reset without the phrase waits 72 hours too, with a mail at the start**
|
||||
(a mailed code asks, a new one carries it out once due; a sign-in with the password
|
||||
calls it off): a proposal, for the developer to confirm. Carried out: a new password
|
||||
and new keys, no authenticators.
|
||||
calls it off; confirmed by the developer on 20 Oct). Carried out: a new password and
|
||||
new keys, no authenticators.
|
||||
- **Keys:** without all three keys (or without email sign-in) the instance offers no
|
||||
password sign-in (`passwordSignIn` in its basics), so an instance can take these
|
||||
releases before its operator makes keys; a key set but shorter than 32 characters
|
||||
stops the server.
|
||||
- **GitHub** (D2): an account with a password and a confirmed authenticator is refused
|
||||
(`usePassword`), one without signs in as before and the app leads to setting up an
|
||||
- **GitHub** (D2): an account with a password that had a confirmed authenticator (one
|
||||
now, or a reset standing: `SignInWays.passwordOnly`) is refused (`usePassword`), one
|
||||
without signs in as before and the app leads to setting up an
|
||||
address, a password and an authenticator (its ways in say what is missing): a refusal
|
||||
there would lock out GitHub's people on a new device, as nothing else signs them in.
|
||||
Where passwords are offered, no new GitHub account is linked (`deprecated`). From
|
||||
`GITHUB_SIGN_IN_ENDS` (a day the operator sets) GitHub signs nobody in (`ended`), the
|
||||
basics stop offering it, and the daily pruning forgets every GitHub ID.
|
||||
- **Email codes** still sign in (until step 3), but not into an account with a password
|
||||
and a confirmed authenticator (`usePassword`), which a code alone would bypass.
|
||||
that had a confirmed authenticator (`usePassword`), which a code alone would bypass.
|
||||
|
||||
Step 3 (email codes go): sign-up keeps `password.set` with its code; `emailCode.verifyCode`
|
||||
and `emailSignIn.signIn` go, and with them the switch token; accounts with an address but
|
||||
|
|
|
|||
Loading…
Reference in a new issue