Skip to main content
This guide covers cryptographic key generation, credential signing, and verification workflows using the Beltic CLI.

Key Management

Generating Keys

The CLI supports two signature algorithms: EdDSA (Ed25519) - Recommended:
beltic keygen --alg EdDSA --out my-key.pem
ES256 (P-256) - For NIST compliance:
beltic keygen --alg ES256 --out my-key.pem
Output files:
  • my-key.pem - Private key (keep secret!)
  • my-key.pub.pem - Public key (share for verification)

Key Storage Best Practices

Development:
mkdir -p ~/.beltic/keys
chmod 700 ~/.beltic/keys
mv my-key.pem ~/.beltic/keys/
chmod 600 ~/.beltic/keys/my-key.pem
Production:
  • Use HSM or KMS (AWS KMS, Azure Key Vault, GCP KMS)
  • Rotate keys every 90 days
  • Never commit keys to version control

Signing Workflows

Developer Credential Signing

beltic sign \
  --payload developer-credential.json \
  --key ~/.beltic/keys/dev-key.pem \
  --out developer-credential.jwt \
  --kid did:web:example.com#dev-key-1 \
  --issuer did:web:issuer.beltic.dev \
  --subject did:web:developer.example.com
Parameters explained:
  • --payload: Input credential JSON
  • --key: Private key file
  • --out: Where to save JWS token (algorithm auto-detected from key)
  • --kid: Key ID (appears in JWT header)
  • --issuer: Issuer DID (appears in iss claim)
  • --subject: Subject DID (appears in sub claim)

Agent Credential Signing

beltic sign \
  --payload agent-credential.json \
  --key ~/.beltic/keys/agent-key.pem \
  --out agent-credential.jwt \
  --kid did:web:example.com#agent-key-1 \
  --subject did:web:agent.example.com
Note: Agent credentials require --subject flag because the subject DID differs from the credential’s agentId.

Self-Signing Credentials

Self-signing allows developers to sign their own credentials where the issuer and subject are the same DID. This is useful for:
  • Development and testing - Quick iteration without external issuer
  • Self-hosted agents - Agents that manage their own identity
  • Decentralized scenarios - No central authority required
Self-signing a DeveloperCredential:
beltic sign \
  --payload developer-credential.json \
  --key ~/.beltic/keys/dev-key.pem \
  --issuer did:web:developer.example.com \
  --subject did:web:developer.example.com \
  --kid did:web:developer.example.com#dev-key-1 \
  --out self-signed-credential.jwt
Self-signing an AgentCredential:
beltic sign \
  --payload agent-credential.json \
  --key ~/.beltic/keys/agent-key.pem \
  --issuer did:web:agent.example.com \
  --subject did:web:agent.example.com \
  --kid did:web:agent.example.com#agent-key-1 \
  --out self-signed-agent.jwt
Key points:
  • Issuer DID (--issuer) and subject DID (--subject) are identical
  • The credential’s issuerDid and subjectDid fields should match
  • Self-signed credentials are cryptographically valid but may have different trust implications
  • Verifiers can check if iss === sub to detect self-signed credentials
Verifying self-signed credentials:
beltic verify \
  --token self-signed-credential.jwt \
  --key dev-key.pub.pem
The verification process is identical - self-signed credentials pass all cryptographic checks.

Custom Claims

Add custom JWT claims:
beltic sign \
  --payload credential.json \
  --key key.pem \
  --out token.jwt \
  --issuer did:web:custom-issuer.com \
  --audience did:web:platform.example.com \
  --kid custom-key-id
Custom claims:
  • --issuer: Override default issuer
  • --audience: Add aud claim for specific verifier
  • --kid: Custom key identifier

Skip Schema Validation

For debugging only:
beltic sign \
  --payload test-credential.json \
  --key key.pem \
  --skip-schema
Warning: Production credentials must always validate against schema!

Verification Workflows

Basic Verification

beltic verify \
  --token credential.jwt \
  --key public-key.pub.pem
Checks performed:
  1. JWT format valid
  2. Signature mathematically valid
  3. Claims valid (not expired, etc.)
  4. Schema validation against credential type
Success output:
✓ Signature valid
✓ Claims valid
✓ Schema valid
VALID
Failure output:
✗ Signature verification failed
INVALID: Signature does not match

Constrained Verification

Verify with specific expectations:
beltic verify \
  --token credential.jwt \
  --key public-key.pub.pem \
  --issuer did:web:issuer.beltic.dev \
  --audience did:web:platform.example.com
Additional checks:
  • Issuer matches expected DID
  • Audience matches expected DID
  • Rejects credentials from untrusted issuers

Verification from File or String

From file:
beltic verify --token credential.jwt --key key.pub.pem
From string:
beltic verify --token "eyJhbGci..." --key key.pub.pem
From stdin:
cat credential.jwt | beltic verify --key key.pub.pem

Algorithm Selection

When to use EdDSA:

  • Default choice for most use cases
  • Faster signing and verification
  • Smaller signatures
  • Modern, recommended by cryptographers

When to use ES256:

  • Enterprise compliance requirements
  • NIST/FIPS mandated environments
  • Legacy system compatibility
  • Regulatory requirements (some jurisdictions)
Performance comparison:
OperationEdDSAES256
Key generation0.5ms2ms
Signing0.3ms1.5ms
Verification0.8ms2ms
Signature size64 bytes64 bytes

Key Rotation

When rotating keys:
# 1. Generate new key
beltic keygen --alg EdDSA --out new-key.pem

# 2. Re-sign all active credentials
for cred in credentials/*.json; do
  beltic sign \
    --payload "$cred" \
    --key new-key.pem \
    --out "$(basename "$cred" .json).jwt"
done

# 3. Update DID document with new key
# (Manual step - update did:web document or DID registry)

# 4. Securely delete old key after grace period
shred -u old-key.pem

Error Handling

Common Signing Errors

Error: “Schema validation failed”
Cause: Credential doesn't match schema
Solution: Run ajv validate first, fix errors
Error: “Failed to read key file”
Cause: Wrong path or permissions
Solution: Check file exists and is readable
Error: “Unsupported algorithm”
Cause: Algorithm not EdDSA or ES256
Solution: Use --alg EdDSA or --alg ES256

Common Verification Errors

Error: “Signature invalid”
Cause: Wrong public key or credential modified
Solution: Ensure using matching public key
Error: “Token expired”
Cause: Current time > exp claim
Solution: Credential expired, request new one
Error: “Issuer mismatch”
Cause: Token issuer != expected issuer
Solution: Verify issuer DID or remove constraint

Production Checklist

Before deploying to production:
  • Generate production keys in secure environment
  • Store private keys in HSM/KMS
  • Set up key rotation schedule (90 days)
  • Document key IDs and DID mappings
  • Test verification with all expected verifiers
  • Set appropriate expiration dates (6-12 months)
  • Configure monitoring for signature failures
  • Establish key recovery procedures

Next Steps

Managing Fingerprints

Agent manifest and fingerprint workflows

Command Reference

Complete CLI documentation

Security Best Practices

Production security guidance