Table of Contents

Client Bootstrap Configuration

Chronicle supports declarative client configuration, allowing clients (clientId/clientSecret pairs) to be defined at startup via configuration or secrets management, rather than exclusively through the Workbench UI.

Configuration

Configuration file

{
  "clients": [
    {
      "clientId": "my-service",
      "clientSecret": "a-strong-secret-value"
    },
    {
      "clientId": "another-service",
      "clientSecret": "another-secret-value"
    }
  ]
}

Environment variables

Cratis__Chronicle__Clients__0__ClientId=my-service
Cratis__Chronicle__Clients__0__ClientSecret=a-strong-secret-value
Cratis__Chronicle__Clients__1__ClientId=another-service
Cratis__Chronicle__Clients__1__ClientSecret=another-secret-value

Properties

Property Type Required Description
clientId string Yes The client identifier used for authentication
clientSecret string Yes The client secret in plaintext. Hashed internally on load

How it works

  1. On startup, Chronicle reads the clients array from configuration
  2. For each client, the secret is hashed using ASP.NET Core's PasswordHasher
  3. The raw secret is never retained in memory beyond the bootstrap phase
  4. If a client with the same clientId already exists, it is skipped (not overwritten)
  5. Bootstrap clients are visible in the Workbench UI alongside manually created clients
  6. The Workbench UI continues to support adding and revoking clients at runtime

Secret management

The clientSecret is provided as plaintext in configuration. In production, use a proper secrets management solution:

Azure Key Vault

# Store secret in Key Vault
az keyvault secret set --vault-name my-vault --name chronicle-client-secret --value "strong-secret"

# Reference in environment variable
Cratis__Chronicle__Clients__0__ClientId=my-service
Cratis__Chronicle__Clients__0__ClientSecret=@Microsoft.KeyVault(SecretUri=https://my-vault.vault.azure.net/secrets/chronicle-client-secret)

Kubernetes Secrets

apiVersion: v1
kind: Secret
metadata:
  name: chronicle-clients
type: Opaque
stringData:
  client-secret: "strong-secret-value"
---
apiVersion: apps/v1
kind: Deployment
spec:
  template:
    spec:
      containers:
        - name: chronicle
          env:
            - name: Cratis__Chronicle__Clients__0__ClientId
              value: "my-service"
            - name: Cratis__Chronicle__Clients__0__ClientSecret
              valueFrom:
                secretKeyRef:
                  name: chronicle-clients
                  key: client-secret

Docker Compose with secrets

services:
  chronicle:
    image: cratis/chronicle:latest
    environment:
      - Cratis__Chronicle__Clients__0__ClientId=my-service
      - Cratis__Chronicle__Clients__0__ClientSecret=${CLIENT_SECRET}

Relationship with Workbench-managed clients

  • Bootstrap clients and Workbench-managed clients coexist
  • Bootstrap clients are registered as regular applications visible in the Workbench
  • If a bootstrap client already exists (matching clientId), it is not re-registered or overwritten
  • Clients created through the Workbench can be revoked through the Workbench; bootstrap clients will be re-created on next restart if removed