Account is the entry point for anything a person does with their OpenVireo account: signing up and in,
unlocking, opening vaults, sharing. See Concepts for what the keys and secrets are.
Connecting
import { Account } from "@openvireo/sdk";
const account = await Account.connect({
issuer: "https://accounts.openvireo.com", // discovery: /.well-known/openvireo-configuration
device: { name: "Firefox on Linux", platform: "web" },
storage: browserStorage(), // where sessions and trusted-device keys live
});
connect reads the issuer’s discovery document to find the account and sync servers, then loads a stored
session if storage has one. A resumed session is signed in but locked (account.signedIn is true,
account.unlocked false): the keys need the master password again.
device.platform is one of web, cli, connect, qt-linux, qt-macos, qt-windows. The name shows up in
the user’s device list.
Storage
storage keeps the session (refresh token, device id), the trusted device’s Secret Key, and each vault’s sync
state. Pick one for the platform:
| Storage | Where | Use it for |
|---|---|---|
browserStorage() | IndexedDB, encrypted with a non-extractable WebCrypto key | browsers |
new FileStorage(path) from @openvireo/sdk/storage/node | a JSON file with mode 0600 | Node and Bun tools |
new MemoryStorage() (the default) | memory | tests, one-off scripts |
Anything with get, set and delete (the KeyValueStorage interface) works, and EncryptedStorage wraps
another storage with an AES-GCM key you provide.
Signing up
const { secretKey, userId } = await account.register({ email, password });
showEmergencyKit(secretKey); // the only time the Secret Key is shown; the user must keep it
register makes the Secret Key and keyset on the device, registers OPAQUE, and leaves the account signed in
and unlocked. With trustDevice (the default) this device keeps the Secret Key for next time. Later,
account.secretKey() returns the kept copy, so the user can download the Emergency Kit again.
Signing in
await account.login({
email,
password,
secretKey, // only needed the first time on this device
totp: () => askForCode(), // asked only when the account has two-factor authentication on
});
totp can be a code or a function, which is called again (with attempt and the last error) when a code
is wrong. A missing code throws mfa_required, too many wrong ones mfa_expired.
Without secretKey on a device that doesn’t trust this account yet, login throws invalid_secret_key: ask
for the Secret Key and try again. Pass trustDevice: false on shared computers.
Unlocking and locking
if (account.signedIn && !account.unlocked) await account.unlock(password);
account.lock(); // wipes the keys from memory; the session stays
await account.logout(); // ends the session on the server and forgets it here
await account.logout({ forgetDevice: true }); // also forgets the trusted Secret Key
unlock needs no OPAQUE round trip: it unwraps the keyset with the password and the kept Secret Key.
The session can also end on its own: when the refresh token expires, is revoked from another device, or is
used twice (token_reused, a sign of a stolen token). Listen for it:
const stop = account.onSignedOut((reason) => { // "session_expired" | "token_reused" | "unauthorized" | "logout"
showSignIn();
});
The account itself
account.email; // the signed-in email
account.userId;
account.fingerprint; // this account's public key fingerprint, for others to compare
await account.changePassword({ current, next }); // signs the other devices out
await account.requestEmailChange("[email protected]"); // mails a code to the new address
await account.changeEmail({ email: "[email protected]", code, password });
const url = await account.webSessionUrl("/settings"); // a one-time link into the account website (60 s)
Changing the password keeps the same Secret Key and keyset, so vaults and shares keep working.
The lower-level account.auth (an AuthClient) covers every account server route, for things Account has no
helper for, such as the device list and two-factor setup:
const { devices } = await account.auth.listDevices(); // name, platform, last_seen_at, current, …
const old = devices.find((d) => !d.current && d.name === "Old laptop");
if (old) await account.auth.revokeDevice(old.id);
The SDK docs cover OpenVireo SDK, develop (86e6cd2), last updated 26 October 2026. Found a mistake? Edit this page on GitHub.