why deepstreamHub? compare us getting started feature roadmap faq
use cases pricing
enterprise blog contact


This tutorial covers aspects of Valve – deepstreamHub’s realtime permission language. You can specify Valve rules in the permission section of the dashboard or upload them via the HTTP API.

Valve Permission Section on deepstreamHub dashboard
Ok, time for some advanced valve rules, but if you're not quite ready yet, you can get up to speed with the basics just head over to the simple Valve example.


Valve automatically injects a set of variables into its permission rules.

data & oldData

data contains the data for events and RPCs. It can be used to validate the payload.

# make sure a tweet contains max 140 characters
    publish: "data.content.length < 140"
# make sure firstname is a string
    write: "typeof data.firstname === 'string'"

For records, data is the INCOMING data - the current data is available as oldData. This is helpful for comparisons:

# make sure bids at an auction can only go up
    write: "data.price > oldData.price"
# make sure that `owner` can't be changed once written
    write: "!data.owner || data.owner == oldData.owner"


user is an object containing information about the user attempting the action. It offers user.id - the username that was provided at login and user.data.

user.data is the meta-data that was provided when the user logged in. This could be the data returned by the http webhook as serverData or the serverData specified via the dashboard. Data is a great place to store authentication data like roles (e.g. {role: 'admin'}), access-levels or flags like { canDeletePosts: false }.

Permissioning also allows age based validation in conjunction with now, e.g., new users on a website may create new content and modify existing data only if more than 24 hours passed since signing up:

        record: "user.data.timestamp + 24*60*60*1000 < now"
        write: "user.data.timestamp + 24*60*60*1000 < now"

String Functions

Valve supports a number of built-in string functions, namely startsWith, endsWith, indexOf, match, toUpperCase, toLowerCase and trim. These can be useful to normalize and compare values, e.g.

        request: "data.card.issuer.toLowerCase() == 'visa' && data.card.number.match(/^4[0-9]{12}(?:[0-9]{3})?$/)"

Cross References

Cross references allow you to reference data from other records within deepstreamHub. This is an incredibly versatile feature; allowing you to check states or user data; make sure an item being purchased is still in stock or verify pre-conditions, e.g. making sure a user can only vote once. Cross references are written as _(recordName).

    request: _('shop-status').isOpen == true

Record names referrenced by the _() function can also be dynamically created, e.g. from strings and path-variables.

# Make sure an item is still in stock
    request: _('item/' + $itemId ).inStock > 0

Nesting cross-references

It's even possible to nest cross references. Say you are running an online pharmacy and can only sell certain categories of drugs in countries they have clearance for. Here's the data you have to work with:

// record drug/iqbxxluu-2lc9bl30t18
    name: 'Aprotinin',
    categoryId: 'iqbxyw8u-1e686wg77xk'

// record category/iqbxyw8u-1e686wg77xk
    name: 'general Antifibrinolytics'
    allowedCountries: [ 'FRA', 'SPA' ]

// user.data
    country: 'USA'

the rule below would now perform the following steps:

  • load information about the drug the user is trying to purchase
  • use the drug's categoryId to load the category it belongs to
  • check if the user's country is in the list of countries this drug's category can be sold in
# Make sure a drug's category is cleared for sale in the user's country
    request: _('category/' + _( 'drug/' + $drugId ).categoryId ).allowedCountries.indexOf( user.data.country ) > -1

In this case the purchase attempt would be declined as the drug's category is only cleared for sale in France and Spain, but the user is from the US.

Performance implications of cross-references

Every cross-reference executes an additional query against deepstreamHub's cache for every permissioning step - which will slow message transactions down. Nested cross references in particular are loaded one after another, so can lead to noticeable delays - so use with caution and try to limit cross-referencing on performance-critical paths.

Realtime Permissions

If all this made sense, it might be time to take your Valve skills to the next level. Learn how to create realtime-permissions that can be modified at runtime!