Sync Rules and Permissions
On this page
- Rules
- Partition-Based Rules and Permissions
- Partition-Based Sync Rule Behavior
- Partition-Based Sync Permissions
- Key Concepts
- Read Permissions
- Write Permissions
- Permission Strategies
- Global Permissions
- Permissions for Specific Partitions
- Permissions for Specific Users
- Permissions Based on User Data
- Function Rules
- Flexible Sync Session Roles and Rules
- Available Expansions in Flexible Sync Rules Quick Reference
- Default Roles
- Flexible Sync Rules
- Read Permissions
- Write Permissions
- Flexible Sync Permission Strategies
- Admin Read/Write, User Write Self
- Document Owner Read Only
- Global Admin, Department Admin, Department Member
- Custom and Default Roles
Rules
MongoDB Realm enforces data access rules for all requests to a synced cluster. Sync rules are dynamic JSON expressions that specify a given user's ability to view and modify synced data.
The way Sync rules work depends on whether you are using Partition-Based Sync or Flexible Sync.
This page describes data access rules for synced clusters. Non-synced cluster use a different rules model that sync rules override. If sync is enabled for a cluster, any non-sync rules defined for the cluster do not apply.
If your app does not use sync, check out MongoDB Collection Rules for more information on rules for non-synced clusters.
Partition-Based Rules and Permissions
Whenever a user opens a synced realm from a client app, Realm evaluates your app's rules and determines if the user has read and write permissions for the partition. Users must have read permission to sync and read data in a realm and must have write permission to create, modify, or delete objects. Write permission implies read permission, so if a user has write permission then they also have read permission.
Partition-Based Sync Rule Behavior
Sync rules apply to specific partitions and are coupled to your app's data model by the partition key. Consider the following behavior when designing your schemas to ensure that you have appropriate data access granularity and don't accidentally leak sensitive information.
- Sync rules apply dynamically based on the user. One user may have full read & write access to a partition while another user has only read permissions or is unable to access the partition entirely. You control these permissions by defining JSON expressions.
- Sync rules apply equally to all objects in a partition. If a user has read or write permission for a given partition then they can read or modify all synced fields of any object in the partition.
- Write permissions require read permissions, so a user with write access to a partition also has read access regardless of the defined read permission rules.
Partition-Based Sync Permissions
Realm enforces dynamic, user-specific read and write permissions to secure the data in each partition. You define permissions with JSON rule expressions that control whether or not a given user has read or write access to the data in a given partition. Realm evaluates a user's permissions every time they open a synced realm.
Your rule expressions can use JSON expansions like
%%partition
and %%user
to dynamically
determine a user's permissions based on the context of their request.
Key Concepts
Read Permissions
A user with read permissions for a given partition can view all fields of any object in the corresponding synced realm. Read permissions do not permit a user to modify data.
Write Permissions
A user with write permissions for a given partition can modify the value of any field of any object in the corresponding synced realm. Write permissions require read permissions, so any user that can modify data can also view that data before and after it's modified.
Permission Strategies
You can structure your read and write permission expressions as a set of permission strategies that apply to your partition strategy. The following strategies outline common approaches that you might take to define sync read and write permissions for your app.
Global Permissions
You can define global permissions that apply to all users for all partitions. This is, in essence, a choice to not implement user-specific permissions in favor of universal read or write permissions that apply to all users.
To define a global read or write permission, specify a boolean value or a JSON expression that always evaluates to the same boolean value.
Example | Description | |
---|---|---|
| The expression true means that all users have the given access
permissions for all partitions. | |
| The expression false means that no users have the given access
permissions for any partitions. | |
| This expression always evaluates to true , so it's effectively the
same as directly specifying true . |
Permissions for Specific Partitions
You can define permissions that apply to a specific partition or a groups of partitions by explicitly specifying their partition values.
Example | Description | |||||||||
---|---|---|---|---|---|---|---|---|---|---|
| This expression means that all users have the given access permissions
for data with a partition value of "Public" . | |||||||||
| This expression means that all users have the given access permissions
for data with any of the specified partition values. |
Permissions for Specific Users
You can define permissions that apply to a specific user or a group of users by explicitly specifying their ID values.
Example | Description | |||||||||
---|---|---|---|---|---|---|---|---|---|---|
| This expression means that the user with id
"5f4863e4d49bd2191ff1e623" has the given access permissions for data
in any partition. | |||||||||
| This expression means that any user with one of the specified user ID
values has the given access permissions for data in any partition. |
Permissions Based on User Data
You can define permissions that apply to users based on specific data defined in their custom user data document, metadata fields, or other data from an authentication provider.
Example | Description | |
---|---|---|
| This expression means that a user has read access to a
partition if the partition value is listed in the readPartitions
field of their custom user data. | |
| This expression means that a user has write access to a
partition if the partition value is listed in the
data.writePartitions field of their user object. |
Function Rules
You can define complex dynamic permissions by evaluating a function that returns a boolean value. This is useful for permission schemes that require you to access external systems or other custom logic that you cannot express solely in JSON expressions.
Example | Description | |||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| This expression calls the canReadPartition function and
passes in the partition value as its first and only argument. The
function looks up the user's permissions for the partition from a MongoDB
collection and then returns a boolean that indicates if the user can read
data in the requested partition. |
Flexible Sync Session Roles and Rules
In flexible sync, a session role determines which permissions apply for the duration of a sync session.
A session role consists of:
- A name
- An "apply when" rule expression
- A set of read and write rule expressions
You define Flexible Sync session roles on a per-collection basis. Each "collection" when using Realm Sync corresponds to a Realm Object type.
When a user begins a session by opening a synced realm, Realm determines which session role applies for the user for each collection in play. Realm considers session roles in the order that you defined them in the configuration. It evaluates each session role's "apply when" expression until one evaluates to true. If no session role applies, the user has no permissions for that collection.
Your session role "apply when" expressions can use JSON expansions to refer to user metadata and custom user data and even call functions to determine the given user's role. However, because Realm only evaluates session roles at the start of a session -- that is, before any query for specific documents -- you can't refer to a document or its field values to determine whether the session role applies.
The session role stays assigned for the duration of the session. If you make changes to an applied session role while a user is in the middle of a session, Realm does not evaluate the updated session role until the next time the user starts a session. Likewise, if something changes that would qualify the user for a different session role, the user's current session role does not change until the next session.
Realm triggers a client reset if anything about the session role changed since the previous session.
At the start of a session, Realm expands all JSON expansions in the "apply when", read, and write expressions and stores the result. This has the following implications:
- If the value changes during a session, Realm continues to use the value as it was at the time of session start.
- On the next session, if the value is different from what it was at the start of this session, Realm triggers a client reset.
- You cannot use the
%function
operator in read and write rules. Functions would not operate on a per-document basis. - You cannot store permissions information (such as "which document IDs may this user access?") in the user object.
Available Expansions in Flexible Sync Rules Quick Reference
Expansion | Can Use in "Apply When"? | Can Use in Read & Write Rules? |
---|---|---|
Yes | Yes | |
Yes | Yes with an important caveat | |
No | No | |
Yes | Yes with an important caveat | |
No. These expansions refer to the document. Realm evaluates "apply when" expressions at session start, so there's no document to evaluate. | No. These expansions might access non-queryable fields of the document, which is not possible. | |
No | No | |
Yes | No | |
Yes | No. Realm expands the expansions at the start of the session, so the function would not operate on a per-document basis. | |
Yes | Yes | |
Yes | Yes. However, note that you cannot currently have an array field as a queryable field on a document. | |
Yes | Yes |
Default Roles
You can create one or more default session roles that apply across all collections. If a collection does not have any custom session roles defined, session role resolution reverts to default session roles.
Because session roles apply only at the session level and not on a per-document level, most apps only need one (default) session role with per-document logic in that session role's read and write rules. With Flexible Sync, session roles can be thought of as a way to group read and write rule expressions to organize your code.
Flexible Sync Rules
You define a read and write rule expression pair for every session role.
Rule expressions can refer to the queryable fields of your data model.
In response to a Flexible Sync subscription query, Realm evaluates the read and write rule expressions for each document that matches the query. The client only receives documents where the rule expression evaluates to "true".
Consider the following behavior when designing your schemas to ensure that you have appropriate data access granularity and don't accidentally leak sensitive information.
- Sync rules apply dynamically based on the value of the queryable field or user metadata. One user may have full read & write access to a document while another user has only read permissions or is unable to access the document. You control these permissions by defining JSON expressions.
- There are no field-level permissions. Sync rules apply to all documents in a query on a per-collection basis. If a user has read or write permission for a given collection, then they can read or modify all synced fields of any document that matches the sync query in the collection.
- Write permissions require read permissions, so a user with write access to a collection also has read access regardless of the defined (or undefined) read permission rule.
Read Permissions
A user with read permissions for a given collection can view all fields of any object matching the client-side query. Read permissions do not permit a user to modify data.
Write Permissions
A user with write permissions for a given collection can modify the value of any field of any object matching the client-side query. Write permissions require read permissions, so any user that can modify data can also view that data before and after it's modified.
Flexible Sync Permission Strategies
These common flexible sync permission strategies rely on session role
names stored in custom user data. When a
logged-in user's session role name matches the name in the applyWhen
rule, the user has the corresponding read and write permissions for that
session role.
Admin Read/Write, User Write Self
In this permission strategy, users with the admin
role can read and
write any document. Users who do not have the admin
role can read any
document, but can only write their own data.
{ "Employees": [{ "name": "admin", "applyWhen": { "%%user.custom_data.isAdmin": true}, "read": {}, // evaluates to the same as true "write": {} }, { "name": "self", "applyWhen": {}, "read": {}, "write": {"employee_id": "%%user.id"} } ] }
Document Owner Read Only
In this permission strategy, users can read only their own documents. Users cannot write, even to their own documents.
{ "Employees": [{ "name": "everyone", "applyWhen": {}, "read": {"owner_id": "%%user.id"}, "write": false } ] }
Global Admin, Department Admin, Department Member
In this permission strategy, users with the globalAdmin
session role
can read and write to any document. Users with the departmentAdmin
session role can read any document, but can only write to documents in
their department. Users with the departmentMember
session role can
read any document in their department, but can't write to any documents.
Members can only read documents in their own departments; they cannot
read documents for other departments.
{ "Employees": [{ "name": "globalAdmin", "applyWhen": { "%%user.custom_data.isGlobalAdmin": true }, "read": {}, "write": {} }, { "name": "departmentAdmin", "applyWhen": { "%%user.custom_data.isLocalAdmin": true }, "read": {}, "write": { "department": "%%user.custom_data.department" } }, { "name": "departmentMember", "applyWhen": {}, "read": { "department": "%%user.custom_data.department" }, "write": false } ] }
Custom and Default Roles
This permission strategy combines custom and default roles. The custom
session role applies to the Employees
collection. The Store
collection is not listed in the configuration, and has no custom session
role, so it also evaluates to the default role.
Sync attempts to find a matching session role by traversing the session roles in descending order. List the most specific custom session roles first, getting gradually more general, so the user "falls through" to the correct session role. If no role applies, and you have defined a default role, the user gets the default role permissions.
{ "rules": { "Employees": [ { "name": "employeeWriteSelf", "applyWhen": {}, "read": {}, "write": { "employee_id": "%%user.id" } } ] }, "defaultRoles": [ { "name": "admin", "applyWhen": { "%%user.custom_data.isGlobalAdmin": true }, "read": {}, "write": {} }, { "name": "owner", "applyWhen": { "%%true": { "%function": { "name": "isOwner", "arguments": [ "%%user.id" ] } } }, "read": {}, "write": { "owner_id": "%%user.custom_data.ownerId" } }, { "name": "shoppers", "applyWhen": {}, "read": {}, "write": false } ] }