SDK Guide
Signing & Verification
Sign credentials as JWS tokens and verify signatures with the TypeScript SDK.
Complete SDK guide for signing credentials and verifying JWS tokens.
Key Generation
import { generateKeyPair } from '@beltic/sdk';
// EdDSA (recommended)
const { privateKey, publicKey } = await generateKeyPair('EdDSA');
// ES256 (NIST compliance)
const { privateKey, publicKey } = await generateKeyPair('ES256');Signing Credentials
import { signCredential } from '@beltic/sdk';
const token = await signCredential(credential, privateKey, {
alg: 'EdDSA',
issuerDid: 'did:web:issuer.beltic.dev',
subjectDid: credential.subjectDid,
keyId: 'did:web:issuer.beltic.dev#key-1',
audience: 'did:web:platform.example.com', // Optional
});
console.log('Signed token:', token);Self-Signing Credentials
Self-signing enables developers to sign their own credentials where issuerDid === subjectDid. This supports development workflows, self-hosted agents, and decentralized identity scenarios.
Self-signing with SDK:
import { signCredential, generateKeyPair } from '@beltic/sdk';
// Generate keys
const { privateKey, publicKey } = await generateKeyPair('EdDSA');
// Self-sign a DeveloperCredential
const myDid = 'did:web:developer.example.com';
const token = await signCredential(credential, privateKey, {
alg: 'EdDSA',
issuerDid: myDid, // Same as subject
subjectDid: myDid, // Same as issuer
keyId: `${myDid}#key-1`,
});
// Self-sign an AgentCredential
const agentDid = 'did:web:agent.example.com';
const agentToken = await signCredential(agentCredential, privateKey, {
alg: 'EdDSA',
issuerDid: agentDid,
subjectDid: agentDid,
keyId: `${agentDid}#agent-key-1`,
});Use cases:
- Development - Test credential workflows without external issuer
- Self-hosted agents - Agents that manage their own identity
- Decentralized systems - No central authority required
Verifying self-signed credentials:
import { verifyCredential } from '@beltic/sdk';
const result = await verifyCredential(token, {
keyResolver: async ({ kid, alg, iss }) => {
// Resolve public key from DID or local key store
return publicKey;
},
});
// Check if self-signed
const isSelfSigned = result.payload.iss === result.payload.sub;
console.log('Self-signed:', isSelfSigned);Self-signed credentials pass all cryptographic verification checks. Verifiers can detect self-signing by comparing iss and sub claims.
Verifying Credentials
import { verifyCredential } from '@beltic/sdk';
const result = await verifyCredential(token, {
keyResolver: async (did) => {
// Return public key for the DID
return publicKey;
},
expectedIssuer: 'did:web:issuer.beltic.dev',
expectedAudience: 'did:web:platform.example.com',
});
console.log('Verified:', result.credential);Key Import/Export
import { importKeyFromPEM, exportPublicKey, importPublicKey } from '@beltic/sdk';
// Import from PEM file
const privateKey = await importKeyFromPEM(pemString, 'EdDSA');
// Export public key as JWK
const jwk = await exportPublicKey(publicKey);
// Import public key from JWK
const importedKey = await importPublicKey(jwk, 'EdDSA');Complete Workflow Example
import {
validateDeveloperCredential,
validateAgentCredential,
signCredential,
verifyCredential,
generateKeyPair,
ValidationError,
SignatureError,
} from '@beltic/sdk';
async function credentialWorkflow() {
// 1. Validate credential before signing
const credential = { /* DeveloperCredential or AgentCredential */ };
const isDeveloper = 'legalName' in credential;
const validation = isDeveloper
? validateDeveloperCredential(credential)
: validateAgentCredential(credential);
if (!validation.ok) {
throw new ValidationError(validation.errors);
}
// 2. Generate keypair
const { privateKey, publicKey } = await generateKeyPair('EdDSA');
// 3. Sign credential
const issuerDid = 'did:web:issuer.beltic.dev';
const subjectDid = credential.subjectDid || credential.agentId;
const token = await signCredential(credential, privateKey, {
alg: 'EdDSA',
issuerDid,
subjectDid,
keyId: `${issuerDid}#key-1`,
audience: 'did:web:platform.example.com', // Optional
});
// 4. Verify credential
const verified = await verifyCredential(token, {
keyResolver: async ({ kid, alg, iss }) => {
// In production, resolve key from DID document or JWKS
// For this example, return the public key directly
return publicKey;
},
expectedIssuer: issuerDid,
expectedAudience: 'did:web:platform.example.com',
allowedAlgorithms: ['EdDSA'],
});
return {
token,
credential: verified.credential,
algorithm: verified.algorithm,
};
}Error Handling
import { ValidationError, SignatureError } from '@beltic/sdk';
try {
const token = await signCredential(credential, privateKey, options);
} catch (error) {
if (error instanceof ValidationError) {
// Credential validation failed
console.error('Validation errors:', error.format());
console.error('Issues by path:', error.byPath());
} else if (error instanceof SignatureError) {
// Signing failed
console.error('Signing error:', error.message);
console.error('Step:', error.step); // 'PARSE' | 'SIGNATURE' | etc.
} else {
throw error;
}
}
try {
const verified = await verifyCredential(token, options);
} catch (error) {
if (error instanceof SignatureError) {
console.error('Verification failed:', error.message);
console.error('Step:', error.step);
} else {
throw error;
}
}