Background
The Ledger API can be configured to require a JWT for authorization purposes. See the docs here and here.
In a production deployment, you would point Canton to a service like Auth0. But what if you want to just play with it locally? Or what if you would like to setup automated integration tests, including JWT tokens with a variety of claims?
This demo configures an instance of mock-oauth2-server
as the authorization service for a Canton participant in a Docker Compose network.
This demo will enable you to:
- Experiment with various auth-related Canton configuration options.
- Experiment with the relationship between JWT tokens and Canton User Management.
- Examine the response of the Ledger API endpoints with and without various JWT claims.
- Consider testing JWT-dependent scripts in a local environment.
- Consider building JWT-dependent, automated integration tests.
Setup
Download the code for the demo:
git clone https://github.com/wallacekelly-da/daml-public-demos.git \
--branch mock-oauth2-docker-compose \
mock-oauth2-docker-compose
Demo Steps
-
Peruse the Canton configuration.
- mydomain.conf, participant1.conf, and participant2.conf
- Notice that
participant1
does not require a JWT;participant2
does require a JWT. - bootstrap.canton allocates three parties and three users per participant node.
-
Peruse the mock-oauth2-server configuration in mockauth.json. Notice the four mappings based on
mock_token_type
. -
Start the Docker Compose network.
Using the open-source images:
docker compose up --detach participant1 participant2
Or using the enterprise images:
docker compose \ --file docker-compose.yaml \ --file docker-compose.enterprise.yaml \ up --detach participant1 participant2
-
Start a console for running the demo’s remaining commands.
docker compose run --rm --build console
-
Within the Docker Compose-hosted console, create a variety of tokens:
Audience-based token, for user
wallace
:curl -s http://mockauth/mockissuer/token \ -d grant_type=client_credentials \ -d client_id=ignored \ -d client_secret=ignored \ -d mock_token_type=audience \ -d participant=`cat "./configs/participant2.id"` \ -d sub=wallace \ | jq -r '.access_token' \ > audience.token
Scope-based token, for user
david
:curl -s http://mockauth/mockissuer/token \ -d grant_type=client_credentials \ -d client_id=ignored \ -d client_secret=ignored \ -d mock_token_type=scope \ -d participant=`cat "./configs/participant2.id"` \ -d sub=david \ | jq -r '.access_token' \ > scope.token
Custom claims token, for the
operator
party:curl -s http://mockauth/mockissuer/token \ -d grant_type=client_credentials \ -d client_id=ignored \ -d client_secret=ignored \ -d mock_token_type=custom \ -d actAs=`cat "./configs/participant2-operator.id"` \ -d readAs=`cat "./configs/participant2-operator.id"` \ | jq -r '.access_token' \ > custom.token
curl -s http://mockauth/mockissuer/token \ -d grant_type=client_credentials \ -d client_id=ignored \ -d client_secret=ignored \ -d mock_token_type=custom-admin \ | jq -r '.access_token' \ > admin.token
-
View the JWTs:
For example, to view the audience-based token:
cat audience.token
To view the token claims:
cat audience.token \ | jq -R 'split(".") | .[0], .[1] | @base64d | fromjson'
-
Use the tokens with Daml Assistant:
The following will fail, without a JWT:
daml ledger list-parties --host participant2 --port 4001
The following will succeed, with a JWT:
daml ledger list-parties --host participant2 --port 4001 \ --access-token-file audience.token
-
Use the tokens with grpcurl to call the Ledger API:
The following will fail, for user
david
:TOKEN=$(cat scope.token) grpcurl --plaintext \ -H "Authorization: Bearer ${TOKEN}" \ participant2:4001 \ com.daml.ledger.api.v1.admin.UserManagementService/ListUsers \ | jq '.users[].id'
The following will succeed, for user
wallace
:TOKEN=$(cat audience.token) grpcurl --plaintext \ -H "Authorization: Bearer ${TOKEN}" \ participant2:4001 \ com.daml.ledger.api.v1.admin.UserManagementService/ListUsers \ | jq '.users[].id'
-
Use the tokens with Daml Script:
The following will fail, when acting as the
operator
party:daml ledger upload-dar .daml/dist/console-1.0.0.dar \ --host participant2 --port 4001 --access-token-file custom.token
The following will succeed, when presenting an
admin
token:daml ledger upload-dar .daml/dist/console-1.0.0.dar \ --host participant2 --port 4001 \ --access-token-file admin.token
The following will fail, without an
actAs
claim:daml script --dar .daml/dist/console-1.0.0.dar \ --script-name Main:createContracts \ --input-file configs/participant2-operator.json \ --ledger-host participant2 \ --ledger-port 4001 --access-token-file admin.token
The following will succeed, when acting as the
operator
party:daml script --dar .daml/dist/console-1.0.0.dar \ --script-name Main:createContracts \ --input-file configs/participant2-operator.json \ --ledger-host participant2 \ --ledger-port 4001 \ --access-token-file custom.token