vault: pass full connect/token crypto through session/login

Vaultwarden (2025.12.0/f21a3ada) returns both classic (Key/PrivateKey/Kdf*) and
v2 crypto (UserDecryptionOptions.MasterPasswordUnlock, AccountKeys) synthesized
from the classic stored fields. session/login now returns the whole native
connect/token response minus the transport tokens (under `connectToken`),
alongside the spec's protectedUserKey/privateKey/kdf aliases, so the SDK gets
whatever unlock path it uses. Temp diagnostic logs the response field NAMES
(values redacted) to empirically confirm on a real login.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-29 03:09:12 +00:00
co-authored by Claude Opus 4.8
parent aae0fbd0ea
commit 91ed03d514
+14 -1
View File
@@ -83,7 +83,19 @@ vaultRouter.post('/session/login', async (ctx) => {
clientId,
});
// Ciphertext to us — passed straight to the client, which decrypts on-device with the master key.
// TEMP diagnostic — field NAMES only (values redacted) to empirically confirm the crypto shape.
const names = (o: unknown) => (o && typeof o === 'object' ? Object.keys(o as object) : typeof o);
const udo = (d as { UserDecryptionOptions?: { MasterPasswordUnlock?: unknown } }).UserDecryptionOptions;
console.log(
`[vault] connect/token fields: ${Object.keys(d).join(',')} | UserDecryptionOptions=${JSON.stringify(names(udo))} | MasterPasswordUnlock=${JSON.stringify(names(udo?.MasterPasswordUnlock))} | AccountKeys=${JSON.stringify(names((d as { AccountKeys?: unknown }).AccountKeys))}`,
);
// Everything except the transport tokens (which the platform holds) is crypto material the SDK unlocks
// on-device — ciphertext to us. Vaultwarden returns BOTH classic (Key/PrivateKey/Kdf*) and v2
// (UserDecryptionOptions.MasterPasswordUnlock, AccountKeys); pass the whole native response through
// under `connectToken` so the SDK gets whatever it uses, alongside the spec's named aliases.
const connectToken: Record<string, unknown> = { ...d };
for (const k of ['access_token', 'refresh_token', 'token_type', 'expires_in']) delete connectToken[k];
return ctx.json({
ok: true,
protectedUserKey: pick(d, 'Key') ?? null,
@@ -94,6 +106,7 @@ vaultRouter.post('/session/login', async (ctx) => {
kdfMemory: pick(d, 'KdfMemory') ?? null,
kdfParallelism: pick(d, 'KdfParallelism') ?? null,
},
connectToken,
});
});