@x-multi/sdk
v0.2.1
Published
VAULT_AUTH sign-in + cross-device sign-request protocol for XRPL dApps. Powered by X-Multi.
Maintainers
Readme
@x-multi/sdk
Sign in to your dApp with an XRPL multisig vault. One-line VAULT_AUTH integration powered by X-Multi.
Pre-release. API is stable but the underlying hosted flow is being wired up. Subscribe to releases on GitHub for
v0.2.0(full functionality).
What this solves
Most XRPL sign-in tools (Xaman, WalletConnect) ask a single wallet to sign a nonce. That doesn't work for multisig vaults — there's no single key. CTOs, DAOs, and treasury accounts get locked out unless they hack a regular key onto the vault, which defeats the security multisig provides.
@x-multi/sdk lets your dApp accept multisig vaults as first-class identities. Three lines on your end; the user's signer quorum collaboratively signs an on-chain proof; you verify the proof and treat the vault as logged in.
Install
npm install @x-multi/sdk
# or
pnpm add @x-multi/sdk
# or
yarn add @x-multi/sdkUse
import { signInWithXMulti } from '@x-multi/sdk'
async function handleLogin() {
const proof = await signInWithXMulti({ domain: window.location.hostname })
// proof.vaultAddress — the authenticated XRPL r-address
// proof.signers — the addresses that signed off
// proof.session — one-shot session ID (server-side replay protection)
// proof.txHash — on-chain proof transaction
await myExistingLoginEndpoint(proof.vaultAddress, proof.session)
}That's it. The SDK opens X-Multi's hosted sign-in flow in a popup, drives the user through proof creation, verifies the resulting on-chain transaction, and resolves with the proof.
Server-side: enforce one-shot sessions
The XRPL transaction backing each proof is public. To prevent replay, track each session server-side and reject reuse:
CREATE TABLE used_vault_proofs (
session_id UUID PRIMARY KEY,
vault TEXT NOT NULL,
accepted_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);// In your /api/login handler, after the SDK resolves on the client:
await db.insert('used_vault_proofs', { session_id, vault })
// ^ unique-constraint failure here = someone is replaying. Reject.Full integration guide: xmulti.app/integrate
API
signInWithXMulti(options)
| Option | Type | Default | Notes |
|---------------|----------------------------|--------------------------|--------------------------------------------------------------------|
| domain | string | (required) | Your dApp's domain. Embedded in the proof + enforced server-side. |
| popup | boolean | true | If false, redirects the whole page instead of using a popup. |
| popupSize | { w: number; h: number } | { w: 480, h: 720 } | Popup dimensions. |
| returnUrl | string | (required when popup: false) | Where to redirect after sign-in. Must be same-origin. |
| timeoutMs | number | 300_000 | Reject if the flow doesn't complete within this many ms. |
Returns: Promise<SignInResult> — see types.ts.
Rejects with SignInError (code-tagged) on any failure path. Codes:
popup_blocked, popup_closed, timeout, session_mismatch, domain_mismatch, verify_failed, expired, invalid_response, unknown.
Browser support
ES2020 + DOM. Anything that can run modern JavaScript and open window.open (i.e. every desktop browser, every mobile browser running outside a strict iframe).
License
MIT
