Skip to content

Encryption

Use sync encrypt and decrypt hooks.

ts
const keyPrefix = "my-key:";

const storage = oto<{ token: string }>({
  encryption: {
    encrypt: (plainText) => btoa(`${keyPrefix}${plainText}`),
    decrypt: (cipherText) => {
      const decoded = atob(cipherText);
      if (!decoded.startsWith(keyPrefix)) throw new Error("Invalid key");
      return decoded.slice(keyPrefix.length);
    },
    migrate: true,
  },
});

migrate: true upgrades plain JSON entries to the encrypted wrapper when values are read.

Security warning: btoa/atob is encoding, not cryptographic encryption. Use a real cipher (for example Web Crypto AES-GCM) for production.

Security note: encryption-at-rest does not protect against active XSS. If malicious code runs in your page, it can still access decrypted data.

Reserved keys note: __oto_encrypted and __oto_payload are reserved for the encryption envelope. Objects matching that shape will be treated as encrypted wrappers.