Security

This page covers FaunaDB’s administrative security and application security:

FaunaDB key system

Access to the FaunaDB API uses secrets that correspond to access keys, which authenticate connections as having particular permissions. The access key system applies both to administrator- and server-level connections, as well as to object- and user-level connections.

Keys are defined as documents within the keys collection. Like databases, keys exist within the system-global root database context.

Keys are tied to a specific database and allow access to its contents. If no database is specified, the key grants access to the database in which it was created. The level of access a key provides depends on its role.

You must copy the key’s secret out of the key when it is first created and store it securely. Only a BCrypt hash of the key is stored on disk. It is impossible to recover the key’s secret if it is discarded.

Field name Value type Description

role

String

The key’s role. Either admin, server, server-readonly, client, or one or more user-defined roles.

secret

String

The key’s authentication secret. Only present on creation.

hashed_secret

String

The key’s hashed authentication secret.

priority

Number

A priority between 1 and 500, inclusive. Defaults to 1.

database

Database ref

The database associated with this key. Optional.

data

Object

A JSON object. Optional.

Access keys

Keys belong to one of four built-in roles, either admin, server, server-readonly, or client, or to one or more used-defined roles.

Admin keys

Keys with the admin role are used for managing databases, keys, and user-defined roles. An admin key can be used to create and destroy databases and keys. They should be very well protected.

Admin keys for FaunaDB accounts are managed in the FaunaDB Console.

Server keys

Keys with the server role bypass all permission checks within the database they’re assigned to. Because they provide unrestricted access, they should be well protected and only used in trusted or server-side environments.

Server read-only keys

Keys with the server-readonly role allow read-only access to all data within the database that they are assigned to. Because they provide unrestricted read access, they should be well protected and only used in trusted or server-side environments.

Client keys

Keys with the client role are restricted to actions and resources that are specifically marked with the public permission. Because their access is controlled, they are suitable for embedding in untrusted environments, such as mobile clients.

Typically they are used as part of an application’s user authentication flow, or to access public data, such as an application’s logged-out view.

User-defined roles

User-defined roles provide configurable, domain-specific, security rules. Roles are created with the CreateRole function, and have the following structure:

Field name Value type Description

name

String

The role’s name.

privileges

VarArgs

membership

VarArgs

Optional. One or more membership configuration objects.

User-defined roles can only be managed with an admin key.

Privilege configuration object

A privilege configuration object defines, for a given resource, what actions are permitted.

Field name Value type Description

resource

Reference

A reference to a collection, index, set, or user-defined function.

actions

Object

An object containing key-value pairs, where the keys are action names, and the values are either a boolean value to indicate whether access is permitted, or a predicate function that can compute whether access is permitted.

The available actions are:

  • create: permits the create of new documents, collections, or set.

  • delete: permits the deletion of existing documents, collections, or sets.

  • read: permits the reading of documents, collections, sets, or indexes.

  • write: permits writing to existing documents within a collection.

  • history_read: permits reading historical versions of a document, collection, or set.

  • history_write: permits inserting events into the history for an existing document or set.

  • unrestricted_read: permits the reading of an index without considering any other read permissions.

  • call: permits the calling of user-defined functions.

When configuring read access to an index, both the read and unrestricted_read actions are permitted. The read action grants access to the index’s data. However, an additional read permission check is performed before allowing access to the indexed document, which filters out references that the user cannot read. The unrestricted_read action disables the additional check, returning all of the documents associated with the index.

An action’s value can be a boolean, to indicate whether the action is permitted or not, or a read-only lambda predicate function. Lambda predicate functions must be created using a query, using the same format that the CreateFunction function accepts. The predicate function takes different parameters depending on the configured action. Predicates must return a boolean value where true grants the action, and false denies it.

The parameters to a predicate function are:

Action Argument(s) Description

create

Object

An object containing the new document’s data.

delete

Reference

The reference to the document to be deleted.

read

Reference, or index terms

A reference to the document to be read, or one or more terms to be matched against the target index.

write

Object, Object

Two objects, one containing the original document data, and the second containing the new document data to be written.

history_read

Reference

The reference to the document to be read.

history_write

Reference, Timestamp, String, Object

The reference to the document to be written, the timestamp to write to (which may create or update an event depending on existence of a matching timestamp), the action string, and an object containing the new document data.

unrestricted_read

Index terms

The terms matched against the target index.

call

Parameters

The parameters that are to be passed to the user-defined function.

Membership configuration object

A membership configuration object dynamically defines which authenticated resources are members of a given role. Token access is covered in the next section.

Field name Value type Description

resource

Reference

A reference to a collection in which its documents are members of the configured role.

predicate

Query

Optional. A read-only lambda predicate function that takes the reference of the authenticated resource and returns a boolean value that indicates whether the referenced resource is a member of the configured role.

Token access

Tokens allow direct access to FaunaDB by application users. Their use is optional. Each token has an associated document. Requests made with a token apply resource-level permission checks based on its document. When a document is a member of a user-defined role, that role is used to evaluate the user’s permissions.

Both server and client keys can generate tokens. Token generation with a client key requires a password. The password is optional when using a server key, but will be verified if provided.

Permissions

FaunaDB has a built-in permissions system that allows for fine-grained control over access to data.

Access is controlled by a resource’s permissions object. The identity of a request’s key is checked against the value of the permission field corresponding to the resource and action being taken.

Permission fields may be set to one of the following values:

Value Access Allowed

empty

Only server keys are allowed.

"public"

Any key is allowed.

document ref

Only tokens belonging to the specified document are allowed.

collection ref

Only tokens belonging to documents in the specified collection are allowed.

Collection permissions

Creating, reading, and modifying a document in a collection is controlled by the collection’s permissions. Applicable fields on a collection are:

Permission Field Action Allowed

create

Creating a document in the collection.

read

Reading documents in the collection.

write

Writing to document in the collection.

A document also has permissions, which are applied in addition to permissions defined on its collection. The permissions on a document may contain these fields:

Permission Field Action Allowed

read

Reading this document.

write

Writing to this document.

User-defined function permissions

Calling a function is controlled by its permissions. Applicable fields are:

Permission Field Action Allowed

call

Calling the function.

Index permissions

Query access to an index is controlled by its permissions. Applicable fields are:

Permission Field Action Allowed

read

Querying the index.

Delegates

A document may delegate access on its behalf to other documents by adding the other documents' refs to its delegates list. Any tokens belonging to a member of delegates is granted access as though they were tokens belonging to the delegating document.

For example, if a user (with id 1) has read access to the "spells" collection, but another user (with id 2) does not, the first user may grant access via delegation to the second user with the following query:

curl https://db.fauna.com/ \
    -d '{
          "update": { "ref": { "collection": "users" }, "id": 1 },
          "params": {
            "object": {
              "delegates": [ { "ref": { "collection": "users" }, "id": 2 } ]
            }
          }
        }'
client.Query(
  Update(
    Ref(Collection("users"), 1),
    Obj("delegates", Arr(Ref(Collection("users"), 2)))));
client.query(
  Update(
    Ref(Collection(Value("users")), Value(1)),
    Obj("delegates", Arr(Ref(Collection(Value("users")), Value(2))))));
result, _ := client.Query(
    f.Update(
        f.RefCollection(f.Collection("users"), "1"),
        f.Obj{"delegates": f.Arr{f.RefCollection(f.Collection("users"), "2")}},
    ),
)

fmt.Println(result)
client.query(
  Update(
    Ref(Collection("users"), 1),
    Obj("delegates" -> Arr(Ref(Collection("users"), 2)))))
client.query(
  q.update(
    Ref(q.collection("users"), 1),
    {"delegates": [Ref(q.collection("users"), 2)]}
  ))
$client.query do
  update ref(collection_('users'), 1),
         delegates: [ref(collection_('users'), 2)]
end
client.query(
    Update(
        ref: Ref(collection: Collection("users"), id: 1),
        to: Obj(
            "delegates" => Arr(Ref(collection: Collection("users"), id: 2))
        )
    )
)
client.query(
  q.Update(
    q.Ref(q.Collection("users"), 1),
    { delegates: [q.Ref(q.Collection("users"), 2)] }))
.then((ret) => console.log(ret))
map[ref:{1 0xc420118d80 <nil>} ts:1527631398281881 delegates:[{2 0xc420119000 <nil>}]]
{ ref: Ref(id=1, collection=Ref(id=users, collection=Ref(id=collections))),
  ts: 1527631398281881,
  delegates: [ Ref(id=2, collection=Ref(id=users, collection=Ref(id=collections))) ] }

Now, when the second user attempts to read from the "spells" collection, they are granted the same level of access as the first user.

Delegates are not transitive — in the example above, the second user may not delegate the first user’s permissions to another user.

Was this article helpful?

We're sorry to hear that.
Tell us how we can improve! documentation@fauna.com

Thank you for your feedback!