Roles

Reference: role

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. They’re typically assigned to keys and used for system processes. You can’t assign built-in roles to tokens.

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)

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

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 `Store` collection.
  privileges Store {
    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 != "Deleted"
      )
    }
  }

  // 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 `inventory` function.
  privileges inventory {
    call {
      // Check that the `store` is the user's `store`.
      // `Query.identity()` is `null` for JWTs or keys.
      predicate ((store) => Query.identity()?.store == store)
    }
  }
}

Role system collection

Fauna stores user-defined roles as documents in the Role system collection. These documents act as an FQL version of the FSL role schema. You can use Role methods to access 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)

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 user-defined `submitOrder` function
  privileges submitOrder {
    call
  }
}

By default, UDFs run with the same privileges as the transaction’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

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 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.

Multi-tenancy and scope

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

You can copy and deploy roles across databases using FSL and a CI/CD pipeline. For example pipelines, see Manage schema with GitHub Actions and Manage schema with GitLab CI/CD.

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!