You're viewing the legacy docs. They are deprecated as of May 18, 2016.
Go to current docs

Security & Rules Guide

Bolt Compiler

The Bolt Compiler is a Type-based modeling and authorization language that compiles to JSON based security rules.

Overview

Firebase is secured using a JSON-formatted Security and Rules language. It is a powerful feature of Firebase, but can be error prone to write by hand.

The Bolt compiler helps developers express the schema and authorization rules for their database using a familiar JavaScript-like language. This guide introduces the concepts and features of Bolt.

Installation

The Bolt compiler is used via the command-line with the firebase-tools You'll need to have the firebase-tools installed and the firebase-bolt package.

npm install --global firebase-tools
npm install --global firebase-bolt

Name your Bolt files with a .bolt file extension, such as rules.bolt. To compile the Bolt file into JSON based rules, use the following command:

firebase-bolt < rules.bolt > rules.json

Path statements

A path statement describes where your data is stored in Firebase, and how it can be accessed.

path / {
  read() = true;
  write() = true;
}

This path statement, defines read and write permissions to every part of your database (all paths beneath the root (/) of the database). The read and write methods are defined using the syntax read() = <expression>;. When the expression evaluates to true, reading (or writing) is allow at the given path location (and all children of that path).

Use the Bolt compiler to convert this to Firebase JSON-formatted rules:

firebase-bolt < all_access.bolt
{
  "rules": {
    ".read": "true",
    ".write": "true"
  }
}

Type statements

The core idea of Bolt is using data types to express the schema of a path. Type statements describe the structure of your data.

The Firebase database is schemaless. Unless you specify otherwise, any type or structure of data can be written anywhere in the database. Specifying a schema enables you to catch coding errors early, and prevent malicious programs from writing data that you don't expect.

Let's say an application wants to allow users to write messages to your database. Each message can be up to 140 characters and must by signed by the user. In Bolt, you can express this using a type statement:

type Post {
  message: String,
  from: String
}

// Allow anyone to read the list of Posts.
path /posts {
  read() = true;
}

// All individual Posts are writable by anyone.
path /posts/$id is Post {
  write() = true;
}

This database allows for a collection of Post to be stored at the /posts path. Each one must have a unique ID key. Note that a path expression (after the path keyword) can contain a wildcard component. This matches any string, and the value of the match is available to be used in expressions, if desired.

For example, writing data at /posts/123 will match the path statement when $id is equal to (the string) '123'.

The Post type allows for exactly two string properties in each post (message and from). It also ensures that no message is longer than 140 characters.

Data Validation

Bolt type statements can contain a validate() method. If the expression evaluates to true if the data is valid and can be saved to the database. When the expression evaluates to false, the attempt to write the data will return an error to the Firebase client and the database will be unmodified.

Let's modify our Post type to only accept messages that have a character count less than or equal to 140 characters.

type Post {
  // validate character length of the message property
  validate() = this.message.length <= 140;

  message: String,
  from: String
}

To access properties of a type in an expression, use the this keyword. The this keyword references the data representing the type.

Bolt is designed to output idiomatic Firebase JSON Rules.

{
  "rules": {
    "posts": {
      ".read": "true",
      "$id": {
        ".validate": "newData.hasChildren(['message', 'from']) && newData.child('message').val().length <= 140",
        "message": {
          ".validate": "newData.isString()"
        },
        "from": {
          ".validate": "newData.isString()"
        },
        "$other": {
          ".validate": "false"
        },
        ".write": "true"
      }
    }
  }
}

Built-in Data Types

Bolt supports the built-in datatypes of String, Number, Boolean, Object, Any, and Null. Null is useful for specifying optional properties.

path / is Sample;

type Sample {
  name: String,
  age: Number,
  isMember: Boolean,

  // The | type-operator allows this type to be an Object or undefined (null in Firebase).
  attributes: Object | Null
}

Extending Built-in Types

Bolt allows user-defined types to extend the built-in types. This can make it easier for you to define a validation expression in one place, and use it in several places. For example, suppose we have several places where we use a NameString - and we require that it be a non-empty string of no more than 32 characters:

path /users/$id is User;
path /rooms/$id is Room;

type User {
  name: NameString,
  isAdmin: Boolean
}

type Room {
  name: NameString,
  creator: String
}

type NameString extends String {
  validate() = this.length > 0 && this.length <= 32;
}

The type NameString can be used anywhere the String type can be used - but it adds the additional validation constraint that it be non-empty and not too long. Note that the this keyword refers to the value of the string in this case.

Functions

Bolt also allows you to organize common expressions as top-level functions in a Bolt file. Function definitions look just like type and path methods, except they can also accept parameters.

isUser(uid) = auth != null && auth.uid == uid;

path /users/$userid is User {
  read() = true;
  write() = isUser($userid);
}

type User {
  name: String,
  age: Number | Null
}

The isUser() function will test if the given user id matches the currently signed-in user. Bolt functions can be included in any path statement.

Workflow

Bolt is not yet integrated into the online Firebase Security and Rules Dashboard. There are two ways to use Bolt to define rules for your application:

  1. Use the firebase-bolt command line tool to generate a JSON file from your Bolt file, and then copy and paste the result into the Dashboard Security and Rules section.
  2. Use the Firebase Command Line tool. If you have firebase-bolt installed on your computer, you can set the rules property in your firebase.json file to the name of your Bolt file. When you use the deploy command, the command line will read and compile your Bolt file and upload the compiled JSON to your application Rules.