Skip to main content
Version: 9.2

Record-Level Security Basics

Use Record-Level Security to protect and filter rows of data so users only see the records they are allowed to see. This control can help you to manage multi-tenant or role-sensitive applications.

Overview

Record-Level Security is a server-side security filter that pre-filters records before a user loads a widget. It is most commonly used to enforce tenant isolation in a commingled dataset architecture.

To enable record-level security, mark the Record-Level Security columns in Qrvey Composer, then securely pass the permissions block from your backend when you generate the widget configuration.

Core Principles

Record-Level Security embodies the following core principles:

  • Restrictions should be applied so the end user is not aware filters are enforced.
  • End users should not be able to see or modify the Record-Level Security filters.
  • Record-Level Security values should be treated as sensitive and stored on the server side.

Tutorial Video

The following tutorial video shows how to set up Record-Level Security.

Tags: Embed, Record-Level Security, Authorization

General Configuration

Record-Level Security requires the following general configuration steps.

Step 1: Designate Dataset Fields as Record-Level Security Fields

  1. Open your dataset in Qrvey Composer.

  2. Select the options menu for a column (for example, ProductID), then select Enable Record Level Security.

    Enable Record Level Security
  3. Enter a security name (for example, product_id) to be referenced in the widget JSON.

    • It can match the column name for clarity.
    • Do not include spaces or special characters. Use underscores if needed.
  4. Apply your changes.

Step 2: Pass Record-Level Security Values When Embedding

When you embed a widget, you must pass the Record-Level Security values in the JSON permissions block of the widget configuration. Record-Level Security is nested under the permissions property. The structure is an array because you might need to define Record-Level Security for multiple datasets.

The following code snippet shows the minimum structure required to pass Record-Level Security:

app.get('/api/get-jwt-token', async (req, res) => {
try {
const response = await axios.post('https://demo.qrvey.com/devapi/v4/core/login/token', {
version: 2,
expiresIn: '1w',
appId: 'i38McJ02G',
userId: 'HPESUG1wR',
clientId: 'HPESUG1wR',
orgId: 'org:0',
permissions: [
{
dataset_id: "dataset1",
record_permissions: [
{
security_name: "product_id",
validation_type: "EQUAL",
values: ["344"]
}
]
}
]
});
  • Permissions are displayed as an array of objects. Each object represents one dataset to filter.
  • Inside each dataset object, the record_permissions array contains security filter objects.
  • Each security filter includes a security_name (set to the name of the Record-Level Security column), operator, and values to filter by.
  • Each dataset can contain multiple Record-Level Security columns.
  • Do not include Boolean operators (AND/OR) when passing a single value. Keep values minimal and clear.

Placement of Record-Level Security Code

Record-Level Security values are sensitive. Do not embed the raw permissions block directly in the client-side code. Because the widget configuration is visible on the client, use the following techniques:

  • Generate the widget configuration and sensitive properties from your back end. Do not pass Record-Level Security configuration in the widget's configuation object.
  • Include the Record-Level Security configuration in the body of your JWT token that the client can pass to the embedded component.
  • Make sure the client only receives the encrypted configuration, not raw Record-Level Security values.

Step 3: Locate the Dataset ID

The dataset_id used in the permissions block serves as the internal Qrvey dataset identifier. It can be found in the URL of the dataset design page in Composer:

https://example.qrvey.com/#/application/appId/data-uploads/dataset_id/

Copy that dataset ID into the widget permissions block.

Step 4: Test Record-Level Security

After you add the permissions block to your server-generated widget configuration, restart your backend service if needed and load the embedded widget. If configured correctly, the embedded view displays only the records allowed by the Record-Level Security values you passed.

Example test:

  1. Pass a single product ID (for example, product_id = 344) in the permissions block.
  2. Load the widget. The widget should render only the records for product 344.

Record-Level Security in Composer

Record-Level Security does not apply in Composer. Within Composer, you still see all values. Record-Level Security takes effect in the embedded widget when it receives the permissions block that contains filter values. This means developers can design and test dashboards in Composer using regular filters.

Tip: To permit the embedded widget to show all records during testing, pass a wildcard for all security columns. Use an asterisk to represent a wildcard:

"values": ["*"]

This lets embedded views behave like Composer until you start passing explicit Record-Level Security values.

Best Practices

  • Designate Record-Level Security fields in the dataset before applying any changes.
  • Store Record-Level Security values on the server side. Never expose raw Record-Level Security values on the client side.
  • Embed only the encrypted widget configuration using JWT.
  • Test by embedding and running client-side filters to confirm only permitted values appear.
  • Use the asterisk wildcard for temporary testing to mimic Composer behavior.