Skip to content

CBTC Authentication

⚠️ API Disclaimer: CBTC APIs are subject to change. Authentication flows may evolve as Canton’s identity layer matures.


Overview: How Authentication Works for CBTC on Canton

Section titled “Overview: How Authentication Works for CBTC on Canton”

All CBTC operations go through the Canton Ledger API, which requires a valid JWT (JSON Web Token) for every request. The JWT is issued by an OIDC (OpenID Connect) provider connected to your Canton participant node.

This guide covers two authentication options for developers building with CBTC and the Canton Network:

  • Keycloak (officially supported by BitSafe)
  • Auth0 (community example, not officially maintained) For deeper background on how Canton handles authentication and authorization at the platform level, see the Canton Authorization Documentation.

sequenceDiagram
 participant App as Your Application
 participant OIDC as OIDC Provider<br>(Keycloak / Auth0)
 participant Canton as Canton Participant<br>(Ledger API)

 App->>OIDC: 1. Request token (client credentials or auth code)
 OIDC-->>App: 2. JWT access token
 App->>Canton: 3. API call with Bearer token
 Canton-->>App: 4. Response

Set Up Keycloak for CBTC Authentication (Officially Supported) ✅

Section titled “Set Up Keycloak for CBTC Authentication (Officially Supported) ✅”

Keycloak is the officially supported OIDC provider for CBTC integrations. BitSafe engineering provides support for Keycloak-based authentication.

  • Keycloak instance running and accessible
  • A realm configured for your Canton participant
  • A client application registered in Keycloak

In your Keycloak admin console:

  1. Navigate to your realm → Clients → Create client
  2. Set Client type to OpenID Connect
  3. Set Client ID (e.g., cbtc-minting-app)
  4. Enable Client authentication (for server-to-server flows)
  5. Under Service account roles, enable as needed

Your Canton participant must be configured to trust your OIDC provider. Participant configuration is complex and environment-specific. Refer to the official validator operator documentation:

Canton Validator Operator Guide →

Client Credentials flow (for server-to-server / backend integrations):

Terminal window
curl -X POST "https://<your-keycloak>/auth/realms/<your-realm>/protocol/openid-connect/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=cbtc-minting-app" \
-d "client_secret=$CLIENT_SECRET"

Password grant flow (for user-facing / interactive applications):

Terminal window
curl -X POST "https://<your-keycloak>/auth/realms/<your-realm>/protocol/openid-connect/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=password" \
-d "client_id=cbtc-minting-app" \
-d "username=$KEYCLOAK_USERNAME" \
-d "password=$KEYCLOAK_PASSWORD"

Response (both flows):

{
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"expires_in": 300,
"token_type": "Bearer"
}

Include the token in all Canton Ledger API calls:

Terminal window
curl -X POST "https://<your-participant>/v2/state/active-contracts" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{... }'

Tokens expire (typically 5 minutes for Keycloak). Your application should:

  1. Cache the token until near expiry
  2. Request a new token before the current one expires
  3. Retry failed requests with a fresh token if you receive a 401

Set Up Auth0 for CBTC Authentication (Community Example) ⚠️

Section titled “Set Up Auth0 for CBTC Authentication (Community Example) ⚠️”

💡 Auth0 compatibility. Both Keycloak and Auth0 follow the OAuth2/OIDC standard, so the login flow and token usage are identical. There is one known caveat: Auth0 requires an extra audience parameter in the token request. The cbtc-lib and canton-lib libraries do not pass this parameter by default, so they won’t work out of the box with Auth0. This is a straightforward fix on either the library side or the client side. See the workaround below. BitSafe engineering support covers Keycloak-based authentication only. For Auth0-specific configuration issues, refer to Auth0’s documentation.

  • Auth0 tenant and API configured
  • Application registered as Machine to Machine (for backend) or Single Page Application (for frontend)

In the Auth0 dashboard:

  1. Navigate to Applications → APIs → Create API
  2. Set Name (e.g., Canton Ledger API)
  3. Set Identifier to your participant’s Ledger API URL
  4. Set Signing Algorithm to RS256

Step 2: Register a Machine-to-Machine Application

Section titled “Step 2: Register a Machine-to-Machine Application”
  1. Navigate to Applications → Create Application
  2. Select Machine to Machine Applications
  3. Authorise the application to call your Canton Ledger API
  4. Note the Client ID and Client Secret

Point your participant to Auth0’s JWKS endpoint. Participant configuration is complex and environment-specific. Refer to the official validator operator documentation:

Canton Validator Operator Guide →

Terminal window
curl -X POST "https://<your-auth0-domain>/oauth/token" \
-H "Content-Type: application/json" \
-d '{
"client_id": "'$CLIENT_ID'",
"client_secret": "'$CLIENT_SECRET'",
"audience": "https://<your-participant>/v2/",
"grant_type": "client_credentials"
}'

⚠️ The audience parameter is required for Auth0. This is the key difference from Keycloak. Without it, Auth0 will return an opaque token that the Canton participant will reject. Set audience to your participant’s Ledger API base URL. If using cbtc-lib / canton-lib: The Rust libraries’ keycloak::login::password and keycloak::login::client_credentials functions do not pass an audience parameter. To use Auth0, you’ll need to either:

  1. Make the token request directly via HTTP (as shown above) instead of using the library helper
  2. Patch the login functions to include the audience field, which is a small change A library-level fix may be shipped in a future release of canton-lib.

Same as Keycloak. Include the Bearer token in all API requests.


Wallet-Based Authentication for Canton dApps

Section titled “Wallet-Based Authentication for Canton dApps”

For applications that use Canton-compatible wallets (Loop, Console/Zoro, Bron), authentication is handled by the wallet provider. Your application receives a JWT through the wallet’s SDK or connect flow.

Supported wallets:

  • Loop Wallet
  • Console / Zoro Wallet
  • Bron Wallet
  • WalletConnect (for dApp integrations)
  • Node login (direct participant authentication) See the Integration Guides for wallet-specific connection patterns.

Issue Cause Resolution
401 Unauthorized on every request JWT not trusted by participant Verify JWKS URL in participant config matches your OIDC provider
Token expires immediately Clock skew between OIDC provider and participant Sync system clocks (NTP)
CORS errors in browser Ingress not configured for CORS Add CORS annotations to your ingress - see Minting App Installation Guide
invalid_grant from OIDC provider Client secret rotated or incorrect Regenerate and update client secret

JWT Security Best Practices for Canton Applications

Section titled “JWT Security Best Practices for Canton Applications”
  • Never expose client secrets in frontend code. Use the Client Credentials flow only from backend services.
  • Rotate secrets regularly. Update client secrets in both your OIDC provider and your application config.
  • Use short-lived tokens. The default 5-minute expiry is appropriate for most use cases.
  • Restrict party access. Configure your JWT claims to limit which Canton parties a token can act as.