Beltic logo
Cli guideWorkflows

Signing & Verification Workflows

Complete guide to key management, signing credentials, and verification workflows.

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