Skip to content

API v2: SecretSpace 3 accounts and sessions (2.0.0-alpha.1) - #10

Merged
usermaneGermane merged 1 commit into
mainfrom
v3-server-accounts
Nov 10, 2026
Merged

usermaneGermane merged 1 commit into
mainfrom
v3-server-accounts

Conversation

@usermaneGermane

Copy link
Copy Markdown
Owner

What

Phase 2 of SecretSpace 3, server side: accounts, sessions and per-vault blobs. Version 2.0.0-alpha.1, a test version for the Lab.

New routes under /v2/. The 2.x routes (/vault/<user> with the shared token) are unchanged, so 2.x clients, including prod, sync as before.

Route Who What
GET /v2/prelogin/<user> anyone Argon2id salt and cost from the stored keyset. Unknown names get a stable made-up answer, so it doesn't reveal which names exist
POST /v2/accounts server token = sign-up code create the account and its personal vault
POST /v2/login anyone Login Key → 12-hour session. Wrong tries are rate-limited
POST /v2/logout, GET /v2/me session —
PUT /v2/me/keyset session new master password; all other sessions end
GET/PUT /v2/vaults/<id>[/meta] member same revision/If-Match/history rules as 2.x. Readers get 403 on PUT. Non-members get 404. The blob must be PMV3 for this vault

Never on the server: a master password, a Secret Key or a vault key. The Login Key is stored as a salted scrypt hash, and sessions are stored hashed.

Where the data lives: <store>/_v2/. No 2.x name can start with _, so it never collides with a 2.x vault.

Design deviation: the Login Key is hashed with scrypt from the standard library instead of Argon2id. It's already a 256-bit key, so a slow hash adds nothing, and the server stays package-free.

Checks

  • tests/test_server_v2.py: 48 new tests. All server tests pass.
  • Mutation check: I broke 11 guards one at a time, and the tests caught every one:
    • reader write, vault-id check, session expiry, non-member access, lockout;
    • sign-up token, duplicate names, sessions after a password change;
    • exact-name login, disabled account, pre-login leak.
  • passman_server.py is identical in both server repos.
  • Windows only: the build now handles pre-release versions (file version 2.0.0.1, as in the client). The test build of SecretSpace-Server-Installer.exe 2.0.0-alpha.1 compiled fine; it was not installed.

The clients that use this come in the matching client PRs (3.0.0-alpha.3 / 1.0.0-alpha.3).

🤖 Generated with Claude Code

https://claude.ai/code/session_011ojnyVg7ccsR3pZ64s7aRH

…a.1)

Phase 2 of the 3.0 design (DESIGN-3.0.md section 6). New routes under /v2/,
beside the 2.x /vault/<user> routes, which are unchanged:

- GET  /v2/prelogin/<user>  the Argon2id salt and cost from the stored
  keyset; for a name with no account a made-up but stable answer (HMAC with
  a server key), so it does not tell which names exist
- POST /v2/accounts         sign-up, with the server's token as the code;
  makes the account and its personal vault
- POST /v2/login            Login Key -> session (12 h); scrypt-hashed Login
  Key compared in constant time, a dummy hash for unknown names, 10 wrong
  tries in 15 min pause the name for a minute
- POST /v2/logout, GET /v2/me
- PUT  /v2/me/keyset        new password: new keyset + Login Key, every
  other session of the account ends
- GET/PUT /v2/vaults/<id>[/meta]  the 2.x blob rules per vault (revision,
  If-Match, 428/409, history, key generation), members only (404 alike for
  "not yours" and "no such vault"), readers cannot PUT (403), and a blob
  must be PMV3 naming this vault

Data in <store>/_v2/ (a 2.x name cannot start with "_"). Sessions are
stored hashed; nothing on disk logs anyone in. The 2.x vault GET/PUT code
moved into _send_blob/_store_blob, shared by both APIs; 2.x behaviour is
unchanged (POST on a 2.x path still answers 501). /health also says
"api": [1, 2].

Deviation from the design: the Login Key is hashed with scrypt (standard
library) rather than Argon2id; it is already a 256-bit HKDF output, so a slow
hash adds nothing, and the server keeps needing no packages.

tests/test_server_v2.py: 48 tests. Mutation check: 11 deliberately broken
guards (reader write, vault-id check, session expiry, non-member access,
lockout, sign-up token, duplicate names, sessions after a password change,
exact-name login, disabled accounts, pre-login leak), all caught.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011ojnyVg7ccsR3pZ64s7aRH
@usermaneGermane
usermaneGermane merged commit 6d004ce into main Nov 10, 2026
3 checks passed
@usermaneGermane
usermaneGermane deleted the v3-server-accounts branch November 10, 2026 07:00
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.

1 participant