Enabling auth-services on a running MainNet participant for party-scoped private contract queries?
Hi everyone,
We’re building a governance dApp (DAOs, proposals, voting) on Canton MainNet with a self-hosted participant (web34ever::12205...). Go backend talks to the participant via gRPC Ledger API.
We’re adding private contracts where the operator party is excluded from observers:
template DAO with
admin : Party
members : [Party]
visibility : DAOVisibility
where
signatory admin
observer case visibility of
Public -> [operator] <> members
Private -> members -- operator excluded
From researching this forum (thanks WallaceKelly & bernhard — your posts on JWT authorization, actAs/readAs semantics, and PQS vs JSON API were exactly what we needed), we understand that:
- Per-party JWT with
actAs=[memberParty]is required to query private contracts — operator readAs won’t work actAsimpliesreadAs, so a single right grant is sufficient- JSON API is fine for our scale (~50-200 DAOs), no need for PQS yet
- Ledger API User creation via
/v2/users+/v2/users/{id}/rightsis the right pattern
Two remaining questions:
1. Adding auth-services to an already-running MainNet participant
We did not configure ledger-api.auth-services when we initially set up our participant. We plan to add:
canton.participants.web34ever {
ledger-api {
auth-services = [{
type = jwt-rs-256-crt
certificate = "/path/to/our-public.crt"
}]
}
}
Our backend would sign JWTs with the corresponding private key, including actAs=[partyId] claims for each user.
Are there any gotchas with enabling auth on a participant that already has existing contracts and allocated parties? Does a restart with auth-services added require any migration, or is it purely additive?
2. Coexistence with Splice validator stack
We’re also preparing for Splice validator onboarding (splice-validator-app + splice-wallet-app). Does the Splice stack configure its own auth on the participant (e.g. Keycloak)? If so, can multiple auth-services entries coexist — ours (cert-based) alongside Splice’s (JWKS)?
auth-services = [
{ type = jwt-rs-256-crt, certificate = "our-key.crt" }, # our backend
{ type = jwt-jwks, url = "http://keycloak:8080/.../jwks" } # splice stack
]
Or would we need to consolidate into a single auth provider?
Any pointers appreciated. Happy to share more about our contract model if helpful.
Thanks!
hey @web3
so on above, some pointers I’d give is
-
Canton stores auth configuration at the process level so your contracts, parties, and transaction history live in the participant’s database and are completely unaffected by adding
auth-servicesAFIK the change affects only how the Ledger API authenticates incoming requests going forward. -
the user Identity management layer is separate from auth-services configuration. The users and their
actAs/readAsrights you’ve created persist in the participant DB. Auth-services just controls how the participant verifies that the JWT presented actually belongs to the claimed user. Your existing user/rights setup carries over intact. -
When you onboard with the Splice the validator app configures its own auth against the participant’s Ledger API using the OIDC provider you specify at onboarding time (Auth0 or Keycloak). Splice expects to be the configured auth provider by default in its Docker Compose config. It will set the
ledger-api-authKubernetes secret or theLEDGER_API_AUTH_*env vars which typically overwrite your configuration if you’re using the Splice deployment tooling. -
also Recommended is to set Splice’s
splice-app-validator-ledger-api-authsecret to point to your Keycloak instance but ensure the participant itself has both auth entries configured in your own config file, not overridden by Splice or your custom auth.
Your setup looks correct.
- Adding auth-services later
Yes — you can add ledger-api.auth-services to an existing MainNet participant without migration.
You just:
- update config
- restart participant
- start sending JWTs
Existing:
- contracts
- parties
- data
will continue working normally.
Main thing to remember:
after enabling auth, every Ledger API request must include a valid JWT.
Your per-party JWT approach with:
actAs=[partyId]
is the correct design for private contracts.
- Splice + your auth together
Yes — multiple auth-services can coexist.
Example:
auth-services = [
{ type = jwt-rs-256-crt, certificate = "our.crt" },
{ type = jwt-jwks, url = "http://keycloak/.../jwks" }
]
This is supported.
So:
- your backend can use cert-signed JWTs
- Splice can use Keycloak/JWKS
at the same time.
Just make sure JWT claims (actAs, aud, expiration, etc.) are configured correctly.
One important note:
If a contract is private and operator is excluded:
Private -> members
then operator truly cannot read/query it.
So your backend must always issue JWTs for the actual member party when accessing private contracts.
Your architecture already matches this properly.