Tutorial: Using Cerbos with Auth0

An example application of integrating Cerbos with an Express server using Auth0 for authentication.

Dependencies

Getting started

  1. Clone the repo

    git clone git@github.com:cerbos/express-auth0-cerbos.git
  2. Start up the Cerbos PDP instance docker container. This will be called by the express app to check authorization.

    cd cerbos
    ./start.sh
  3. Install node dependencies

    npm install
  4. Start the express server

    node index.js

Auth0 Rule to add roles to token

By default any roles set up in the Auth0 console are not passed through in the authentication token. To enable this, add the following rule to the Auth Pipeline in your Auth0 account.

function (user, context, callback) {
  const namespace = 'https://cerbos.cloud';
  const assignedRoles = (context.authorization || {}).roles;

  let idTokenClaims = context.idToken || {};
  let accessTokenClaims = context.accessToken || {};

  idTokenClaims[`${namespace}/roles`] = assignedRoles;
  accessTokenClaims[`${namespace}/roles`] = assignedRoles;

  context.idToken = idTokenClaims;
  context.accessToken = accessTokenClaims;

  callback(null, user, context);
}

Policies

This example has a simple CRUD policy in place for a resource kind of contact - like a CRM system would have. The policy file can be found in the cerbos/policies folder here.

Should you wish to experiment with this policy, you can try it in the Cerbos Playground.

The policy expects one of two roles to be set on the principal - admin and user. These roles are authorized as follows:

Action User Admin

list

Y

Y

read

Y

Y

create

Y

Y

update

If owner

Y

delete

If owner

Y

This business logic is represented in Cerbos as a resource policy.

---
apiVersion: api.cerbos.dev/v1
resourcePolicy:
  version: default
  resource: contact
  rules:
    - actions: ["read", "create"]
      effect: EFFECT_ALLOW
      roles:
        - admin
        - user

    - actions: ["update", "delete"]
      effect: EFFECT_ALLOW
      roles:
        - admin

    - actions: ["update", "delete"]
      effect: EFFECT_ALLOW
      roles:
        - user
      condition:
        match:
          expr: request.resource.attr.owner == request.principal.id