Auth0 Example Configuration

This section describes a minimal example configuration of the trigger service with authorization enabled using Auth0 as the OAuth 2.0 provider together with the OAuth 2.0 middleware included in Daml. It uses the sandbox as the Daml ledger.

Configure Auth0

Sign up for an account on Auth0 to follow this guide.

Create an API

First, create a new API on the Auth0 API dashboard. This will represent the Daml ledger API and controls properties of access tokens issued for the ledger API.

  • Enter the name of the API, e.g. ex-daml-api.
  • Enter the API identifier: https://daml.com/ledger-api.
  • Select the signing algorithm RS256.
  • Press the “create” button.

Enter the settings of the newly created API.

  • Allow offline access in the access settings section to enable issuance of refresh tokens.

Create an Application

Create a new native application. This will represent the OAuth 2.0 middleware.

  • Enter the name of the application, e.g. ex-daml-auth-middleware.
  • Choose the application type “native”.
  • Press the “create” button.

Enter the settings of the newly created application.

  • Configure the allowed callback URLs: http://localhost:5000/auth/cb.

    This is the URL to the callback endpoint of the auth middleware, in this case through the reverse proxy.

  • Take note of the “Client ID” and “Client Secret” displayed in the “Basic Information” section.

  • Take note of the following URLs in the “Endpoints” tab of the advanced settings:
    • OAuth Authorization URL,
    • OAuth Token URL, and
    • JSON Web Key Set.

Create a Rule

Create a new rule. This will define user privileges, the mapping from scopes to ledger claims, and construct the access token.

Note, for simplicity this rule will grant access to any claims to any user. In a real setup the rule will need to validate whether the user is authorized to access the requested claims. Rules can be used to implement custom authorization policies.

This rule will define a one-to-one mapping between scopes and Daml ledger claims, this is compatible with the default request templates that are built into the OAuth 2.0 middleware.

  • Enter the name of the rule, e.g. ex-daml-token.

  • Enter the following script:

    function (user, context, callback) {
      // NOTE change the ledger ID to match your deployment.
      const ledgerId = 'daml-auth0-example-ledger';
      const apiId = 'https://daml.com/ledger-api';
    
      const query = context.request.query;
    
      // Only handle ledger-api audience.
      const audience = query && query.audience || "";
      if (audience !== apiId) {
        return callback(null, user, context);
      }
    
      // Determine requested claims.
      var admin = false;
      var readAs = [];
      var actAs = [];
      var applicationId = null;
      const scope = (query && query.scope || "").split(" ");
      scope.forEach(s => {
        if (s === "admin") {
          admin = true;
        } else if (s.startsWith("readAs:")) {
          readAs.push(s.slice(7));
        } else if (s.startsWith("actAs:")) {
          actAs.push(s.slice(6));
        } else if (s.startsWith("applicationId:")) {
          applicationId = s.slice(14);
        }
      });
    
      // Construct access token.
      context.accessToken[apiId] = {
        "ledgerId": ledgerId,
        "actAs": actAs,
        "readAs": readAs,
        "admin": admin
      };
      if (applicationId) {
        context.accessToken[apiId].applicationId = applicationId;
      }
    
      return callback(null, user, context);
    }
    

    You can use the Real-time Webtask Logs extension to view any console.log output generated by your rule during the processing of authorization requests.

Create a User

Create a new user.

  • Enter an email address, e.g. alice@example.com.
  • Enter a secure password.
  • Remember the credentials.
  • Choose the “Username-Password-Authentication” connection.
  • Press the “create” button.

Enter the details page of the newly created user.

  • Edit the email address.
  • Press “Set email as verified”.
  • Press “save”.

Start Daml

Next, configure the relevant Daml components to use Auth0 as the IAM.

Sandbox

Start the sandbox using the following command. Replace JSON_Web_Key_Set by the corresponding URL found in the application settings and make sure that the ledger ID matches the one in the Auth0 rule.

daml sandbox \
  --address localhost \
  --port 6865 \
  --ledgerid daml-auth0-example-ledger \
  --wall-clock-time \
  --auth-jwt-rs256-jwks "JSON_Web_Key_Set"

OAuth 2.0 Middleware

Start the auth middleware using the following command. Replace the client identifier and URL placeholders by the corresponding values found in the application settings and make sure that the callback URL matches the allowed callback URL in the application settings. The --callback flag defines the middleware’s callback URL as exposed through the reverse proxy.

DAML_CLIENT_ID="Client_ID" \
DAML_CLIENT_SECRET="Client_Secret" \
daml oauth2-middleware \
  --address localhost \
  --http-port 3000 \
  --oauth-auth "OAuth_Authorization_URL" \
  --oauth-token "OAuth_Token_URL" \
  --auth-jwt-rs256-jwks "JSON_Web_Key_Set" \
  --callback http://localhost:5000/auth/cb

Trigger Service

Start the trigger service using the following command. The --auth flag defines the middleware’s URL prefix as exposed through the reverse proxy, similarly the --auth-callback flag defines the trigger service’s callback URL as exposed through the reverse proxy.

daml trigger-service \
  --address localhost \
  --http-port 4000 \
  --ledger-host localhost \
  --ledger-port 6865 \
  --auth http://localhost:5000/auth \
  --auth-callback http://localhost:5000/trigger/cb

Configure Web Server

This guide uses Nginx as a reverse proxy and web server.

  • Configure nginx using the following snippet:

    http {
      server {
        listen 5000;
        server_name localhost;
        root html;
    
        location /auth/ {
          proxy_pass http://localhost:3000/;
        }
    
        location /trigger/ {
          proxy_pass http://localhost:4000/;
        }
      }
    }
    

    This exposes the auth middleware under the URL http://localhost:3000/ and the trigger service under the URL http://localhost:4000/.

  • Add the following index.html to your web root:

    <!DOCTYPE html>
    <html>
      <body>
        <button onclick="listTriggers()">list triggers</button>
      </body>
      <script>
        async function listTriggers() {
          // The rule defined above accepts all claims for all users.
          // So, we can always access claims to the party Alice.
          const resp = await fetch("http://localhost:5000/trigger/v1/triggers?party=Alice");
          if (resp.status === 401) {
            const challenge = await resp.json();
            console.log(`Unauthorized ${JSON.stringify(challenge)}`);
            var loginUrl = new URL(challenge.login);
            loginUrl.searchParams.append("redirect_uri", window.location.href);
            window.location.replace(loginUrl.href);
          } else {
            const body = await resp.text();
            console.log(`(${resp.status}) ${body}`);
          }
        }
      </script>
    </html>
    

    This defines a very simple web site with a single button that will request the list of Alice’s running triggers from the trigger service. If the user is authorized it will print the list to the JavaScript console, otherwise it will redirect to auth middleware’s login endpoint to obtain authorization.

Test the Setup

Use the following commands to determine if the OAuth 2.0 middleware and trigger service are running and available through the reverse proxy.

$ curl http://localhost:5000/auth/livez
{"status":"pass"}
$ curl http://localhost:5000/trigger/livez
{"status":"pass"}

Direct your web browser to the URL http://localhost:5000. It should display the test page with the single “list triggers” button defined above.

  • Open the JavaScript console.

  • Press the “list triggers” button.

  • An “Unauthorized” message should appear in the console and you should be redirected to the auth0 login page.

  • Login with the credentials of the auth0 user that you created before.

  • The browser should be redirected to the test page.

  • Click the button again. This time a message like the following should appear in the console.

    (200) {"result":{"triggerIds":[]},"status":200}