# ABAC via tokens (pre-10.4.0.cl)

> For the complete documentation index, see [llms.txt](https://developers.thoughtspot.com/docs/llms.txt)

Source: https://developers.thoughtspot.com/docs/abac-user-parameters-beta

# ABAC via tokens (pre-10.4.0.cl)

This article describes the best practices to implement Row-level security (RLS) using Attribute-Based Access Control (ABAC) in a pre-10.4.0.cl environment. If your ThoughtSpot instance is on 10.4.0.cl or later, please refer to the [GA documentation]({{navprefix}}/{{abac-user-parameters}}).

> **IMPORTANT:** As this feature directly impacts data security, it’s disabled by default on ThoughtSpot instances. With the GA rollout, ThoughtSpot recommends switching your workflow to the auth/token/custom API endpoint. For more information, see the migration guide.

## Overview

In ABAC implementation, security entitlements are sent in as lists of attributes with the token at session creation time via the authentication service.

Administrators can set the following attributes for a user via the authentication token, along with the existing capability to assign ThoughtSpot groups:

-   [Runtime filters]({{navprefix}}/{{runtime-filters}})  
    Can filter multiple values of any data type. Binds to any Column in any Data Source with a matching Column Name (ThoughtSpot property, not underlying database table column name).
    
-   [Parameters]({{navprefix}}/{{runtime-parameters}})  
    Binds a single value to any Parameter in any Worksheet by Parameter Name and Type match. Parameters can be used in **worksheet formulas** and then as **worksheet filters**.
    
-   [Runtime sorts]({{navprefix}}/{{runtime-sort}})  
    Overrides to sort order within columns.
    

> **IMPORTANT:** The runtime filters require passing the exact ThoughtSpot Worksheet or Model column name or will not apply to the data set. You must coordinate between the team that maintains the worksheets and the team that builds the token request service if any changes will be made to a worksheet, or the filters will no longer be applied. For the same reasons, end users of an embedded app cannot have edit access to any worksheet using ABAC RLS via tokens.

The request for a token with ABAC details can [persist]({{navprefix}}/{{abac-user-parameters-beta}}#persistForUser) the set of filters and Parameter values to the user’s `user_parameters` property, after which all sessions and scheduled reports will use the persisted values.

## Token request

The ABAC message to ThoughtSpot is encoded in JSON Web Token (JWT) format, using the existing ThoughtSpot V2.0 REST API access tokens, which are OAuth JWT tokens.

The token can be used as a bearer token for cookieless Trusted Auth or REST API access, or as a sign-in token to create a ThoughtSpot session, in which case the ABAC user parameters should be **persisted**.

> **NOTE:** ThoughtSpot compresses the size of JWT token by default to ensure that larger payloads, for instance, more complex filtering conditions can be passed via JWT. ThoughtSpot recommends leaving that compression on to ensure all JWT tokens can get properly interpreted by the application regardless of their size, and to obfuscate the values passed in the JWT payload. However, if you want to decode the JWT token and decode the values of the token (at the expense of compression), contact ThoughtSpot Support.

### Request format

The ABAC request is sent using the `user_parameters` key of the [V2.0 Full Access Token request]({{navprefix}}/restV2-playground?apiResourceId=http%2Fapi-endpoints%2Fauthentication%2Fget-full-access-token).

There are three potential keys within `user_parameters`, each taking an array of objects:

...
"user\_parameters": {
   "runtime\_filters": \[\],
   "parameters" : \[\],
   "runtime\_sorts": \[\]
}

The format for the objects in each section follows the equivalent formats in the Visual Embed SDK for [runtime filters]({{navprefix}}/{{runtime-filters}}), [runtime parameters]({{navprefix}}/{{runtime-parameters}}), or [runtime sorts]({{navprefix}}/{{runtime-sort}}).

There is a `[persist]({{navprefix}}/{{abac-user-parameters-beta}}#persistForUser)` key to be added on each object that takes a boolean `true` or `false`. This determines if the values are persisted at the user level beyond just the token itself, for features such as alerts and subscriptions that run outside a user’s session.

The following is a `user_parameters` section that would be part of the JSON request of the [V2.0 Full Access Token request]({{navprefix}}/restV2-playground?apiResourceId=http%2Fapi-endpoints%2Fauthentication%2Fget-full-access-token):

```JavaScript
"user_parameters": {
   "runtime_filters": [
      {
        "column_name": "Region",
        "operator": "IN",
        "values": ["West", "Southwest"],
        "persist": false
      },
      {
        "column_name": "Product Type",
        "operator": "IN",
        "values": ["Shirts", "Swimwear"],
        "persist": true
      }
    ],
    "parameters": [
      {
        "name": "Secured",
        "values": ["rxzricmwfe87q7bh7jyg"],
        "persist": true
      }
    ]
  }
```

### Apply to specific objects

By default, any specified filter or parameter will bind to **any content** with an exact match for the column or parameter name.

You can choose the filter or parameter to apply only to specific ThoughtSpot objects by including an `objects` section with the following format:

```JavaScript
"runtime_filters": [
   {
     "column_name": "Region",
     "operator": "IN",
     "values": ["West", "Southwest"],
     "persist": false
     "objects": [
         {
           // example of the format
           "type": "{OBJECT_TYPE}",
           "identifier": "{id or name of the object}"
         },
         {
            "type":"LOGICAL_TABLE",
            "identifier": "9bd202f5-d431-44bf-9a07-b4f7be372125"

         }
      ]
]
```

### Token-based override vs. persisting values

When `persist: false` is chosen for an ABAC attribute, it only acts as an **override**, with the values tied only to the specific token.

You can treat the REST API **token request** with any values where `persist: true` as "update user\_parameters" API endpoint, even if you don’t use the token in the response.

Filters and parameters must be **persisted** for them to apply when using [cookie-based trusted authentication]({{navprefix}}/{{trusted-authentication}}#cookie) or scheduled reports.

  
| persist | authentication type | behavior |
| --- | --- | --- |
| 
`false`

 | 

Cookieless Trusted Auth

 | 

Token values override user’s values, without updating user\_parameters

 |
| 

`true`

 | 

Cookieless Trusted Auth

 | 

Token values override, but user\_parameters is also updated by token request

 |
| 

`true`

 | 

Cookie-based Trusted Auth

 | 

Token request updates user\_parameters, token is used by SDK to start a session

 |
| 

`true`

 | 

Discard token after request

 | 

Token request updates user\_parameters

 |

Remember, the successful **request** for a token updates the stored `user_parameters` property of the user, rather than the first use of the token.

Persisting values opens up use cases for ABAC outside of the cookieless Trusted Authentication pattern: even if users authenticate via SAML, OIDC, or go directly into ThoughtSpot via username and password, an administrator can make a token request with `persist: true` to set their stored `user_parameters`.

### Remove persisted values

The syntax to fully remove persisted elements in a user’s `user_parameters` property is to pass an **empty array** for the category.

A request with an empty array affects persisted values despite there being no `persist` key within the request.

The following would clear **all** persisted values of any type:

"user\_parameters": {
   "runtime\_filters": \[\],
   "parameters" : \[\],
   "runtime\_sorts": \[\]
}

## Implement RLS with ABAC via tokens

The ABAC via tokens pattern allows for setting arbitrary filters and overriding the values of existing worksheet parameters. These two capabilities can be combined in a number of ways to create secure and unbreakable RLS.

The current standard best practice pattern for RLS using ABAC via tokens is:

1.  Use parameters for any single-value items, with formulas and filters at the worksheet layer to create the desired filtering clauses on every query
    
2.  Use runtime filters to define any **multi-value** filter conditions on columns (parameters are single-valued)
    
3.  If using runtime filters, pass a **shared secret** to the worksheet as a 'check parameter'. This parameter will be used in a formula/filter combination at the Worksheet level to block unrestricted data access when no filters are set via the token
    
4.  Edit the Worksheet TML, then add `is_hidden: true` to any parameter that will be set via token
    

The ability to set the parameter to `is_hidden: true` allows the flexibility to use as many parameters as desired for any type of formula to be used as a worksheet filter.

### Show all

The way to set a runtime filter to **show all values** is to not send in any runtime filter at all for that column.

Without additional information, it’s impossible to know if the lack of a runtime filter is intentional to indicate a **show all values** condition or if something went wrong—a malformed ABAC token or the user entered into ThoughtSpot without a token at all.

### Check parameter and shared key

To make sure that no data shows when a properly-built token is not used to start the user session, you need to send a **"check parameter"** when using runtime filters.

The **shared secret** is a string value used in both the **token request service** to generate each token, and within the **Worksheet formula** to evaluate the parameter.

If the "check parameter" value from the token does not match the value defined in the Worksheet formula (the **shared secret**), the formula and filter combination blocks any data from showing for the user.

### Build the ABAC token request

The [token request service]({{navprefix}}/{{trusted-auth-token-request-service}}) must have the following to build a token request for ABAC:

1.  The **shared secret** to go into the "check parameter"
    
2.  Runtime filters for defining multi-value conditions on columns
    
3.  Any additional parameters
    

The runtime filters must be built by:

1.  Retrieving user data entitlements
    
2.  Translating entitlements into ThoughSpot runtime filters
    

#### Retrieve entitlements

The value of the ABAC pattern is that you can send different combinations of filters for different types of users.

You can retrieve the attribute names and values from any source: the embedding application’s session details, an entitlement REST API, a query to a different database, etc.

#### Translate entitlements into runtime filters

Runtime filters **match on the name property of a column** as defined in ThoughtSpot, not the column’s name in the underlying database table.

The [token request service]({{navprefix}}/{{trusted-auth-token-request-service}}) **MUST** know the ThoughtSpot column names that will be used for each of the attributes, so you’ll need to coordinate between ThoughtSpot Worksheet designers and the [token request service]({{navprefix}}/{{trusted-auth-token-request-service}}) to make sure the matching column names and values are being sent.

> **IMPORTANT:** End users of an embedded app cannot have edit access to any worksheet using ABAC RLS via tokens. You must follow proper development and deployment practices for all your customer-facing production environments as well as the production token request service.

As mentioned in the preceding section, the format for runtime filters within the token match with [runtime filters]({{navprefix}}/{{runtime-filters}}) in the Visual Embed SDK. In general, RLS entitlements are lists of values using the `IN` operator, but you can pass in filters on numeric and time columns using the full set of operators.

All values are passed into the token as **arrays of strings**, even if the column is a numeric, boolean, or date type in ThoughtSpot and the database. The column data type will be respected in the query issued to the database.

For example, let’s assume three attributes that are needed to filter down a user on a multi-tenanted database: `Customer ID`, `Region`, and `Product Type`.

The following is what the token request would look like if restricting on all three attributes:

```JavaScript
"runtime_filters": [
   {
     "column_name" : "Customer ID",
     "operator": "EQ",
     "values": ["492810"],
     "persist" : true
  },
   {
     "column_name": "Region",
     "operator": "IN",
     "values": ["West", "Southwest"],
     "persist": true
   },
   {
     "column_name": "Product Type",
     "operator": "IN",
     "values": ["Shirts", "Swimwear"],
     "persist": true
   }
 ]
```

A user might be entitled to **all access** on any given column (you might drop some levels of a hierarchy if you include more granular columns to filter on for that user).

> **IMPORTANT:** The process for translating the entitlements request into ThoughtSpot runtime filters must drop the filter definition entirely to represent all access.

The following is a request where a different user can see all `Region`, but still has restrictions on `Customer ID` and `Product Type`:

"runtime\_filters": \[
   {
     "column\_name" : "Customer ID",
     "operator": "EQ",
     "values": \["492810"\],
     "persist" : true
  },
   {
     "column\_name": "Product Type",
     "operator": "IN",
     "values": \["Shirts", "Swimwear"\],
     "persist": true
   }
 \]

Because the `runtime_filters` section is entirely within the control of the **token request service**, you have full flexibility to generate any set of filters for any type of user within the token.

#### Set the 'check parameter' to the shared secret

The **shared secret** is just a long string value that cannot be easily guessed or determined programmatically. You can generate these values randomly and the end user will never see it, only the Worksheet editor if they look at the formula.

Information about how to set up the appropriate set of Worksheet parameters, formulas, and filters for the 'check parameter' to provide security is provided in the following sections.

All that is required within the token request service is that the same **shared secret** defined within the Worksheet formula is being sent with the appropriate 'check parameter' name.

If the parameter is named `Secured` and the **shared secret** value is `rxzricmwfe87q7bh7jyg`, then the `parameters` section of the token request will look like the following snippet:

```JavaScript
"parameters": [
   {
     "name": "Secured",
     "values": ["rxzricmwfe87q7bh7jyg"],
     "persist": true
   }
]
```

### Use Parameters to filter a Worksheet

The basic pattern for using a Parameter to filter a Worksheet includes these steps:

1.  Create [Parameters](https://docs.thoughtspot.com/cloud/latest/parameters-create) in Worksheet
    
2.  Make [formula](https://docs.thoughtspot.com/cloud/latest/formulas) that evaluates the Parameter’s default value and the expected values from the token
    
3.  Make [Worksheet filter](https://docs.thoughtspot.com/cloud/latest/filters#_worksheet_filters) based on the formula, set to **true**.
    

[Parameters](https://docs.thoughtspot.com/cloud/latest/parameters-create) are defined at the Worksheet level within ThoughtSpot. Parameters have a data type and a default value set by the Worksheet author.

To use a Parameter, you’ll make a [formula](https://docs.thoughtspot.com/cloud/latest/formulas) on the Worksheet.

[Worksheet filters](https://docs.thoughtspot.com/cloud/latest/filters#_worksheet_filters) can reference Worksheet formulas once they have been created, which creates the security layer out of the result of the formula.

All of these Worksheet-level features are set by clicking **Edit** on the Worksheet, then expanding the menu on the left sidebar:

![Worksheet Edit Sidebar](/docs/doc-images/images/worksheet_edit_sidebar.png)

#### Define the check parameter

The simplest 'check parameter' pattern is a shared key string that is stored in both the [token request service]({{navprefix}}/{{trusted-auth-token-request-service}}) and the Worksheet formula used for the Worksheet filter.

Parameters are always visible in the UI, even though a parameter set via a token can never be overridden by any action in the UI or using the Visual Embed SDK.

Thus the 'check parameter' and its default value should be named something that looks pleasant to end users. For example, if the parameter name is "Secured", you can set the default value to "✔️" or "true" or "yes" (any Unicode value is allowed, including emojis):

![Check Parameter with Default Value for Display](/docs/doc-images/images/check_parameter_definition.png)

This will display on Liveboards and Answers as shown here:

![Parameter with Default Value on Answer](/docs/doc-images/images/parameter_with_default.png)

#### Create the Worksheet security formula

A Parameter doesn’t do anything on its own. You need a formula to evaluate the Parameter’s value.

Any security formula to be used on a worksheet should result in a **boolean** true or false, and then the worksheet filter will be set to only return data when the formula returns true.

##### Logic for groups to see all data

In any security formula you build, you may want a clause that gives access to all data to certain groups.

You can chain together any number of `if…​then…​else` clauses within a formula, including using the `ts_groups` or `ts_username` values, to build out your preferred logic:

`if ( 'data developers' in ts_groups ) then true else if ( parameter_name = field_name ) then true else false`

##### Check parameter formulas

The simplest formula for a 'check parameter' with shared key looks as follows:

`if ( check_parameter_name = 'shared-key-value') then true else false`

For example, if the 'check parameter' is called `Secured`, and the secret key value is a long-encoded string like `rxzricmwfe87q7bh7jyg`, the Worksheet formula will be as shown in the following figure. Note that the Parameter name is always lower-cased in formulas:

![Security Formula in Worksheet](/docs/doc-images/images/worksheet_formula.png)

##### Formulas comparing a parameter to a column

Parameters can be used in a formula to directly match a value in a column, or any other type of function you’d like to use:

`if ( parameter_name = field_name ) then true else false`

##### Use Parameters with pass-through functions

[ThoughtSpot SQL Pass-through functions](https://docs.thoughtspot.com/cloud/latest/formula-reference#passthrough-functions) allow you to send arbitrary SQL to the data source, while passing in values to substitute from ThoughtSpot.

The basic form of the SQL Pass-through function is:

`sql_passthrough_function("<sql_statement>", <ThoughtSpot variable 1>, <ThoughtSpot variable 2>,…​)`

The list of variables after are substituted into the SQL statement using curly braces in the order listed, starting at 0:

`sql_bool_op ( "tableName.columnName IN ({0}, {1})" , parameterName0, parameterName1)`

If you are referencing a field NOT in ThoughtSpot, perhaps a column that is not part of the JOINed data model or of a complex data type ThoughtSpot does not natively recognize, you need to qualify the column with `tableName.columnName` syntax in your query, so that the SQL is not ambiguous if a similar column name exists on multiple tables.

If you do not get all your data types correct, the ThoughtSpot-generated query will cause errors at the data warehouse level, which you will see in ThoughtSpot.

#### Set a Worksheet filter on the Worksheet security formula

The last step is to set a **Worksheet filter** on the **formula** you just created to evaluate the 'check parameter'.

The last step is to set a **Worksheet filter** on the **formula** you just created to evaluate the 'check parameter'.

1.  Click the Add new icon (+) next to **Filters**.  
    
2.  Click the formula you created (at the end of the list) in the **Filter** dialog.
    
    ![Create New Filter on Worksheet](/docs/doc-images/images/new_worksheet_filter_step_1.png)
    
3.  Click **Add values in bulk**.
    
    ![Choose add values in bulk](/docs/doc-images/images/new_worksheet_filter_step_2.png)
    
4.  Type in the value **true** in the bulk dialog box, and then click **Done**.
    
    ![Type in true in bulk values box](/docs/doc-images/images/new_worksheet_filter_step_3.png)
    
5.  Click **Done** on the Filter dialog.  
    You should see it listed on the **Edit Worksheet** page:
    
    ![Completed Worksheet filter](/docs/doc-images/images/new_worksheet_filter_step_4.png)
    

Now the 'check parameter' will be evaluated all the time, blocking all data unless the appropriate value is passed in via ABAC token.

The last step is to set a **Worksheet filter** on the **formula** you just created to evaluate the 'check parameter'.

1.  Click the Add new icon (+) next to **Filters**.  
    
2.  Click the formula you created (at the end of the list) in the **Filter** dialog.
    
    ![Create New Filter on Worksheet](/docs/doc-images/images/new_worksheet_filter_step_1.png)
    
3.  Click **Add values in bulk**.
    
    ![Choose add values in bulk](/docs/doc-images/images/new_worksheet_filter_step_2.png)
    
4.  Type in the value **true** in the bulk dialog box, and then click **Done**.
    
    ![Type in true in bulk values box](/docs/doc-images/images/new_worksheet_filter_step_3.png)
    
5.  Click **Done** on the Filter dialog.  
    You should see it listed on the **Edit Worksheet** page:
    
    ![Completed Worksheet filter](/docs/doc-images/images/new_worksheet_filter_step_4.png)
    

## Indexing

Several features within ThoughtSpot, such as autocompletion in Search on values within columns or the suggestions in Explore, use ThoughtSpot indexing.

Due to the runtime nature of ABAC via tokens, ThoughtSpot indexing will not be restricted by the values supplied in a token.

You must turn off indexing for any field that needs to be restricted by RLS when using ABAC via tokens for RLS.

## Known limitations

-   Schedules created with JWT using ABAC will not follow the same security rules as schedules created with standard RLS set up in ThoughtSpot.  
    Schedules created by users in a session secured via RLS using ABAC currently do not follow any data security rules, that is, all data will be shown in schedules. ThoughtSpot recommends removing the ability to create schedules for your end users. The improvements in the upcoming versions include:
    
    1.  The security rules applied to the schedule will be those of the schedule creator
        
    2.  Using `persist:true` in the JWT for security rules will ensure that the schedule is run using the filter rules persisted on the user.
        
    
-   Runtime filter conditions must match the column names in your worksheet to avoid data leakage.
    
    The `runtime_filters` must include the exact ThoughtSpot worksheet column name, or they will not apply to the data set. If a worksheet is changed, you must coordinate between the team that maintains it and the team that builds the token request service, or the filters will no longer be applied. For the same reasons, the end users of an embedded app cannot have edit access to any worksheet using ABAC RLS via tokens.  
    
    Currently, the ABAC via tokens method requires using trusted authentication and using Worksheets as data sources for Liveboards and Answers, rather than individual Table objects. You can pass in runtime filters and Parameters for a user via their login token. Both features work like the runtime filters and Parameters available within the Visual Embed SDK, but values set via token cannot be overridden by any user action within the ThoughtSpot UI.