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 and indexes

  • 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:

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,
  // including its documents and indexes.
  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. read access includes the ability to call the collection’s indexes. An example FSL role schema:

role customer {
  // Grant read access to `Product` documents and indexes.
  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
  }
}

Built-in roles also have collection privileges. See built-in roles.

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)
      )
    }
  }
}

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

See Attribute-based access control (ABAC)

Privilege predicate arguments

Privilege predicates are passed different arguments based on their action.

Action Predicate function signature

create

(doc: Object) => Boolean | Null

 

doc: Object containing the document to create. Includes metadata fields.

delete

(doc: Object) => Boolean | Null

 

doc: Object containing the document to delete. Includes metadata fields.

read

(doc: Object) => Boolean | Null

 

doc: Object containing the document to read. Includes metadata fields.

write

(oldDoc: Object, newDoc: Object) => Boolean | Null

 

oldDoc: Object containing the original document. Includes metadata fields.

newDoc: Object containing the document to write. Includes metadata fields.

create_with_id

(doc: Object) => Boolean | Null

 

doc: Object containing the document to create. Includes metadata fields.

history_read

(doc: Object) => Boolean | Null

 

doc: Object containing the document to read. Includes metadata fields.

call

(args: Array) => Boolean | Null

 

args: Array containing the function call’s arguments.

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.

\