curl -X POST \
--url 'https://{ThoughtSpot-Host}/api/rest/2.0/auth/token/custom' \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
--data-raw '{
"username": "secured_user",
"secret_key": "{secret_key}",
"persist_option": "REPLACE",
"filter_rules": [
{
"column_name": "Country",
"operator": "IN",
"values": ["Germany", "Australia"]
}
]
}'
ABAC JWT migration guide
Administrators can migrate their existing implementation of ABAC with JSON Web Token (JWT) to the new ABAC via RLS model, where:
-
Row-level security (RLS) rules are defined in ThoughtSpot on tables and data models
-
JWTs only provide values for variables used in those RLS rules, instead of sending full filter rules.
Supported migration pathsπ
Important notes and considerationsπ
Review the information in the following sections before getting started with the migration.
ABAC feature supportπ
The legacy JWT ABAC implementation is deprecated and will be removed from the product in an upcoming version. The ABAC beta implementation is no longer supported in ThoughtSpot. ThoughtSpot strongly recommends using ABAC via RLS in all new implementations and migrating your existing legacy or beta JWT ABAC implementation to ABAC via RLS.
Persistence behaviorπ
ABAC via RLS does not support session-based ABAC rules ("persist_option": "NONE"). If your implementation currently relies on session-based rules:
-
Create dedicated user accounts for your application users. You can use REST APIs to automate user creation, update, or deletion.
-
Apply persisted security rules to those users.
-
Use cookieless authentication with these persisted users.
This approach addresses all use cases that previously relied on session-based JWT and ensures Liveboard schedule attachments enforce security rules and deliver only secured output to your end users.
Table joinsπ
The filters in JWT ABAC beta implementation respect MODEL JOINS. However, RLS by default is an INNER join. If you want to adjust behavior for your implementation, contact ThoughtSpot Support.
From legacy JWT ABAC with filter_rules to ABAC via RLSπ
Before migrating to the new method, complete the following checks:
-
Analyze your current JWT ABAC implementation.
-
Configure equivalent RLS rules using variables.
-
Implement and test RLS-based ABAC in a non-production environment.
-
Adjust your JWT payloads to set variable values instead of
filter_rules. -
Roll out and decommission legacy JWT ABAC.
Analyze your current implementationπ
In a typical legacy JWT ABAC implementation:
-
The
/api/rest/2.0/auth/token/customendpoint is used for JWT generation, populatingfilter_rulesorparameter_valuesin the token to create data security rules. Depending on user requirements, these values are applied on all models or specific models as per the object scope set in the request payload. -
The
is_mandatory_token_filterattribute is set totrueon columns in Models to secure them by default.
-
Indexing on all sensitive columns in your Tables is disabled.
Retrieve values from user properties (Optional)π
If required, you can retrieve the filter and parameter values stored for each JWT user from the user metadata via a POST request to the /api/rest/2.0/users/search API endpoint. The access_control_properties section of user metadata returned in the API response includes this information:
[{
"id": "0000084b-1e75-d506-8258-0b6abbb863ed",
"name": "testjwtuser",
"display_name": "testjwtuser",
[...]
"access_control_properties": {
"<org_id>": {
"ALL": {
"filter_rules": [{
"column_name": "country",
"operator": "IN",
"values": ["Germany", "Australia"]
}],
"parameter_values": []
}
}
},
"variable_values": {}
}]
Configure equivalent RLS rules and variablesπ
You may want to set up RLS rules and variables equivalent to filter and parameter rules in your existing implementation. Note that the following mapping pattern applies to each attribute:
-
Column in
filter_rulesβ RLS rule condition with formula variable on that column. -
Values in
filter_rulesβ variable values passed via JWT. -
is_mandatory_token_filterbehavior β RLS rule that denies all when variable is empty or missing. -
TS_WILDCARD_ALLor similar βallow allβ semantics β variable valueTS_WILDCARD_ALLin the RLS rule.
To set equivalent RLS rule conditions and variables:
-
Create formula variables using the /api/rest/2.0/template/variables/create API endpoint. These variables will be referenced in RLS rules. To create variables, you need
ADMINISTRATION(Can administer ThoughtSpot) privilege. If role-based access control (RBAC) is enabled on your instance, theCAN_MANAGE_VARIABLES(Can manage variables) privilege is required. -
Create rules using these variable(s) directly on the ThoughtSpot table in the Row Security Editor tab. These should be the same rules as the ones previously defined in the JWT, which will be ultimately replaced after migration. To add multiple conditions, use the
ANDoperator.
-
Create a JWT token request with
variable_valuesand generate the token using the/api/rest/2.0/auth/token/customAPI endpoint. Note that these values can be scoped to specific models, so that different security rules can be applied to different data in ThoughtSpot.curl -X POST \ --url 'https://{ThoughtSpot-Host}/api/rest/2.0/auth/token/custom' \ -H 'Accept: application/json' \ -H 'Content-Type: application/json' \ --data-raw '{ "username": "secured_user", "secret_key": "{secret_key}", "persist_option": "REPLACE", "variable_values": [ { "name": "country_rls_var", "values": [ "Germany", "Australia" ] }, { "name": "category_rls_var", "values": [ "Jeans", "Jackets" ] } ], "objects": [ { "type": "LOGICAL_TABLE", "identifier": "cd252e5c-b552-49a8-821d-3eadaa049cca" }, { "type": "LOGICAL_TABLE", "identifier": "38399c50-02f1-4310-804b-214b81f25333" } ]}' -
Keep indexing disabled on all sensitive columns
NoteUsers with administration and Can Administer and Bypass RLS privileges are exempt from RLS rules and can view all rows unless additional logic is implemented to secure rows in the data model. RLS rules are defined on tables, but Models can be configured to either apply or bypass those rules. For more information, see How RLS rules work. -
Verify variable values are assigned to your users. This information can be retrieved using one of the following methods:
-
Via a
POSTrequest to the/api/rest/2.0/users/searchAPI endpoint. Verify thevariable_valuessection of the user metadata returned in the API response. -
Via a
POSTrequest to the/api/rest/2.0/template/variables/searchAPI endpoint, with variables specified in the request body. Setresponse_contenttoMETADATA_AND_VALUESto fetch the variable values and verify the response payload.NoteWe do not recommend using the
/api/rest/2.0/users/{user_identifier}/updateendpoint to update variable values for a user. Instead, use either/api/rest/2.0/template/variables/update-valuesor/api/rest/2.0/auth/token/custom.
-
Expected setup before the testing phaseπ
Ensure that you have both legacy JWT GA and ABAC via RLS properly set up in your environment before starting the tests. For testing purposes, weβll use an example setup with filter_rules, the mandatory token filter setting in the model, and RLS rules with country_rls_var and category_rls_var variables.
Your implementation can also include parameters to configure security rules by using pass-through functions. Typically, users may want to map existing security rules, such as those created with filter_rules or parameter values used in model formulas and model filters, to new RLS rules that reference variables and are applied at the table level.
Test the migrationπ
We recommend testing the migration in these main steps:
-
Ensure everything continues to work correctly when both legacy JWT GA and ABAC via RLS are enabled.
-
Remove filter conditions on legacy JWT ABAC implementation to test how security rules function with solely ABAC via RLS.
-
Remove legacy JWT GA, and retain only ABAC via RLS.
|
Important
|
When creating a token request with |
Legacy rulesπ
The legacy parameters, filter_rules and parameter_values, are linked. If you define one without including the other in the API request, the omitted parameter will be deleted from the user profile. This behavior remains unchanged with the introduction of variable_values to maintain backward compatibility.
Migration to variable_valuesπ
The variable_values parameter in the ABAC via RLS implementation operates independently.
Sending variable_values alone will not erase your legacy rules. Likewise, sending legacy parameters without variable_values will not erase stored variable values.
This allows developers to assign variable_values for ABAC via RLS without disrupting an existing legacy JWT GA setup. To reset all legacy values from users' metadata, use "persist_option": "RESET".
Summary matrixπ
Use the information in the following table to understand how API calls change the userβs stored security settings and variable store settings:
| Your payload includesβ¦β | filter_rules in userβs access_control_properties | parameter_values in userβs access_control_properties | variable_values in the variable store |
|---|---|---|---|
Legacy requests | |||
Both | Updates | Updates | Unchanged |
Only | Updates | DELETED | Unchanged |
Only | DELETED | Updates | Unchanged |
Migration calls | |||
| Updates | DELETED | Updates |
| DELETED | Updates | Updates |
| Updates | Updates | Updates |
ABAC via RLS only | |||
Only | Unchanged | Unchanged | Updates |
Phase 1: Test RLS while legacy JWT configuration is still enabledπ
Generate tokens that include both:
-
Your existing legacy JWT ABAC keys (
filter_rulesand/orparameter_values) -
New
variable_valuesfor your RLS rules
For example:
curl -X POST \
--url 'https://{ThoughtSpot-Host}/api/rest/2.0/auth/token/custom' \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
--data-raw '{
"username": "secured_user",
"secret_key": "{secret_key}",
"persist_option": "REPLACE",
"filter_rules": [
{
"column_name": "Country",
"operator": "IN",
"values": ["Germany", "Australia"]
}
],
"variable_values": [
{
"name": "country_rls_var",
"values": [
"Germany",
"Australia"
]
}
]
}'
Since both conditions are similar, the data should be filtered uniformly as shown in the following diagram. If the filtering conditions differ, the resulting data should be the intersection of the two.

Phase 2: Bypass legacy JWT configurationπ
If the phase 1 testing is conclusive, bypass legacy JWT configuration. To test RLS independently while keeping legacy JWT configuration as a fallback:
-
When generating tokens, set the legacy JWT ABAC implementation to allow everything by using the keyword
TS_WILDCARD_ALLin your legacyfilter_rulesandparameter_values. -
Keep sending
variable_valuesfor the RLS rules as before.
For example:
curl -X POST \
--url 'https://{ThoughtSpot-Host}/api/rest/2.0/auth/token/custom' \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
--data-raw '{
"username": "secured_user",
"secret_key": "{secret_key}",
"persist_option": "REPLACE",
"filter_rules": [
{
"column_name": "Country",
"operator": "IN",
"values": ["TS_WILDCARD_ALL"]
}
],
"variable_values": [
{
"name": "country_rls_var",
"values": [
"Germany",
"Australia"
]
}
]
}'
After this configuration, all filtering is governed by the variable rules set for ABAC via RLS, since legacy JWT implementation with filter_rules allows all values.

Phase 3: Remove all legacy JWT rulesπ
After the legacy JWT configuration values are set to allow all values for that user, subsequent calls can be made without setting the legacy JWT ABAC values. This allows you to test the payload with variable_values, which you ultimately will be using to generate authentication tokens in the future.
For example:
curl -X POST \
--url 'https://{ThoughtSpot-Host}/api/rest/2.0/auth/token/custom' \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
--data-raw '{
"username": "secured_user",
"secret_key": "{secret_key}",
"persist_option": "APPEND",
"variable_values": [
{
"name": "country_rls_var",
"values": [
"Germany",
"Australia"
]
}
]
}'
For those users:
-
Legacy JWT ABAC GA rules are no longer in effect.
-
Their access is governed solely by ABAC via RLS.
-
This payload should match what you plan to use in production.

Examples for mapping legacy JWT ABAC GA expressions to ABAC via RLSπ
A few examples of how to translate legacy JWT expressions into equivalent RLS rules are listed here. These examples assume the following:
-
Your setup has a variable named
country_rls_var. -
RLS expressions use
ts_var(country_rls_var)to reference the value passed viavariable_values.
| Operator | Legacy JWT ABAC implementation | Equivalent values in RLS rules in table for ABAC via RLS |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
Note
|
RLS rules support multi-value variables; use appropriate functions or operators in the RLS expression depending on how you want to handle lists. |
From JWT ABAC Beta implementation to ABAC via RLSπ
In this migration scenario, the JWT ABAC beta implementation will be migrated to ABAC via RLS.
Scope and prerequisitesπ
This document assumes that you are currently using the /api/rest/2.0/auth/token/full or /api/rest/2.0/auth/token/object for ABAC token generation, and provides instructions to migrate your ABAC implementation to the /api/rest/2.0/auth/token/custom API endpoint. These migration steps apply only if:
-
Your implementation has used the legacy method of generating JWT tokens via
/api/rest/2.0/auth/token/fullor/api/rest/2.0/auth/token/objectAPI endpoint. -
Your instance has the necessary configuration settings enabled for migrating JWT token generation process from the
/api/rest/2.0/auth/token/fullto the/api/rest/2.0/auth/token/customAPI endpoint. For more information, refer to the JWT ABAC beta migration guide.
|
Important
|
The legacy JWT ABAC beta implementation is deprecated and is no longer supported in ThoughtSpot. |
Review your legacy JWT ABAC Beta implementationπ
A typical JWT ABAC Beta implementation includes the following:
-
JWT generation via
POST /api/rest/2.0/auth/token/full, withruntime_filtersand other attributes populated for creating data security rules. Depending on user requirements, the values are set on all models or for specific models.curl -X POST \ --url 'https://{ThoughtSpot-Host}/api/rest/2.0/auth/token/full' \ -H 'Accept: application/json' \ -H 'Content-Type: application/json' \ --data-raw '{ "username": "secured_user", "secret_key": "{secret_key}", "user_parameters": { "runtime_filters": [ { "column_name": "Country", "operator": "IN", "values": ["Germany", "Australia"], "persist": true } ], "parameters": [ { "name": "Secured", "values": ["f65fee3a-75f4-4e6e-a801-995113566d68"], "persist": true } ], } }'
You may also be using a parameter property to pass a validation in the data model and ensure that the model is secured by default, as shown in the following token request example:

Ensure that indexing is disabled on all sensitive columns in your tables.
Retrieve values stored for each user (Optional)π
If required, you can retrieve the values previously stored for each user after token generation. To do so, get user metadata via the /api/rest/2.0/users/search API endpoint. The response from this call provides a list of filter and variable values in the user_parameters section of the output.
For example:
[{
"id": "0000084b-1e75-d506-8258-0b6abbb863ed",
"name": "testjwtuser",
"display_name": "testjwtuser",
[...]
"user_parameters": {
"<org_id>": {
"runtimeFilters": [{
"columnName": "Country",
"operator": "IN",
"values": ["Germany", "Australia"]
}],
}
},
"variable_values": {}
}]
This can be helpful when you design equivalent ABAC via RLS rules and want to validate that the same logic will be enforced.
Set up ABAC via RLSπ
Configure ABAC via RLS while keeping the legacy Beta JWT ABAC in place.
-
Create variables, with their type as
FORMULA_VARIABLEusing the/api/rest/2.0/template/variables/createAPI endpoint. These variables will be referenced in your RLS security rules. -
Create RLS rules on tables and reference these variables in the rules.

-
Where applicable, replicate your existing JWT ABAC Beta logic. To add more than one condition, you can use the
ANDoperator. -
To assign values to these variables, define the
variable_valuesin your token generation request to/api/rest/2.0/auth/token/customAPI endpoint. These attributes will ultimately replace conditions defined viaruntime_filtersin your current JWT ABAC beta implementation.NoteThe variable values can be scoped to specific models, so that different security rules can be applied to different data sets in ThoughtSpot.
curl -X POST \ --url 'https://{ThoughtSpot-Host}/api/rest/2.0/auth/token/custom' \ -H 'Accept: application/json' \ -H 'Content-Type: application/json' \ --data-raw '{ "username": "secured_user", "secret_key": "{secret_key}", "persist_option": "REPLACE", "variable_values": [ { "name": "country_rls_var", "values": [ "Germany", "Australia" ] }, { "name": "category_rls_var", "values": [ "Jeans", "Jackets" ] } ], "objects": [ { "type": "LOGICAL_TABLE", "identifier": "model1-guid" }, { "type": "LOGICAL_TABLE", "identifier": "model2-guid" } ] }' -
Keep indexing disabled on all sensitive columns.
|
Note
|
|
Verify variable values for users (Optional)π
Verify that variable values are correctly assigned to users using one of the following methods:
-
Send a
POSTrequest to the/api/rest/2.0/users/searchwith user details, and explore thevariable_valuessection of the response payload. -
Send a
POSTrequest to the/api/rest/2.0/template/variables/searchAPI endpoint with variable details. In the request body, specify theresponse_contentasMETADATA_AND_VALUES, and explore the variable values for each user in the response payload.
If you want to update variables, use either /api/rest/2.0/template/variables/update-values or /api/rest/2.0/auth/token/custom API endpoint.