@sigcore/sdk
v2.0.0
Published
Iframe SDK for Sigcore wallet operations — secure key management for SaaS clients
Readme
@sigcore/sdk
v1.0 GA — pre-release / invitation-only. The public API is stable and covered by SemVer; access is gated. Contact
[email protected]for an invitation, a publishable key, and access to the seal-on-mint sessions endpoint. Once you have those, the integration below is everything.
Sigcore is a non-custodial wallet platform. Private
keys live inside an attested AMD SEV-SNP enclave; tenants never hold key
material. The SDK is a thin TypeScript bridge: it embeds a Sigcore-hosted
iframe (https://sdk.sigcore.io/bridge/) and exposes typed methods over a
hardened postMessage channel. Wallet creation, signing, HD derivation,
and signing-intent flows all return through this bridge — your application
code never touches a private key, mnemonic, or audience JWT.
Install
npm install @sigcore/sdkThe package is zero-dependency at runtime and ships as ES2022 ESM. Node ≥ 18 is required at build time; modern browsers (last 2 major versions of Chrome/Firefox/Safari/Edge) at runtime.
Quick start (Next.js App Router)
The SDK is a browser-only client. Mount it inside a client component and
hand it the client_secret your backend mints from
POST https://api.sigcore.io/v1/sessions.
// app/_components/SigcoreProvider.tsx
"use client";
import { useEffect, useRef, useState } from "react";
import { loadSigcore, type LoadSigcoreResult, SigcoreError } from "@sigcore/sdk";
const PUBLISHABLE_KEY = process.env.NEXT_PUBLIC_SIGCORE_PUBLISHABLE_KEY!;
// e.g. "sig_pk_live_xxxxxxxxxxxxxxxxxxxxxx"
export function SigcoreProvider({ children }: { children: React.ReactNode }) {
const sigcoreRef = useRef<LoadSigcoreResult | null>(null);
const [ready, setReady] = useState(false);
useEffect(() => {
let cancelled = false;
void (async () => {
const sigcore = await loadSigcore(PUBLISHABLE_KEY, {
onSessionExpired: async () => {
// Your backend mints a fresh client_secret per the seal-on-mint
// flow (it MUST seal_to: sigcore.client.getIframeReceiverKey()).
const sealed = await fetch("/api/sigcore/session", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({
receiverKey: sigcore.client.getIframeReceiverKey(),
}),
}).then((r) => r.json());
await sigcore.client.setClientSession(sealed.envelope);
},
});
if (cancelled) {
sigcore.destroy();
return;
}
sigcoreRef.current = sigcore;
// Initial session: again, your backend seals the client_secret to
// the bridge's HPKE receiver key before returning it.
const sealed = await fetch("/api/sigcore/session", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({
receiverKey: sigcore.client.getIframeReceiverKey(),
}),
}).then((r) => r.json());
await sigcore.client.setClientSession(sealed.envelope);
setReady(true);
})().catch((err) => {
if (err instanceof SigcoreError) {
console.error("Sigcore failed to load:", err.code, err.message);
} else {
throw err;
}
});
return () => {
cancelled = true;
sigcoreRef.current?.destroy();
sigcoreRef.current = null;
};
}, []);
if (!ready) return null;
return <>{children}</>;
}Then call wallet methods on sigcoreRef.current.client:
const { wallet } = await sigcore.client.createWallet({
orgId: "org_xxxxxxxx",
name: "Treasury",
algorithm: "SECP256K1_ECDSA",
});
const signed = await sigcore.client.signMessage({
orgId: "org_xxxxxxxx",
walletId: wallet.id,
messageHex: "0xdeadbeef", // hex-encoded message bytes
});Parent-page security requirements
The bridge is iframe-embedded. Your CSP must permit it:
Content-Security-Policy:
frame-src https://sdk.sigcore.io;
connect-src 'self' https://api.sigcore.io;Other notes:
- COEP-
require-corpis supported. The bridge response setsCross-Origin-Resource-Policy: cross-origin, so parents that opt into cross-origin isolation can still embed it. sandboxdefaults toallow-scriptsonly. The SDK adds the iframe itself; do not overridesandboxto addallow-same-origin— that re-enables a sandbox-escape vector documented inMIGRATION_V1.md§10.- No origin pre-registration. The bridge is open to embedding from any
origin. Trust is established by (a) publishable-key validation at session
exchange and (b)
api.sigcore.io's CORS allow-list pinned tohttps://sdk.sigcore.io. Tenants integrate by installing the SDK; nothing else is required. - Publishable keys are browser-safe. They identify a tenant but grant
no API access on their own. Commit them to source or expose them
through
NEXT_PUBLIC_*/VITE_*env vars. client_secretis not browser-safe. Mint it server-side viaPOST https://api.sigcore.io/v1/sessions(withseal_to: receiverKey) and return only the sealed envelope to the browser.
Migration from v0.x
Breaking changes since 0.x are documented in MIGRATION_V1.md.
The largest shifts:
loadSigcorenow takes the publishable key as its first positional argument.setSigcoreAccessTokenis gone. UsesetClientSession(envelope)with a sealed envelope from your backend.- The wire protocol bumped to major
2. Bridges built against1.xare rejected withINCOMPATIBLE_BRIDGE.
Reporting issues
Security reports: [email protected]. Public issue tracker:
NYXL-io/trustcore-sigcore-sdk.
