Login tokens in the OS keychain: secure_session commands (cinny #105, step 1) #28

Merged
jared merged 3 commits from desktop-keychain into main 2026-09-30 20:19:01 -04:00
Owner

Desktop half of cinny #105, step 1. Pairs with LotusGuild/cinny#254. Either can merge first.

New commands: secure_session_supported / _set / _get / _clear.

  • Windows: Credential Manager, via keyring 3.6 (windows-native). The entry is session under service Lotus Chat.
    • Contents: secrets only (userId, deviceId, accessToken, refreshToken).
    • Size cap: 1,200 chars. Windows' limit is 2,560 bytes.
    • Threading: the calls run on the blocking pool, off the main thread.
  • Other platforms: supported = false, and the other commands answer "not supported on this platform".
    • Linux Secret Service can prompt to unlock a wallet at startup, which needs its own testing.
    • No new Linux dependency: without a platform feature, the crate only has its mock store.

Tested

  • Rust (keyring's mock store):
    • round trip and clear, including clearing an empty keychain;
    • incomplete and oversized sessions are rejected with nothing written;
    • the JSON shape the web client sends;
    • a realistic OIDC session fits;
    • 15 tests pass in total.
  • Linux release build: the commands answer as designed, and login is unaffected.
  • Windows: type-checked only.

⚠️ Windows test before merging

With the cinny PR in the build:

  1. Log in. Settings → General shows "Login in the system keychain: A copy of your login is kept…".
  2. Open Credential Manager → Windows Credentials: there's an entry for session.Lotus Chat.
  3. Log out. The entry is gone.
  4. Restart the app while logged in. Still logged in, no prompts.

🤖 Generated with Claude Code

https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA

Desktop half of **cinny #105, step 1**. Pairs with **LotusGuild/cinny#254**. Either can merge first. New commands: `secure_session_supported` / `_set` / `_get` / `_clear`. - **Windows:** Credential Manager, via `keyring` 3.6 (`windows-native`). The entry is `session` under service `Lotus Chat`. - **Contents:** secrets only (`userId`, `deviceId`, `accessToken`, `refreshToken`). - **Size cap:** 1,200 chars. Windows' limit is 2,560 bytes. - **Threading:** the calls run on the blocking pool, off the main thread. - **Other platforms:** `supported = false`, and the other commands answer *"not supported on this platform"*. - Linux Secret Service can prompt to unlock a wallet at startup, which needs its own testing. - No new Linux dependency: without a platform feature, the crate only has its mock store. ## Tested - **Rust (keyring's mock store):** - round trip and clear, including clearing an empty keychain; - incomplete and oversized sessions are rejected with nothing written; - the JSON shape the web client sends; - a realistic OIDC session fits; - 15 tests pass in total. - **Linux release build:** the commands answer as designed, and login is unaffected. - **Windows:** type-checked only. ## ⚠️ Windows test before merging With the cinny PR in the build: 1. Log in. Settings → General shows **"Login in the system keychain: A copy of your login is kept…"**. 2. Open *Credential Manager → Windows Credentials*: there's an entry for `session.Lotus Chat`. 3. Log out. The entry is gone. 4. Restart the app while logged in. Still logged in, no prompts. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
jared added 1 commit 2026-09-29 00:25:23 -04:00
Commands for the web client to keep a copy of the login tokens in the OS
keychain: secure_session_supported / _set / _get / _clear.

- Windows: Credential Manager via the keyring crate (3.6, windows-native),
  entry "session" in service "Lotus Chat". Only the secrets are stored
  (userId, deviceId, accessToken, refreshToken); the serialized value is
  capped at 1200 chars (Windows' limit is 2560 bytes).
- Other platforms: supported = false and the other commands answer "not
  supported on this platform" (Linux Secret Service can prompt to unlock a
  wallet at startup; that needs its own testing). No new Linux dependency:
  without a platform feature the crate only has its mock store.
- Keychain calls run on the blocking pool, off the main thread.

Step 1 is a mirror only (the web client still reads its session from
localStorage); see the cinny PR.

Tests: round trip + clear, clearing an empty keychain, incomplete and
oversized sessions rejected with nothing written, the JSON shape the web
client sends, a realistic OIDC session fits (keyring's mock store). Linux
release build: commands answer as designed and login is unaffected.
Windows: type-checked only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
jared added 1 commit 2026-09-30 11:01:01 -04:00
jared added 1 commit 2026-09-30 20:18:54 -04:00
jared merged commit ec643c677a into main 2026-09-30 20:19:01 -04:00
Sign in to join this conversation.