Setup and Installation
Canonical setup guide for the Blockstream Enterprise Custody JavaScript SDK, including registry access, package selection, key generation, and first-time SDK initialization.
This page is the canonical setup guide for the Blockstream Enterprise Custody JavaScript SDK. Complete it before following the onboarding, wallet, tokenization, or request guides.
Before you begin
You need:
- Node.js 18 or later
- Access to a running Blockstream Enterprise Custody instance
- Access to the private JavaScript package registry
- A valid npm auth token for that registry
- An admin or existing onboarding flow that can provision your device credentials
How to set up the JS registry
The SDK packages are distributed through a private registry. Installing them requires both:
- access to the private package repository or registry
- an npm auth token
If either one is missing, package installation will fail.
Add this to your project-level .npmrc or user-level ~/.npmrc:
@blockstream:registry=https://enterprise.blockstream.com/integrations/npm
//enterprise.blockstream.com/integrations/npm/:_authToken=${NPM_TOKEN}Then export the token:
export NPM_TOKEN=your_token_hereAsk your Blockstream administrator for:
- the registry URL
- the npm token
- confirmation that your account can access the SDK packages
Choose the packages you need
| Package | Install when you need it | Why it exists |
|---|---|---|
@blockstream/cryptic | Always | Runtime client for signing, encryption, decryption, and COSE |
@blockstream/ecs-registry | Most ECS integrations | Typed ECS request and response schemas |
@blockstream/amp-registry | AMP or tokenization flows on Liquid | Typed AMP-specific request and response schemas |
zod | When using any registry package | Peer dependency used for schema parsing and typing |
node-forge | When using @blockstream/cryptic | Runtime dependency externalized by the library build |
uuid | Optional, only if your application uses generated IDs | Convenient for request IDs and resource creation examples |
@noble/curves | Optional, only for manual ECDSA key generation examples | Advanced/manual key generation path |
@blockstream/registry-shared exists to support the registry packages and is not usually a package that application developers install directly.
Install the SDK
Core ECS integration
Use this for most applications that need authenticated ECS requests and typed ECS schemas.
npm install @blockstream/cryptic @blockstream/ecs-registry zod node-forgeAMP and tokenization
Add the AMP registry if you are issuing assets, managing restrictions, or working with AMP wallet flows on Liquid.
npm install @blockstream/cryptic @blockstream/ecs-registry @blockstream/amp-registry zod node-forgeCredentials and values you will need
The SDK constructor needs five runtime values:
| Value | Source | Purpose |
|---|---|---|
clientRsaPrivateKeyPem | Generated locally | Decrypt server responses |
clientEcdsaPrivateKey | Generated locally | Sign requests |
deviceUuid | Returned by the server during API-user creation or regular-user device authorization | Bind requests to a registered device |
serverRsaPublicKeyPem | Returned during onboarding or provided by your Blockstream administrator | Encrypt request material for the server |
serverEcdsaPublicKey | Returned during onboarding or provided by your Blockstream administrator | Verify server signatures |
About deviceUuid
deviceUuid is generated by the server. You do not invent it locally.
It is returned by one of these flows:
- API user onboarding: the server returns
device_uuidwhen the user is created - Regular user onboarding: the server returns the permanent
device_uuidwhen the invitation is authorized
Persist deviceUuid with the matching private keys. Future authenticated requests depend on that exact pairing.
Key generation
There are two supported approaches:
- Recommended: use the SDK helper
- Advanced: generate keys manually with
@noble/curvesplus Web Crypto ornode-forge
Recommended: built-in key generation
Use the helper from @blockstream/cryptic/utils unless you have a specific reason to control key generation yourself.
import { generateUserKeyPairs } from '@blockstream/cryptic/utils'
const keys = await generateUserKeyPairs()
console.log(keys.ecdsa.privateKeyHex)
console.log(keys.ecdsa.publicKeyHex)
console.log(keys.rsa.privateKeyPem)
console.log(keys.rsa.publicKeyPem)The helper returns:
keys.ecdsa.privateKeyHexkeys.ecdsa.publicKeyHexkeys.rsa.privateKeyPemkeys.rsa.publicKeyPem
When you construct Blockstream, convert the ECDSA hex key into bytes:
import { Buffer } from 'buffer'
import { Blockstream } from '@blockstream/cryptic'
import { generateUserKeyPairs } from '@blockstream/cryptic/utils'
const keys = await generateUserKeyPairs()
const client = new Blockstream(
keys.rsa.privateKeyPem,
Buffer.from(keys.ecdsa.privateKeyHex, 'hex'),
deviceUuid,
serverRsaPublicKeyPem,
Buffer.from(serverEcdsaPublicKeyHex, 'hex'),
)Advanced: manual ECDSA generation with @noble/curves
Install @noble/curves only if you are not using the built-in helper:
npm install @noble/curvesimport { Buffer } from 'buffer'
import { p256 } from '@noble/curves/nist'
const ecdsaPrivateKey = p256.utils.randomSecretKey()
const ecdsaPublicKey = p256.getPublicKey(ecdsaPrivateKey, true)
const ecdsaPrivateKeyHex = Buffer.from(ecdsaPrivateKey).toString('hex')
const ecdsaPublicKeyHex = Buffer.from(ecdsaPublicKey).toString('hex')Advanced: manual RSA generation with Web Crypto
async function exportPem(key: CryptoKey, format: 'pkcs8' | 'spki') {
const exported = await crypto.subtle.exportKey(format, key)
const base64 = btoa(String.fromCharCode(...new Uint8Array(exported)))
const lines = base64.match(/.{1,64}/g) ?? []
if (format === 'pkcs8') {
return `-----BEGIN PRIVATE KEY-----\n${lines.join('\n')}\n-----END PRIVATE KEY-----`
}
return `-----BEGIN PUBLIC KEY-----\n${lines.join('\n')}\n-----END PUBLIC KEY-----`
}
const rsaKeyPair = await crypto.subtle.generateKey(
{
name: 'RSA-OAEP',
modulusLength: 2048,
publicExponent: new Uint8Array([1, 0, 1]),
hash: 'SHA-256',
},
true,
['encrypt', 'decrypt'],
)
const rsaPrivateKeyPem = await exportPem(rsaKeyPair.privateKey, 'pkcs8')
const rsaPublicKeyPem = await exportPem(rsaKeyPair.publicKey, 'spki')Advanced: manual RSA generation with node-forge
Use this path if your environment already standardizes on node-forge for key material handling.
import forge from 'node-forge'
const rsaKeyPair = forge.pki.rsa.generateKeyPair({ bits: 2048, e: 0x10001 })
const rsaPrivateKeyPem = forge.pki.privateKeyToPem(rsaKeyPair.privateKey)
const rsaPublicKeyPem = forge.pki.publicKeyToPem(rsaKeyPair.publicKey)Initialize the SDK
Once you have your key material, deviceUuid, and the server public keys, create a reusable Blockstream instance:
import { Buffer } from 'buffer'
import { Blockstream } from '@blockstream/cryptic'
const client = new Blockstream(
clientRsaPrivateKeyPem,
Buffer.from(clientEcdsaPrivateKeyHex, 'hex'),
deviceUuid,
serverRsaPublicKeyPem,
Buffer.from(serverEcdsaPublicKeyHex, 'hex'),
)Verify the setup
Make a simple authenticated request to confirm the client is wired correctly:
const request = await client.request({
action: 'get',
resource: '/users/me',
})
const response = await fetch(`${ECS_BASE_URL}/request`, {
method: 'POST',
headers: { 'Content-Type': 'application/octet-stream' },
body: Buffer.from(request),
})
const result = await client.parse(new Uint8Array(await response.arrayBuffer()))
console.log(result.payload)If you receive your user profile back, the setup is working.
Where to go next
Getting Started
Start here to install the Blockstream Enterprise Custody JavaScript SDK, onboard a device, and make your first authenticated request with the built-in broadcaster helpers.
Making Requests
How to send single, batch, and atomic batch requests with the built-in broadcaster helpers in the SDK, including Node-side mTLS transport when `/request` requires client certificates.