app.get('/ts-token',(req,res) => {
// req.session will be set by another endpoint handling login into the web application
session=req.session;
// secret_key must be stored securely; here we assume the ThoughtSpot server name and secret_key are stored in env file
let thoughtspot_url = process.env.TS_SERVER_URI;
let thoughtspot_secret_key = process.env.TS_SECRET_KEY;
// Short-time out for cookie-based login; make longer for cookieless
const timeoutInSec = 60;
// Assuming 'user_email' is the session value that matches the username in ThoughtSpot
if (session.user_email) {
let tsTokenUrl = thoughtspot_url + "api/rest/2.0/auth/token/full";
let tsTokenBody = {
"username": session.user_email,
"org_id" : 0, // May need to make a variable, if customers are on different orgs
"validity_time_in_sec": timeoutInSec,
"auto_create": false,
"secret_key": thoughtspot_secret_key
};
// using Fetch to make HTTP request; you may use other package
const response = await fetch(tsTokenUrl, {
method: 'POST',
body: JSON.stringify(tsTokenBody),
headers: { Accept: "application/json",
"X-Requested-By": "ThoughtSpot",
"Content-Type": "application/json"
}
});
const results = await response.json();
res.send(results.token);
}
else{
res.send('No user session exists');
}
})
Token request service
Overview๐
The token request service is the portion of the web application with access to the ThoughtSpot secret_key
that issues the request to ThoughtSpot to generate tokens.
In most cases, the token request service is a REST API endpoint added to the web application. Providing a REST API service allows the Visual Embed SDK to request new tokens whenever they are needed to start a new ThoughtSpot session.
The init()
function calls the token request service endpoint, which returns the token to the web browser, triggering the Visual Embed SDK to handle the rest of the login flow. The token request can instead happen on the back-end of the web app and the token can be embedded into the returned web page directly, but this will require a page reload if there is a need for a new token.
There are no requirements for how the token request service is built or hosted, other than being able to issue REST API commands to the ThoughtSpot instance and having access to the secret_key
. When using a ThoughtSpot cloud instance, the authenticator service will need outbound request access to the hosted ThoughtSpot cloud instance.
Trusted authentication tokens can be requested in a way that creates users and assigns them at the time of login. Please see the full documentation of just-in-time provisioning for implementation details.
Quick code example๐
Every web application framework has its own way of handling users, sessions, and making REST API requests to other services.
The following example shows how a token request service might look in Node.js with Express and the express-session
package used to manage a session in the embedding web application.
Store the secret key๐
The secret_key
allows a REST API request for a login token for any username, without any additional authentication to the ThoughtSpot cluster.
This means the secret_key
must be stored by the token request service securely and never revealed to the user in their browser. How you store the secret_key
so that the token request service has access will depend on your web application backend.
Any examples you may find using the secret_key
from a front-end page are purely for testing only.
ThoughtSpot generates a new secret_key
when trusted authentication is enabled on a ThoughtSpot instance. See the secret_key documentation for more details.
Authenticate the user๐
The token request service must access the authentication details of the web application logged-in user (at minimum, the ThoughtSpot username value), and then use those values in the subsequent REST API requests to ThoughtSpot.
Authentication details are often accessed from:
-
Web applicationโs user session
-
JWT token included in the request
-
LDAP or AD details
If your token request service must also create users and give them access, additional authentication details must be accessed:
-
user email address
-
user display name
-
ThoughtSpot group names to add a user to
-
Org ID to which the user belongs
User password is not required in the login token request when using the secret_key
.
ThoughtSpot user account passwords are neither checked nor modified by any single sign-on method.
Login token REST API requests๐
If you are using ThoughtSpot Cloud, the best practice is to use V2 REST API Full Access Tokens.
Access control in ThoughtSpot (called Sharing) prohibits a signed-in user from loading any content to which they donโt have access. Access control (sharing) can be granted during the login token request process by adding the user to the appropriate ThoughtSpot groups.
Tokens obtained via REST API v2 endpoints tokens can be used for cookie-based or cookieless trusted authentication. REST API v1 login tokens only work for cookie-based trusted authentication.
The /session/token/login
REST API v1 endpoint used by the Visual Embed SDK can accept the token obtained via REST API v1 or v2 endpoint to establish a ThoughtSpot session.
If you are on an older software release, please use the features that are available in your deployed release.
V2 REST API๐
The REST API v2 has separate endpoints for requesting full access or object access tokens. The vast majority of implementations use a full access token obtained via /api/rest/2.0/auth/token/full
API endpoint.
The quick code example above shows how the REST API v2 full access token request would be implemented within a token request service.
REST API v1 token requests๐
The REST API v1 tokens are requested from the /tspublic/v1/session/login/token endpoint.
When a token has been requested in FULL
mode, it will create a full ThoughtSpot session in the browser and application. The token for FULL
access mode persists through several sessions and stays valid until another token is generated.
You can request a limited token using the access_level=REPORT_BOOK_VIEW
option in REST API v1 but this is rarely used and not recommended.
Login token expiration๐
Login tokens obtained from the V1 and V2 REST APIs have different expiration rules.
V2 token๐
The V2 REST API token is a standard OAuth 2.0 token that encodes several properties within the token, most notably the username and the expiration time.
The validity time of the token is never extended by any activity, so a new token must be requested after the initial token passes its expiration time. The Visual Embed SDK can be configured to handle this automatically.
The V2 token REST API endpoint has a request argument called validity_time_in_sec
that defaults to 300 seconds (5 minutes).
For cookie-based trusted authentication, you may want to shorten the validity_time_in_sec
to less than one minute, since the token is only used once and then there is a long-lived cookie-based session. The ThoughtSpot session end time will extend naturally as the user interacts with ThoughtSpot.
For cookieless trusted authentication, you will want to request the token with a longer validity, possibly 20 or 30 minutes, or more.
V1 token๐
The V1 REST API login token is a proprietary token format that cannot be decoded or used for any purpose other than to create a ThoughtSpot session.
V1 tokens stay valid for a length of time based on the following rules:
-
A token stays valid indefinitely until another token for any user is generated.
-
When a new token is generated using the same
secret_key
, the previous token will expire after five minutes. -
When a new
secret_key
is generated for the ThoughtSpot server, and the first new login token is obtained using the newsecret_key
, all tokens generated using the previoussecret_key
become invalid. -
If users make multiple attempts to log in to ThoughtSpot using an invalid or expired token, they may get locked out of their accounts.
To set a consistent five-minute expiration time, you can generate a second token to start the expiration clock for the previous login token that is sent to the userโs browser.
Org-enabled clusters๐
On multi-tenant clusters with Orgs enabled, tokens are scoped to one given Org at a time. The token request service will also need to be aware of the org_id
of the matching ThoughtSpot org for a given user at token request time.
Revoking a token๐
There is a REST API for revoking a V2 Token, which could be incorporated into an additional endpoint of the token request service if you have concerns about the longer-lived tokens existing beyond the web applicationโs session lifespan.
For example, the sign-out process of the web application could call the token request service to revoke the previously requested token.
Code examples๐
The following two examples are for testing purposes only. They establish token request services using all REST API calls correctly, but allow an arbitrary request for a token for any user from the browser.
Feel free to use these examples to start your implementations, but please remove the ability to request any token for any user when building your production version.
-
A simple Python Flask implementation of an Authenticator Service is available in the ts_everywhere_resources GitHub repository.
-
A fully functioning Node.js example using Axios and Express: https://github.com/thoughtspot/node-token-auth-server-example
The following is a C# example of the ThoughtSpot token request, to be used within a REST API service in the .Net platform, storing the secret_key
in Azure Key Vault:
using System.Net.Http;
using System.Text.Json;
using System.Text.Json.Serialization;
// For Azure Key Vault
using Microsoft.Azure.Services.AppAuthentication;
// This example does not include any of the .Net / ASP REST API code
// but simply defines the Request and Response classes necessary for Full Token Request
public class TSFullTokenRequest
{
public string username {get; set;}
public string? password {get; set;}
public string? secret_key {get; set;}
public int validity_time_in_sec {get; set;}
public int? org_id {get; set;}
public string? display_name {get; set;}
public bool? auto_create {get; set;}
}
public class TSTokenScope {
public string access_type {get; set;}
public int org_id {get; set;}
public string? metadata_id {get; set;}
}
public class TSFullTokenResponse
{
public string token {get; set;}
public int creation_time_in_millis {get; set;}
public int expiration_time_in_milis {get; set;}
public TSTokenScope scope {get; set;}
public string valid_for_user_id {get; set;}
public string valid_for_username {get; set;}
}
public static httpClient = new HttpClient();
var tsHost = 'https://{}.thoughtspot.cloud';
var tsTokenEndpoint = '/api/rest/2.0/auth/token/full';
var fullEndpoint = tsHost + tsTokenEndpoint;
// secret_key stored in the Azure Key Valut
var azureServiceTokenProvider = new AzureServiceTokenProvider();
KeyVaultClient kvc = new KeyVaultClient(azureServiceTokenProvider.KeyVaultTokenCallback);
SecretBundle tsSecretKey = kvc.GetSecretAsync(baseUrl, "tsSecretKey").Result;
TSFullTokenRequest tsTokenRequest = new (){
username = 'usernameFromAuthMiddleware',
secret_key = tsSecretKey.Value,
validity_time_in_sec = 30
};
// Ignore any null properties when serializing
JsonSerializerOptions options = new()
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
};
string jsonString = JsonSerializer.Serialize<TSFullTokenRequest>(tsTokenRequest, options);
var response = await httpClient.PostAsync(fullEndpoint, jsonString);
if (response.IsSuccessStatusCode)
{
string responseContent = await response.Content.ReadAsStringAsync();
TSFullTokenResponse tsTokenResp = JsonSerializer.Deserialize(responseContent, TSFullTokenResponse, options);
string token = tsTokenResp.token;
// Return token string from the API endpoint
}
else
{
// handle error, return error from the API endpoint
}
Implement token login without the Visual Embed SDK๐
The Visual Embed SDK handles the final REST API request to create the session, but it is possible to perform the login using /session/login/token or the REST API v2.0 token access endpoints. For more information, see REST API v1 authentication and REST API v2.0 authentication.
Note
|
The REST API v1 |