LogoLogo
What's NewDeveloper CommunitySupportStatus
  • 🚀Get Started
    • What is JourneyApps Platform?
    • Tutorial: Build your First App
      • 1. Introduction
      • 2. Create a new App
      • 3. OXIDE IDE Overview
      • 4. Hello World app
      • 5. The Data Model
      • 6. View Components
      • 7. Queries and Data Sync
      • 8. Simple Navigation
      • 9. View Stack
      • 10. Input Validation
      • 11. View Parameters
      • 12. Data Manipulation
      • 13. Responsive Apps
      • 14. Styling
      • 15. Lists
      • 16. GPS Capturing
      • 17. Relationships
      • 18. Multiple User Roles
      • 19. Deployment and Users
      • 20. Version Control
      • 21. CSV and APIs
      • 22. Conclusion
    • JourneyApps Platform Fundamentals
      • Creating a New App
        • Git-enabled Apps
      • What are Views?
      • What is the Data Model?
      • JourneyApps Syntax Basics
      • Access the Database (DB)
        • Manipulate DB Objects
        • Query DB Objects
      • View Navigation
        • Deep Linking
      • CloudCode Overview
      • OXIDE (Online IDE)
  • 💻Build your App
    • JourneyApps Syntax
      • Syntax Basics
      • Access the DB
      • View Navigation
      • Async & Await
      • TypeScript Apps (Beta)
        • runtime-build package
        • TypeScript App Troubleshooting
      • What's New in V4
        • Updating to the V4 API
    • Configure your Data Model
      • What is the data model?
      • Reference: model
        • field
        • belongs-to
        • has-many
        • index
      • Data Rules
        • Data Buckets
        • Sync Rules - Limit data synced to devices
        • Data ACLs - Limit access to data
        • Real-world example for Data Rules
        • ❔FAQs
        • Migrate to Data Rules
      • App Indexes
      • Webhooks
    • UI Components
      • All UI Components
        • actionSheet
        • Attachments
        • button
        • button-group
        • capture-coordinates
          • marker
          • marker-query
        • capture-file
        • capture-photo
        • capture-signature
        • card
          • accent
          • action
        • columns
          • column
        • component
        • context-menu
          • divider
          • item
        • CSV
        • date-input
        • datetime-input
        • dialog
          • body
        • display-3d-model
          • 📖display-3d-model Guides
            • Guide 1: Initialize and layout a 3D model in a view
            • Guide 2: Control playback position
            • Guide 3: Troubleshooting controls
        • display-coordinates
        • display-file
        • display-image
        • display-photo
        • display-signature
        • heading
        • html
          • HTML Advanced Topics
          • ❔HTML FAQs
          • 📖Guide: HTML & JourneyApps iFrame Client
        • icons
        • info
        • info-table
          • row
        • journey.photos (capture multiple photos)
        • JourneyPrinter (print PDFs)
        • grid
          • cell
          • 📖grid Examples
        • list
          • list-item
            • accent
            • asset
            • pills
              • pill
            • action
        • multiple-choice-checklist
        • navigation (Navigation drawer)
          • general-section
            • item
          • section
            • item
              • item
          • ❔navigation FAQs
        • notification
        • object-dropdown
        • object-list
          • action
        • object-repeat
        • object-table
          • action
          • column
            • action
            • edit-boolean
            • edit-date
            • edit-datetime
            • edit-integer
            • edit-number
            • edit-select
            • edit-text
            • edit-time
            • edit-typeahead
              • action
            • header-action
          • column-group
          • empty-action
          • 📖object-table Guides
            • Actions
            • Cell callouts
            • Column groups
            • Columns
            • Controlled object-table
            • Controls
            • Copy & paste data
            • Edit cells
            • Filters
            • Frozen columns
            • Fullscreen object-table
            • Mode
            • State
            • Styles
        • optionList
        • PhotonSync (transfer data offline)
        • power-bi
          • 📖Guide: PowerBI Embedding
        • scan-barcode
        • shortcut
        • sidebar
        • single-choice-dropdown
        • single-choice-radio
        • template
        • text-input
        • time-input
        • toggle
        • view
      • JS/TS Events
      • Show / Hide UI Components
      • View Templates
      • XML Fields (Attributes)
        • align-content
        • align-controls
        • align-label
        • bind
        • clear-button-visibility
        • control-order
        • disabled
        • error-message
        • icon-position
        • id
        • hide-if
        • modifier-text
        • label
        • label-case
        • label-color
        • on-change
        • on-press
        • placeholder
        • required
        • show-if
    • JS / TS APIs
      • Attachment
      • Bluetooth (Beta)
      • Broadcast
      • component
      • CSV
      • DB
      • HardwareBarcode
      • journey
        • journey.config
        • journey.container
        • journey.device
        • journey.diagnostics
        • journey.dialog
        • journey.files
        • journey.hardware
        • journey.photos
        • journey.runtime
        • journey.sensors
        • journey.viewStack
      • JourneyPrinter
      • KeyboardBarcode
      • LocalDB
      • NFC
      • OnlineDB
      • PhotonSync
      • SerialPort
      • ShortcutManager
      • TCPSocket
      • user
    • Extend your App with Custom Code
      • App packages
        • App packages overview
        • PDF report package
        • TypeScript library & unit tests
        • Manage External Dependencies
      • Custom HTML
    • Style & Customize your App
      • Style & configure UI components
        • Overview
        • Understand extendable themes
        • Use themes on a view
        • Theme specific components on a view
        • Examples
        • Debugging
        • ❔FAQs
      • Change your App Font
      • Custom Branding
        • Custom Container Features
        • Special Requirements for iOS Containers
    • Integrate your App
      • Backend integrations with CloudCode
      • Barcode Scanning
        • Barcode Scanning using Keyboard Emulation
        • Hardware Barcode Scanning
        • scan-barcode
      • Bluetooth Low Energy (BLE)
      • Broadcast API
      • HTTP requests (Fetch API)
      • JourneyApps Print (Android)
      • Maps and navigation
      • NFC
      • Opening external links/apps
      • Serial Port
      • TCP Sockets
    • Design Intuitive Apps
      • UX Guidelines
      • Write Effective Copy
  • 📱App Features
    • RealWear® Voice Control
      • Automatic Voice Commands
        • Automatic Voice Commands - Advanced
      • Manual Voice Commands
    • App, Runtime and Container Updates
    • Batch Operations (App)
    • Call JS/TS Functions from XML
    • Capture GPS Locations
    • Push Notifications
    • Translations
    • XML Format Strings
    • Webhooks (External)
  • 🌐CloudCode
    • CloudCode Overview
    • Trigger a CloudCode Task
      • Trigger CC with a Schedule
      • Trigger CC via a Webhook
      • Trigger CC from an App
      • Trigger CC from Another Task
      • Trigger CC via HTTP
    • Attachments in CloudCode
    • Timezones
    • Advanced CloudCode Topics
      • Access Multiple DBs in CloudCode Tasks
      • Batch API (CloudCode)
      • CloudCode Dependencies
      • Configure HTTPS in CloudCode
      • Deployment environment variables
      • Local CloudCode Development
      • PDF Reports using CloudCode
      • Shared CloudCode Tasks
      • Translations in CloudCode
  • 📥Backend API
    • Introduction
    • API Reference
      • Retrieve All Objects
      • Query Objects
      • Sort Results
      • Limit and Skip
      • Count Objects
      • Create a New Object
      • Retrieve a Single Object
      • Update a Single Object
      • Delete a Single Object
      • Batch Operations (v4 API)
      • Oplog API
      • Retrieve the App Data Model
      • Manage App Users and Sessions
      • Field Representation
      • Error Responses
    • API Limits
    • Update to the V4 API
  • ⚙️Technical
    • Data Synchronization Priority
    • Device Diagnostics
    • JSON1 Query Engine
    • Improve App Performance
    • Security Measures
    • Supported Platforms
      • Web Container
      • Windows Installer
    • Domain Whitelist
  • 🖥️OXIDE
    • Get started with OXIDE
      • OXIDE Overview
      • Components of OXIDE
    • Configure Testing Deployments
    • Edit and Manage Files
      • How to Navigate to a Function
      • Manage External Dependencies
    • Create and Manage App Containers
    • Debugging & Troubleshooting
      • Common Troubleshooting Pointers
      • App Diagnostics Reports
      • Build Logs
    • OXIDE Workspaces
      • OXIDE Trees
  • ❕Deprecated Features
    • Deprecated Features and Components
Powered by GitBook
On this page
  • Data Buckets
  • Data ACLs syntax
  • Examples
  • Implications of implementing data ACLs
  • What happens when access to data is denied
  • Data Rule Reprocessing
  1. Build your App
  2. Configure your Data Model
  3. Data Rules

Data ACLs - Limit access to data

PreviousSync Rules - Limit data synced to devicesNextReal-world example for Data Rules

Last updated 2 years ago

Data ACLs give more granular control over users' access to data objects, therefore making apps more secure. This is achieved by specifying read and/or write permissions on and their relationships when querying DB or OnlineDB.

ACLs vs sync rules

ACLs specify users' access to data objects, whereas sync rules specify which data syncs to users' devices. This document describes ACLs. You can learn more about sync rules

Data ACLs on Web

For apps on it is strongly recommended to implement data ACLs to limit data a single compromised web user could have access to.

Data Buckets

Data ACLs are specified on data buckets. It is important that you are familiar with these before moving on to the next sections. Read up about them here:

Data ACLs syntax

Data ACLs read and write attributes that can be specified for the data buckets , , and the model and has-many tags within these buckets.

Note: These are only “allow” rules - no “deny” rules are supported. This means that if any rule matches, the operation is allowed.

read="any|none|online|offline"

Type
Description

any (default)

Allow syncing of the data, and allow OnlineDB querying of the data.

none

Disable syncing of the data, and disable OnlineDB querying of the data.

online

Disable syncing of the data, and allow OnlineDB querying of the data.

offline

Allow syncing of the data, and disable OnlineDB querying of the data.

Attachments require online access

Downloading attachments requires online access, since they are not stored on a device. The recommended rule for attachments is read="any".

write="any|none|create|update|delete"

  • You can specify one, or a comma-separated combination of the above. E.g. write="none" or write="create,update"

Type
Description

any (default)

Allow any write to an object, as long as the user still has access to the object afterwards.

none

Make the data read-only - don’t allow creating, updating or deleting.

create

Allow the user to create new objects, but not modify existing ones. This is mostly useful for use cases such as creating logs or audit events.

update

Allow updating existing objects in the bucket.

delete

Allow deleting existing objects in the bucket.

Object-specific bucket roots

data_rules.xml
<bucket via="self/region">
    <!-- The root is region in this case -->
    <root write="none" read="any" />
    
    <has-many name="clients" />
</bucket>

If not specified (the tag is not present, or attributes on the tag are not present), root object access permissions default to:

<root read="any" write="update,delete" />

Root permissions have some important details:

  • Only a single root tag is allowed per bucket.

  • When the via path to the bucket root is a belongs-to relationship, write="create" is not a valid permission. Additionally, the write="any" permission also does not allow creates on root objects in this case (but it does allow updates and deletes). The reason for this is that the relationship from the user to the root object would need to be set before creating the root object:

<bucket via="user/region">
   <root write="any" />
</bucket>

let region = DB.region.create();
region.save(); // Not allowed, since user.region() isn't set yet

user.region(region);
user.save(); // Not allowed, unless the region was already saved
  • This does not apply to bucket roots where the via path to the root is a has-many relationship. In this case, write="create" and write="any" are valid permissions and writes are supported if a single operation creates the root object and assigns it to the user/bucket. To illustrate with an example:

<bucket via="user/jobs">
   <root write="any" />
</bucket>

DB.job.create({user: user}).save();  // Allowed, because a single operation
                                     // creates and assigns the user

Examples

Read-only access to all globally synced models:

By specifying write="none" on this global bucket, its data is synced to all users and they have read-only access.

data_rules.xml
<data-rules version="3">
    <global-bucket write="none">
        <!-- These are synced and are read-only -->
        <model name="category" />
        <model name="subcategory" />
    </global-bucket>
</data-rules>

Role-specific access rules:

In this example, only admins should be able to update certain data, while all other users have read-only access. Here we define the read="none" rule on the data bucket that provides write access for admins, since another data bucket already allows synching and unrestricted read access to these objects for all users (including admins).

data_rules.xml
<data-rules version="3">
    <global-bucket write="none">
        <model name="category" />
        <model name="subcategory" />
    </global-bucket>
    
    <!-- For admins: Allow write access and disable syncing and read access, 
    to avoid duplication with the above bucket. -->
    <global-bucket via="self[role == 'admin']" write="any" read="none">
        <model name="category" />
        <model name="subcategory" />
    </global-bucket>
</data-rules>

Allow users to create new regions, but not update their own

In this example, a user belongs-to a region, and the region has-many clients. Users have unrestricted access to their region's clients, but cannot update their own region (and thereby access other region's clients). However, they can create new regions.

data_rules.xml
<data-rules version="3">
    <bucket via="self/region">
        <!-- Prevent writes to the user's region (the bucket root) -->
        <root write="none" />
        
        <!-- Unrestricted access to clients belonging to the user's region -->
        <has-many name="clients" />
    </bucket>
    
    
    <global-bucket>
        <!-- Allow users to create new regions -->
        <model name="region" write="create" />
    </global-bucket>
</data-rules>

Prevent writes to objects after they've reached a certain state

Sometimes it may be necessary to "lock objects" after they have reached a certain state. In this example, we want to prevent technicians from updating jobs once they have been marked as completed.

data_rules.xml
<data-rules version="3">
    <bucket via="self[technician == true]/region">
        <!-- Technicians cannot update jobs in their region once they are completed -->
        <has-many name="jobs" condition="completed == true" write="none" />
        <!-- Allow technicians to update jobs in their region 
        if they are not marked as completed -->
        <has-many name="jobs" condition="completed == false" write="any" />
    </bucket>
</data-rules>

Overwriting access on a bucket's root and relationships:

Here we override the access rules defined for the overall bucket (the default: sync, read and write access), by defining various access rules on the bucket's root and relationships. The individual access rules are described below.

data_rules.xml
<data-rules version="3">
    <!-- The bucket has sync, read and write access -->
    <bucket via="self/region">
        <!-- Prevent writes to the user's region (the bucket root) -->
        <root write="none" />

        <!-- locked clients are synced and read-only -->
        <has-many name="clients" condition="locked == true" write="none" />
        <!-- unlocked clients are synced and can be updated -->
        <has-many name="clients" condition="locked == false" write="any" />
        
        <!-- audit_items are too many to sync, so can only be queried via OnlineDB -->
        <has-many name="audit_items" read="online" />
        
        <!-- log_entries are create-only -->
        <has-many name="log_entries" read="none" write="create" />
    </bucket>
</data-rules>

Implications of implementing data ACLs

App performance is affected in certain cases

Large number of OnlineDB queries and individual object lookups in your app can negatively affect app performance, since individual requests are slower to perform with data rules.

Tips to improve app performance with data rules:

OnlineDB access is limited to synced data by default

The default behavior of data rules is that OnlineDB access is limited to data synced to the device (in other words, as previously specified in the app's sync rules).

With sync rules, it was possible to query any model via OnlineDB, regardless of the model being included in sync_rules.xml. With data rules, only the data specified in data_rules.xml is accessible with OnlineDB.

Let's look at an example. Take the following sync rules definition:

sync_rules.xml
<sync version="2">
    <global-bucket>
        <model name="country" />
        <model name="district" />
    </global-bucket>
</sync>

Since sync rules only specify which data is synced to a device, it would be possible to query another model not included in the sync rules using OnlineDB:

main.js
function init() {
    var sites = OnlineDB.site.all().toArray();
}

With data rules, given the initial sync rules definition, the above OnlineDB query would not return any results. Read or write access to site via OnlineDB would need to be explicitly defined within data rules to support the above query:

data_rules.xml
<data-rules version="3">
    <global-bucket>
        <model name="country" />
        <model name="district" />
        <!-- Allow read access via OnlineDB (write access defaults to any) -->
        <model name="site" read="online" />
    </global-bucket>
</data-rules>

Object writes are only performed if the user has access before and after an update

With data rules, object writes are only performed if the user has access to the object before and after an update. Of course, for create operations it’s only the after state that is validated.

This means that where updates to objects need to occur by a user, those objects still need to be accessible to the user after the update.

Let's look at a practical example.

Take the following bucket defined in data_rules.xml:

data_rules.xml
<bucket via="self/region">
    <!-- only jobs that are not complete are synched -->
    <has-many name="jobs" condition="complete != true" write="any" />   
    ...
</bucket>

And consider the following in-app logic that marks a job as complete.

main.js
function markComplete(selectedJob) {
    selectedJob.complete = true;
    selectedJob.save();
}

Therefore, it is important to review all conditional buckets and models, and ensure that writes are supported.

Taking the above example, the following additional rule in data_rules.xml would enable updates to a job:

data_rules.xml
<bucket via="self/region">
    <!-- only jobs that are not complete are synched -->
    <has-many name="jobs" condition="complete != true" write="any" /> 
    <!-- sync completed jobs to allow setting the completed flag to true --> 
    <has-many name="jobs" condition="complete = true" write="update" />   
    ...
</bucket>

Additional buckets when migrating to data rules

Manual tests are required before deploying data rules to an environment with active users

What happens when access to data is denied

When data rules prevent access to data for a user/device, they can expect the following to happen:

  1. OnlineDB save() operations will throw an "Access denied" error.

  2. OnlineDB destroy() operations will appear to work, but the data will not be touched.

  3. OnlineDB queries will exclude the results.

  4. DB save() operations will show an "Access denied" error in the developer console (in JourneyApps Runtime version 4.85.0 and greater).

Data Rule Reprocessing

Object-specific bucket access rules include their by default. To overwrite this behavior, read and write attributes can be specified for the root object, by adding the a root tag inside a bucket, e.g.:

Use when related objects need to be looked up in a query

When doing individual object lookups, use to batch the requests

When doing OnlineDB writes, use

Note: When , additional data rules will automatically be added to your data rules to support existing OnlineDB calls in your app given this implication. See more details .

Note: When , additional data rules will automatically be added to your data rules to support existing object writes throughout your app given this implication. See more details .

Once a user marks a job as complete, the job would no longer be accessible to the user, as only incomplete jobs are synced to the device. With , this kind of update is supported. With data rules, however, since the user would no longer have access to the job after this update (of setting the complete boolean to true).

When , these rules to support writes to objects that are only conditionally synced, are automatically created. Read more about this here.

Since data rules control which data is available to users it is recommended you test data users should be able to access, and data they shouldn’t be able to access before deploying to active users. For this, you can use the , and specifically run OnlineDB calls and queries. The below section on , should also help with these tests.

Data rule reprocessing follows the same principles as.

Sync rule reprocessing is only applicable if updates have been made to rules that affect what data is synced. Therefore, there are several cases where updates to data rules would not require reprocessing. This includes , and updating/adding/removing rules that don’t have read="any" or read="offline" set. These data rules take effect immediately after deploying an update.

💻
Batch
sync rules
migrating to data rules
migrating to data rules
here.
web
Data Buckets
migrating your app from sync rules to data rules
migrating your app from sync rules to data rules
what happens when access is denied
data buckets
here
here
sync rule reprocessing
global-bucket
bucket
root objects
debug developer console
.include(relationship)
.where('id in ?',ids)