@oslp/vault-embed
v0.6.0
Published
Embed the OSLP vault — the custody surface where sponsored individuals enroll and read — in any registered shell page. Typed events, one mount call, the embed contract handled for you.
Readme
@oslp/vault-embed
Embed the OSLP vault — the custody surface where a sponsored individual
enrolls with a passkey (or a browser-managed password) and reads documents sealed to them — in
your own page, with one call. This package is the reference SDK over the vault embed contract
(spec/vault-embed.md in the OSLP hub); the protocol is normative, the SDK is convenience. You
may implement the protocol directly instead.
Your page stays yours: branding, layout, product. The vault renders inside a cross-origin iframe that your page cannot see into — keys are derived and used inside it, documents decrypt inside it, and what your code gets back is status, never content.
Install
npm install @oslp/vault-embedYour embedding origin must be registered as a shell with your operator — registration feeds the vault's framing policy and the links your backend mints.
Enrollment page
Your backend sponsors an individual and gets an enroll link; the person opens it on your page:
import { OSLPVault } from '@oslp/vault-embed';
const vault = OSLPVault.mount('#secure-slot', {
operator: 'https://api.example-operator.com',
brand: 'Acme Diagnostics', // your registered display name → labels the passkey
user: session.firstName, // person label — browser-internal, never a URL/server
...OSLPVault.linkParams(), // takes t (+ label/mode/rung) from YOUR page URL
}); // ...and strips them from the address bar + history
vault.on('enrolled', () => showBanner('Secure access ready.'));
vault.on('error', (e) => { if (e.code === 'link_expired') offerResend(); });linkParams() carries the stripped link in history.state, so a reload resumes instead of
finding the URL the strip just emptied — you do not need to stash the token yourself, and it never
reappears in the address bar, a bookmark, or a referrer. It is per-tab and dies with the history
entry. Treat "no token" as genuinely no link (see the no-token guard below), not as a refresh.
Read page
A document link carries label (and possibly rung hints) — linkParams() forwards them:
const vault = OSLPVault.mount('#secure-slot', {
operator: OPERATOR,
...OSLPVault.linkParams(), // token + label + mode/rung, verbatim
});
vault.on('opened', () => analytics.track('document_viewed')); // status only
vault.on('error', (e) => { if (!e.retryable) showHelp(e.code); });
// Later, same frame, another document:
vault.open(otherLabelId);Events
| Event | Payload | Meaning |
|---|---|---|
| ready | — | The vault is loaded and listening. |
| enrolled | — | Enrollment / return ceremony completed. |
| opened | — | A document decrypted and rendered. You learn that, never what. |
| error | { code, retryable } | A flow failed; the vault shows its own error UI. Stable codes: link_expired, link_invalid, not_for_this_access, no_longer_available, prf_unavailable, in_app_browser, network, cancelled — treat unknown codes as non-retryable. |
| resize | { height } | Content height changed. Pass autoSize: true to have the SDK size the frame, or CSS-size it yourself (most hosts do). |
What this package never sees
No plaintext, no document names, no keys, no passkey material, no passwords. The user label you
pass travels over the browser-internal message channel — never a URL (URLs land in server logs)
and never any server — and the vault discards it once the passkey is named. If you skip the SDK,
honor the same rule.
Sizing
The frame is width: 100% with no default height. Either CSS-size it (recommended — e.g. a
fixed-height stage like the reference shell) or pass autoSize: true to follow resize events.
License
Apache-2.0. Contributions under the Developer Certificate of Origin — sign your commits off.
