Roles

Reference: FSL role schema

Fauna uses secrets for authentication and authorization. Roles determine a secret’s privileges, which control data access.

Role types

Fauna supports two types of roles:

Built-in roles

Built-in roles grant access to all of a database’s resources. Built-in roles are assigned to keys and typically used for system processes. You can’t assign built-in roles to tokens or JWTs.

Built-in role Privileges

admin

Full access to a database, including all:

  • Collections, including their documents

  • Access providers (but not their JWTs' secrets)

  • Child databases

  • Keys (but not their secrets)

  • Schema, including .fsl schema files

  • Tokens (but not their secrets)

  • User-defined functions (UDFs)

  • User-defined roles

You can also create an admin key in a Fauna account’s top-level context. This key lets you create and manage top-level databases.

server

Same as admin, except the server role can’t access:

  • Access providers

  • Child databases

  • Keys

  • User-defined roles

server-readonly

Same as server, except the server-readonly only has read privileges.

client

Deprecated. Do not use.

User-defined roles

User-defined roles can grant:

  • Access to documents in specific collections, including user-defined and system collections.

  • The ability to call specific user-defined functions (UDFs).

You create and manage user-defined roles as FSL role schema:

role manager {

  // Assign the `manager` role to tokens with
  // an identity document in the `Manager` collection.
  // Not applicable to JWTs or keys.
  membership Manager

  // If the predicate is `true`,
  // assign the `manager` role to tokens with
  // an identity document in the `Customer` collection.
  membership Customer {
    // Check that the identity document's
    // `accessLevel` field value is `manager`.
    predicate (customer => customer.accessLevel == 'manager')
  }

  // Grant `read` access to the `Customer` collection.
  privileges Customer {
    read
  }

  // Grant full access to the `OrderItem` collection.
  privileges OrderItem {
    create
    read
    write
    delete
  }

  // If the predicate is `true`,
  // grant `create` access to the `Order` collection.
  privileges Order {
    create {
      predicate (doc =>
        // Check the order's `status` field.
        doc.status == "cart"
      )
    }
  }

  // If the predicate is `true`,
  // grant `read` access to the `Manager` collection.
  privileges Manager {
    read {
      // Check that the `Manager` document
      // is the token's identity document.
      // `Query.identity()` is `null` for JWTs or keys.
      predicate (doc => Query.identity() == doc)
    }
  }

  // If the predicate is `true`,
  // grant `call` access to the
  // user-defined `checkout` function.
  privileges checkout {
    call {
      // Check that the `orderId` belonds to the user.
      // `Query.identity()` is `null` for JWTs or keys.
      predicate ((orderId, status, payment) => {
        let order = Order.byId(orderId)!
        order?.customer == Query.identity()
      })
    }
  }
}

Role collection

Fauna stores user-defined roles as documents in the Role system collection. These documents are an FQL version of the FSL role schema. You can use Role methods to access and manage user-defined roles in FQL.

See Role FQL docs

Membership

Fauna assigns user-defined roles to tokens based on their identity document’s collection and the role’s membership property:

role customer {
  // Assign the `customer` role to tokens with
  // identity documents in the `Customer` collection.
  membership Customer
}

The membership property doesn’t assign roles to JWTs or keys.

Membership predicates

Each membership property can include a predicate.

Membership predicates let you conditionally assign roles to tokens:

role customer {
  // If the predicate is `true`,
  // assign the `customer` role to tokens with
  // identity documents in the `Customer` collection.
  membership Customer {
    // Checks the `status` field in the
    // token's identity document.
    predicate (user => user.status == "active")
  }
}

You can use membership predicates to implement attribute-based access control (ABAC).

See Attribute-based access control (ABAC)

Membership for multiple roles

You can use membership to assign a token up to 64 roles.

For performance, Fauna stops checking a token’s roles once it verifies the token has the privileges required for a query.

Fauna evaluates membership predicates sequentially, prioritizing previously successful ones.

Privileges

A role can grant one or more privileges. A privilege allows a specific action, such as read or write, on a specific resource, such as a collection or UDF.

Privileges act as an allowlist. Roles grant no privileges by default.

Collection privileges

Collection privileges grant access to a collection’s documents. A collection privilege can allow the create, delete, read, or write actions:

role customer {
  // Grant read access to `Product` documents.
  privileges Product {
    read
  }
}

You can also grant access to system collections that store Fauna resources:

role manager {
  // Grant `create` and `read` access to the `Token` system collection.
  // Allows the role to create token secrets.
  privileges Token {
    create
    read
  }
}

To allow a role to create, delete, or manage user-defined collections themselves, grant access to the Collection system collection:

role manager {
  // Grant full access to the `Collection` system collection.
  // Allows the role to create, delete, read, and update
  // user-defined collections.
  privileges Collection {
    create
    delete
    read
    write
  }
}

Function privileges

Function privileges grant the ability to call a server-side UDF:

role customer {
  // Grants `call` access to the `getOrCreateCart` UDF.
  privileges getOrCreateCart {
    call
  }
}

By default, UDFs run with the same privileges as the query’s authentication secret. You can override this default by specifying an optional role in the UDF’s function schema.

If a role is specified in the function schema, the UDF runs with that role’s privileges, regardless of the authentication secret’s privileges.

See User-defined functions (UDFs)

Privilege predicates

Each privilege action can include a predicate. Privilege predicates let you conditionally grant privileges to a role:

role customer {
  // If the predicate is `true`,
  // grant `write` access to the `Order` collection.
  privileges Order {
    write {
      predicate ((oldDoc, newDoc) =>
        // Disallow write access 10 hours after
        // the original order's last update (`ts`)
        Time.now().difference(oldDoc!.ts, "hours") < 10 &&
        // Check that the user's `country` is
        // in the updated order's `allowedCountries`
        newDoc.allowedCountries.includes( Query.identity()!.country)
      )
    }
  }
}

Privilege predicates are passed different arguments based on their action. See Privilege predicate arguments.

You can use membership predicates to implement ABAC.

See Attribute-based access control (ABAC)

Query-time evaluation

Fauna evaluates a secret’s roles and privileges, including any predicates, at query time for every query. Changes to roles and privileges take effect immediately and affect pre-existing secrets.

Check a secret’s roles

You can use a user-defined collection and UDFs to check a secret’s assigned roles. See Check a secret’s user-defined roles.

Multi-tenancy and scope

Roles are scoped to a single database. A parent database’s roles don’t apply to its peer or child databases.

You can copy and deploy roles across databases using FSL and a CI/CD pipeline. See Manage schema with a CI/CD pipeline.

Is this article helpful? 

Tell Fauna how the article can be improved:
Visit Fauna's forums or email docs@fauna.com

Thank you for your feedback!