Security architecture and integration practices
Keyban embedded wallets are non-custodial. The user's private key is never reconstructed in one place — not on the device, not on Keyban's servers. This page describes how that property is enforced and what an integrator owns at the boundary.
Two-share signing
Every Keyban account is backed by a Threshold Signature Scheme (TSS): a client share held by the SDK on the user's side, and a server share held by the Keyban backend. A signature is the result of a co-signing protocol between the two — neither party ever materialises the full private key.
Client
Keyban SDK
Holds the client share, runs the local half of the TSS protocol.
Client share
Stored via ClientShareProvider. Useless on its own.
Keyban backend
Co-signer
Runs the remote half of the TSS protocol, gated by an authenticated session.
Server share
Never leaves the backend. Never combined with the client share.
Ledger
Smart account / native account
Verifies the signature produced by the two-party protocol.
The TSS implementation is open-sourced in the repository under
signers/: ECDSA
(Schnorr-derived FROST variant) for EVM and Starknet, EdDSA for Stellar.
WASM bindings load the protocol inside the SDK so the cryptographic
primitives run in the browser sandbox.
Where the client share lives
The client share is your storage decision. The SDK does not assume any
backend — it consumes whatever you wire through
ClientShareProvider.
| Use case | Recommended backing |
|---|---|
| Prototypes, demos | localStorage (the Quick Start pattern) |
| Production web apps | Server-side storage tied to the authenticated user, encrypted at rest |
| Mobile / native wrappers | Platform secure enclave (Keychain, Keystore) via your native bridge |
Whatever you choose, the share is durable: losing it means losing access to the account. Plan recovery into your identity flow rather than relying on the share alone.
On-chain verification
The signature produced by the TSS protocol still has to be accepted by the destination ledger. Keyban uses the native account model on each chain:
- Base (EVM). Each user owns an ERC-4337
smart account (
SchnorrAccount) with a FROST Schnorr verifier wired through ERC-7913 multi-signer. OnlyUserOperations validated by the EntryPoint reach the account's business logic. - Stellar. Native Ed25519 accounts. The signature is produced jointly by the SDK and the backend before submission.
- Starknet. Native account abstraction with a Schnorr/Poseidon signer.
The product family pinned to the application determines which ledger is
used (DPP → Starknet, Loyalty → Stellar, Embedded Wallet → Base) and
the network is immutable per application. See
Plan your network environment.
Authentication
User authentication is delegated to better-auth, the engine wrapped by Keyban Auth. Supported methods are Email OTP, Phone OTP, Google OAuth and Auth0 — see Keyban Auth for the integration patterns.
The session cookie or JWT issued at sign-in carries no key material: it only authorises the SDK to start the co-signing protocol with the backend.
Transport security
All traffic between the SDK, the Keyban backend, and downstream ledgers runs over TLS 1.2 or higher. No part of the signing exchange happens in cleartext, and the WASM cryptographic primitives shipped to the browser are versioned alongside the SDK so a partner can pin a known build.
Server-to-server access
API keys (X-Api-Key) authenticate programmatic clients and are issued
from the Admin Console. They carry an explicit
{ resource: ['action'] } permission map; an API key issued by an
account Owner is not Owner-equivalent. See
Permissions & Roles for the full model and
the OR-logic between member roles and API key scopes.
What you own at the integration boundary
Most production incidents Keyban sees come from the small surface a partner controls. Treat the items below as a checklist before going live.
| Concern | What you do about it |
|---|---|
| Client share storage | Move off localStorage for production. Bind the share to the authenticated user on your side, encrypted at rest. |
| API keys | Server-side only. Never ship them in a browser bundle. Rotate via the Admin Console on suspicion of leak. |
| Permission scopes | Issue API keys with the narrowest { resource: ['action'] } your integration actually needs. |
| Inputs handling PII | Pass email and OTP through KeybanInput so the values stay inside the Keyban iframe boundary. |
| Network choice | Keep network: '*Sepolia' / '*Testnet' out of production builds. The application's network is immutable; testnet artefacts do not migrate to mainnet. |
| Error handling | Only SdkError exposes a stable code. For backend errors (Problem+JSON), branch on status and on (status, errors[]). See Handle API errors. |
Non-custodial by design
A custodian is an entity that, on its own, can move user funds. Keyban is structurally not a custodian: with full access to the backend an attacker still needs the client share to sign anything, and the client share never reaches Keyban. This property does not depend on an external attestation to hold — it is a consequence of how the wallets are constructed.
Keyban does not collect payment instruments, KYC documents, or biometric data. The user attributes your application asks for are your decision, and whatever your service stores about end-users on your side falls under the regulations applicable to your business — Keyban does not substitute for that responsibility.
For questions about specific regulations or audits in the context of an ongoing integration, contact security@keyban.io.