Guides

Sessions and store

KeyringSession, clients and the key-value byte store, and how their names map to OS keyring entries.

The session API follows tauri-plugin-stronghold: a session (Stronghold: snapshot) holds clients, each client has a store (key → bytes) and any number of vaults (next guide).

import { KeyringSession } from "tauri-plugin-keyring-store-api";

const session = await KeyringSession.load("/app/secrets", "");
const client = await session.loadClient("desktop");
const store = client.getStore();

await store.insert("settings.json", new TextEncoder().encode('{"theme":"dark"}'));
const bytes = await store.get("settings.json");
const json = bytes && new TextDecoder().decode(bytes);

await session.unload();

The session path is not a file

The first argument of KeyringSession.load(path, password) is not a path on disk, on any OS. It is a logical id: the plugin hashes it, together with the client, vault and record names, into the account name of each OS keyring entry.

You passEffect
The same string on every platformThe same namespace everywhere (the usual case).
Different stringsSeparate namespaces, e.g. one per user or per wallet.
Something that looks like a path, e.g. /wallet/mainFine: it is only a label, no folder has to exist.

Use stable ASCII-like ids. Changing the id later makes the old entries unreachable through the API (they stay in the OS store).

The password is not checked

password exists for Stronghold compatibility. It is not verified: any password opens any session, and it encrypts nothing. Rust wipes it at once and never stores or compares it. Pass "" unless you are migrating code that already passes one. Access control comes from the OS store and the plugin permissions; see Security notes.

Session lifetime

  • KeyringSession.load (initialize) adds the path to an in-memory list of loaded sessions of this process.
  • Store, vault and procedure calls on a path that is not loaded fail with session not initialized: <path>.
  • session.unload() (destroy) removes the path from the list. The entries are not deleted.
  • session.save() writes nothing (every write is already in the OS store) but fails like Stronghold when the session is not loaded.
  • The list is per process: after an app restart call load again.

Clients

session.createClient(name) and session.loadClient(name) do the same thing: check that the session is loaded and return a KeyringClient. A client needs no creation in the OS store; both exist for Stronghold parity. client.getStore() and client.getVault(name) make no IPC call.

Store

MethodDoes
get(key)Resolves to the bytes (Uint8Array) or null.
insert(key, value, lifetime?)Writes the record, replacing an existing one. lifetime is ignored: OS stores have no expiry.
remove(key)Deletes the record and resolves to its previous bytes, or null.

Values are number[] or Uint8Array. Store the text of JSON with TextEncoder as above.

Text or byte ids

Client, vault, record and store key names may be strings or bytes (Uint8Array, ArrayBuffer, number[]). A byte id that equals the UTF-8 of a text id is the same id: store.get([107]) reads the record written with store.insert("k", …).

How names become entries

Every record is one OS keyring entry under your service name. Its account is built from the first 8 bytes (16 hex characters) of the SHA-256 of each name:

KindAccount
Store recordkp:v1:<session>:<client>:st:<key>
Vault recordkp:v1:<session>:<client>:v:<vault>:<record>

So names of any length fit OS limits, and the OS store shows only hashes. The kp: prefix is reserved: the password commands refuse it so the webview cannot read vault keys through getPasswords.

Values are stored as Base64 text. On Windows this limits a store record or vault secret to about 960 bytes, see Windows.

The OS stores cannot list entries, so neither can the plugin: keep your own index of keys if you need one.