> For the complete documentation index, see [llms.txt](https://docs.bitsafe.finance/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.bitsafe.finance/developers/cbtc-authentication.md).

# 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

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](https://docs.digitalasset.com/build/3.4/sdlc-howtos/applications/secure/authorization.html).

***

## CBTC Authentication Flow: JWT and OIDC

```mermaid
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) ✅

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

### Prerequisites

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

### Step 1: Register a Client

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

### Step 2: Configure Your Canton Participant

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 →**](https://docs.dev.sync.global/validator_operator/index.html)

### Step 3: Obtain a Token

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

```bash
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):

```bash
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):

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

### Step 4: Use the Token

Include the token in all Canton Ledger API calls:

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

### Token Refresh

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) ⚠️

> 💡 **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](https://auth0.com/docs).

### Prerequisites

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

### Step 1: Create an Auth0 API

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

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**

### Step 3: Configure Your Canton Participant

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 →**](https://docs.dev.sync.global/validator_operator/index.html)

### Step 4: Obtain a Token

```bash
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`.

### Step 5: Use the Token

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

***

## 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](https://docs.bitsafe.finance/developers/integration-guides) for wallet-specific connection patterns.

***

## Troubleshooting

| 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

* **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.

***


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.bitsafe.finance/developers/cbtc-authentication.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
