Creating Your First Credential
End-to-end tutorial creating a DeveloperCredential from template to verified JWS token.
This tutorial walks you through creating, signing, and verifying your first Beltic credential using the CLI.
What You'll Build
A complete DeveloperCredential workflow:
- Start from a template
- Customize for your identity
- Validate the structure
- Generate keys
- Sign into a JWS token
- Verify the signature
Time required: 15-20 minutes
Prerequisites
- Beltic CLI installed (Installation guide)
- beltic-spec repository cloned
- AJV CLI for validation:
npm install -g ajv-cli ajv-formats
Step 1: Choose a Template
Navigate to the beltic-spec examples:
cd beltic-spec/examples/developer/v1/tests
lsAvailable templates:
valid-individual-minimal.json- Solo developer, basic fieldsvalid-individual-complete.json- Individual with full KYBvalid-organization-tier1.json- Startup, basic org infovalid-organization-tier2-complete.json- Established company
Choose based on your entity type and KYB tier needs.
Step 2: Copy and Customize
cp valid-individual-minimal.json ~/my-developer-credential.json
cd ~Edit my-developer-credential.json with your information:
{
"credentialId": "generate-new-uuid-here",
"legalName": "Your Legal Name or Company Name",
"entityType": "individual", // or "corporation", "limited_liability_company"
"incorporationJurisdiction": {
"country": "US",
"region": "CA" // Optional: state/province
},
"businessEmail": "your.email@example.com",
"kybTier": "tier_1_basic",
"subjectDid": "did:web:yourdomain.com",
"issuerDid": "did:web:issuer.beltic.dev",
"issuanceDate": "2025-01-15T00:00:00Z",
"expirationDate": "2026-01-15T00:00:00Z",
...
}Generate UUID:
# On macOS/Linux
uuidgen | tr '[:upper:]' '[:lower:]'
# Or use online generatorKey fields to update:
credentialId- New UUIDlegalName- Your name/companyentityType- Match your entitybusinessEmail- Your emailsubjectDid- Your DIDissuanceDate/expirationDate- Current dates
Step 3: Validate Against Schema
ajv validate \
-s beltic-spec/schemas/developer/v1/developer-credential-v1.schema.json \
-d my-developer-credential.jsonSuccess output:
my-developer-credential.json validError output:
my-developer-credential.json invalid
[
{
"instancePath": "/businessEmail",
"message": "must match format \"email\""
}
]Fix any errors before proceeding.
Step 4: Generate Cryptographic Keys
beltic keygen \
--algorithm EdDSA \
--output dev-private-key.pemOutput:
Generated EdDSA keypair
Private key: dev-private-key.pem
Public key: dev-private-key.pub.pemImportant: Keep dev-private-key.pem secure! Never commit to version control.
Add to .gitignore:
echo "*.pem" >> .gitignore
echo "*.jwt" >> .gitignoreStep 5: Sign the Credential
beltic sign \
--payload my-developer-credential.json \
--key dev-private-key.pem \
--algorithm EdDSA \
--output developer-credential.jwt \
--kid did:web:yourdomain.com#dev-key-1Output:
Validating credential against schema...
Schema validation: ✓ PASSED
Signing credential...
Signed successfully
Token written to: developer-credential.jwt
Token size: 2,847 bytesThe JWT token contains:
- Header: Algorithm, type (
application/beltic-developer+jwt), key ID - Payload: Issuer, subject, expiration, full credential
- Signature: EdDSA signature over header + payload
Step 6: Verify the Signature
beltic verify \
--token developer-credential.jwt \
--key dev-private-key.pub.pemOutput:
Verifying JWS token...
✓ Signature valid
✓ Claims valid
✓ Schema valid
Credential Details:
ID: your-credential-id
Subject: did:web:yourdomain.com
Issuer: did:web:issuer.beltic.dev
Issued: 2025-01-15T00:00:00Z
Expires: 2026-01-15T00:00:00Z
Type: DeveloperCredential v1
Legal Name: Your Name
Entity Type: individual
KYB Tier: tier_1_basic
VALIDStep 7: Inspect the JWT
To see the JWT structure:
# Extract payload (base64 decode)
cat developer-credential.jwt | cut -d'.' -f2 | base64 -d | jq .Output:
{
"iss": "did:web:issuer.beltic.dev",
"sub": "did:web:yourdomain.com",
"jti": "your-credential-id",
"iat": 1699876800,
"nbf": 1699876800,
"exp": 1731412800,
"vc": {
"credentialId": "your-credential-id",
"legalName": "Your Name",
...
}
}Advanced: Constrained Verification
Verify with specific issuer/audience expectations:
beltic verify \
--token developer-credential.jwt \
--key dev-private-key.pub.pem \
--issuer did:web:issuer.beltic.dev \
--audience did:web:platform.example.comThis ensures the credential was issued by the expected issuer and intended for a specific audience.
SDK Workflow (TypeScript)
The TypeScript SDK provides programmatic credential workflows. Note: SDK is currently in early access.
Step 1: Install SDK
npm install @beltic/sdkStep 2: Validate Credential
import { validateDeveloperCredential, ValidationError } from '@beltic/sdk';
const credential = {
credentialId: 'your-uuid',
legalName: 'Your Name',
// ... rest of credential
};
const result = validateDeveloperCredential(credential);
if (!result.ok) {
const error = new ValidationError(result.errors);
console.error(error.format());
process.exit(1);
}
console.log('Credential valid:', result.value);Step 3: Generate Keys
import { generateKeyPair } from '@beltic/sdk';
const { privateKey, publicKey } = await generateKeyPair('EdDSA');
console.log('Keys generated');Step 4: Sign Credential
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',
});
console.log('Signed token:', token);Step 5: Verify Credential
import { verifyCredential } from '@beltic/sdk';
const verified = await verifyCredential(token, {
keyResolver: async ({ kid, alg, iss }) => {
// Resolve public key from DID or key store
return publicKey;
},
expectedIssuer: 'did:web:issuer.beltic.dev',
});
console.log('Verified credential:', verified.credential);Self-Signing with SDK
// Self-sign where issuer = subject
const myDid = 'did:web:developer.example.com';
const selfSignedToken = await signCredential(credential, privateKey, {
alg: 'EdDSA',
issuerDid: myDid,
subjectDid: myDid, // Same as issuer
keyId: `${myDid}#key-1`,
});Complete SDK Example
import {
validateDeveloperCredential,
signCredential,
verifyCredential,
generateKeyPair,
ValidationError,
} from '@beltic/sdk';
async function createCredential() {
// 1. Validate
const credential = { /* your credential */ };
const validation = validateDeveloperCredential(credential);
if (!validation.ok) {
throw new ValidationError(validation.errors);
}
// 2. Generate keys
const { privateKey, publicKey } = await generateKeyPair('EdDSA');
// 3. Sign
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',
});
// 4. Verify
const verified = await verifyCredential(token, {
keyResolver: async () => publicKey,
});
return { token, verified };
}Complete Example Script
#!/bin/bash
set -e
# 1. Copy template
cp beltic-spec/examples/developer/v1/tests/valid-individual-minimal.json my-dev-cred.json
# 2. Edit file (manual step - update fields)
echo "Update my-dev-cred.json with your information, then press Enter"
read
# 3. Validate
ajv validate -s beltic-spec/schemas/developer/v1/developer-credential-v1.schema.json -d my-dev-cred.json
# 4. Generate keys
beltic keygen --algorithm EdDSA --output dev-key.pem
# 5. Sign
beltic sign \
--payload my-dev-cred.json \
--key dev-key.pem \
--algorithm EdDSA \
--output developer.jwt \
--kid did:web:example.com#key-1
# 6. Verify
beltic verify --token developer.jwt --key dev-key.pub.pem
echo "✓ Developer credential created successfully!"