Docs Menu

Sync Rules and Permissionsicons/link.png

On this page

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.

Important
Non-Sync Rules

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.

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.

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.

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.

Tip

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.

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.

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.

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
true
The expression true means that all users have the given access permissions for all partitions.
false
The expression false means that no users have the given access permissions for any partitions.
{ "%%true": true }
This expression always evaluates to true, so it's effectively the same as directly specifying true.

You can define permissions that apply to a specific partition or a groups of partitions by explicitly specifying their partition values.

Example
Description
{ "%%partition": "PUBLIC" }
This expression means that all users have the given access permissions for data with a partition value of "Public".
{
"%%partition": {
"$in": [
"PUBLIC (NA)",
"PUBLIC (EMEA)",
"PUBLIC (APAC)"
]
}
}
This expression means that all users have the given access permissions for data with any of the specified partition values.

You can define permissions that apply to a specific user or a group of users by explicitly specifying their ID values.

Example
Description
{ "%%user.id": "5f4863e4d49bd2191ff1e623" }
This expression means that the user with id "5f4863e4d49bd2191ff1e623" has the given access permissions for data in any partition.
{
"%%user.id": {
"$in": [
"5f4863e4d49bd2191ff1e623",
"5f48640dd49bd2191ff1e624",
"5f486417d49bd2191ff1e625"
]
}
}
This expression means that any user with one of the specified user ID values has the given access permissions for data in any partition.

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
{ "%%user.custom_data.readPartitions" : "%%partition" }
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.
{ "%%user.data.writePartitions" : "%%partition" }
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.

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
{
"%%true": {
"%function": {
"name": "canReadPartition",
"arguments": ["%%partition"]
}
}
}
// canReadPartition
exports = async (partition) => {
const cluster = context.services.get("mongodb-atlas");
const permissions = cluster
.db("myApp")
.collection("permissions");
const { canRead } = await permissions.findOne({ partition });
return canRead.includes(context.user.id);
}
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 rules apply on a per-collection basis. They are coupled to your app's data model by the queryable field or user metadata. 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 entirely. You control these permissions by defining JSON expressions.
  • Sync rules apply on a per-collection basis to all documents in a query. 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 read permission rules.

When a user submits a query to the Realm app, Sync determines which role applies for the user.

A role consists of:

A role might also include a collection name, if it is a collection-specific role.

A role applies for the duration of the session. If you make changes to an applied role while a user is in the middle of a session, Realm does not evaluate the updated role until the next time the user starts a session.

Because roles apply at the collection level, a user could have different roles for different collections.

Roles resolve to a lower level of permissions until the user's metadata evaluates to true for a given role. At that point, the user receives the corresponding permissions for the duration of their session.

You can create one or more default roles that apply across all collections. If a collection does not have any custom roles defined, role resolution reverts to default roles.

Realm enforces dynamic, user-specific read and write permissions to secure the data in each collection and query. 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 collection and query. Realm evaluates a user's permissions at the beginning of each session.

Tip

Your rule expressions can use JSON expansions to dynamically determine a user's permissions based on the context of their request. However, the user can only use expansions that do not refer directly to a document or the document's values.

Flexible Sync rules must be configured on either:

If you configure rules on anything else, Flexible Sync cannot assign the correct role.

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.

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.

These common flexible sync permission strategies rely on role names stored in custom user data. When a logged-in user's role name matches the name in the applyWhen rule, the user has the corresponding read and write permissions for that role.

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": {
"roles": [
{
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"}
}
]
}
}

In this permission strategy, users can read only their own documents. Users cannot write, even to their own documents.

{
"Employees": {
"roles": [
{
name: "everyone",
applyWhen: {},
read: {owner_id: "%%user.id"}
write: false
}
]
}
}

In this permission strategy, users with the globalAdmin role can read and write to any document. Users with the departmentAdmin role can read any document, but can only write to documents in their department. Users with the departmentMember 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": {
"roles": [
{
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
},
]
}
}

This permission strategy combines custom and default roles. The custom role applies to the Employees collection. The Items collection has no custom role, and therefore the default role applies. The Store collection is not listed in the configuration, and has no custom role, so it also evaluates to the default role.

Sync attempts to find a matching role by traversing the roles in descending order. List the most specific custom roles first, getting gradually more general, so the user "falls through" to the correct role. If no role applies, and you have defined a default role, the user gets the default role permissions.

{
"Employees": {
"roles": [
name: "self",
applyWhen: {},
read: {}
write: {"employee_id": "%%user.id"}
]
},
"Items": {}, // an empty collection will thus conform to the defaultRoles
// the Stores collection is not listed but is part of the syncing schema and
// thus will conform to the defaultRoles, the same as: "Stores": {},
"defaultRoles": {
"roles": [
{
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
},
]
}
  • Sync rules allow you to control who can read and write data in a given realm.
  • You can define rules in the Realm UI or by importing them with Realm CLI.
Give Feedback
MongoDB logo
© 2021 MongoDB, Inc.

About

  • Careers
  • Investor Relations
  • Legal Notices
  • Privacy Notices
  • Security Information
  • Trust Center
© 2021 MongoDB, Inc.