You can embed SeekTable reports into your web application in a secure way by enabling JWT-based authentication for published reports or read-only app view. Secure embedding is available only for self-hosted SeekTable (or managed instance) and only for user accounts with Advanced Publishing subscription. How it works:
|
Your web app
Generates secure JSON Web Token |
→
|
Secure report link
JWT is passed to SeekTable report as an URL parameter or cookie |
→
|
SeekTable
Decodes/verifies JWT and applies claims as report parameters. |
JWT lifetime can be is limited by its expiration date. JWT claims (payload) may be contain report parameters and in this way you can organize row-level security for embedded reports (without SSO): each 'main' app user may have its own set of parameters that restrict access to the data. Users cannot change these parameters because their JWT tokens are signed with a secret key. JWT tokens may be encrypted with symmetric algorithm, and in this case even values of parameters passed in JWT are secured (cannot be accessed by end-users).
If you want to evaluate this feature before purchase you can request a free 14-day trial.
How to enable JWT-based auth for embedded SeekTable views:
Find docker-compose.seektable.env file and add the following lines:
SeekTable_ST__PublicReport__AuthJwtUrlParameter=auth SeekTable_ST__PublicReport__AuthJwtCookieName=cookie_name_or_empty_if_not_used SeekTable_ST__PublicReport__AuthJwt__ValidIssuer=your_web_app_issuer_value SeekTable_ST__PublicReport__AuthJwt__ValidateIssuer=true SeekTable_ST__PublicReport__AuthJwt__ValidateAudience=false SeekTable_ST__PublicReport__AuthJwt__ValidateLifetime=true SeekTable_ST__PublicReport__AuthJwt__ValidateIssuerSigningKey=true SeekTable_ST__PublicReport__AuthJwt__IssuerSigningKeyString=your_secret_signing_key_min_16_chars
If you want enable JWT encryption add:
SeekTable_ST__PublicReport__AuthJwt__TokenDecryptionKeyString=your_secret_decryption_key_min_16_chars
If you want enable generate embed token API add:
SeekTable_ST__PublicReport__EnableGenerateEmbedToken=true
Then re-create seektable/seektable docker container (this is performed automatically if you use docker compose up to start the containers).
Now you should see Security tab on "Configure Published Report" form:
You can either use generate embed token API to obtain JWT or generate JWT on your application side (recommended).
The following code snippets illustrate how to generate JSON Web Token for embeds:
// nuget package: System.IdentityModel.Tokens.Jwt
var handler = new JwtSecurityTokenHandler();
var signingCredentials = new SigningCredentials(
new SymmetricSecurityKey(System.Text.Encoding.UTF8.GetBytes("your_secret_signing_key_min_16_chars")),
SecurityAlgorithms.HmacSha256Signature);
var token = handler.CreateJwtSecurityToken(
subject: new ClaimsIdentity(new[] { new Claim("report_param_name", "report_param_val") }),
signingCredentials: signingCredentials,
audience: "",
issuer: "your_web_app_issuer_value",
expires: DateTime.UtcNow.AddMinutes(5)); // 5 mins expiration
var jwt = handler.WriteToken(token);
// nuget package: System.IdentityModel.Tokens.Jwt
var handler = new JwtSecurityTokenHandler();
var signingCredentials = new SigningCredentials(
new SymmetricSecurityKey(System.Text.Encoding.UTF8.GetBytes("your_secret_signing_key_min_16_chars")),
SecurityAlgorithms.HmacSha256Signature);
var encryptCredentials = new EncryptingCredentials(
new SymmetricSecurityKey(System.Text.Encoding.UTF8.GetBytes("your_secret_decryption_key_min_16_chars")),
SecurityAlgorithms.Aes128KW,
SecurityAlgorithms.Aes128CbcHmacSha256);
var tokenDescriptor = new SecurityTokenDescriptor {
Audience = "",
Issuer = "your_web_app_issuer_value",
Subject = new ClaimsIdentity(new[] { new Claim("report_param_name", "report_param_val") }),
Expires = DateTime.UtcNow.AddMinutes(5), // 5 mins expiration
EncryptingCredentials = encryptCredentials,
SigningCredentials = signingCredentials
};
var encryptedJwt = handler.CreateEncodedJwt(tokenDescriptor);
// module: jsonwebtoken
var jwt = require("jsonwebtoken");
var expiresInMins = 5;
var payload = {
report_param_name: "report_param_value",
iss: "your_web_app_issuer_value",
exp: Math.round(Date.now() / 1000) + (expiresInMins * 60)
};
var token = jwt.sign(payload, "your_secret_signing_key_min_16_chars");
# package: PyJWT
import jwt
import time
payload = {
"report_param_name": "report_param_value",
"iss": "your_web_app_issuer_value",
"exp": round(time.time()) + (60 * 5) # 5 mins expiration
}
token = jwt.encode(payload, "your_secret_signing_key_min_16_chars", algorithm="HS256")
require_once "./vendor/firebase-php-jwt/JWT.php";
use \Firebase\JWT\JWT;
$jwtSigningKeyStr = "your_secret_signing_key_min_16_chars";
$jwtIssuer = "your_web_app_issuer_value";
$payload = [
"report_param_name" => "report_param_value",
"iss" => $jwtIssuer,
"exp" => strtotime("+5 minutes")
];
$token = JWT::encode($payload, $jwtSigningKeyStr);
How to pass a multivalue parameter?
On SeekTable side JWT payload claim values are mapped to System.Security.Claims.Claim objects where Value is always converted to a string.
As a result, it is not possible to provide multiple values simply by specifying a JSON array as a claim value. To overcome this limitation the following workaround may be used:
value,value2,value3Parameter["param_name"]!=null && Parameter["param_name"].Length==1 && Parameter["param_name"][0].ToString().Contains(",") ? String.Split(",", Parameter["param_name"][0]) : Parameter["param_name"]
If you don't use C#/.NET please check your development platform about how to generate JSON Web Token. Notes:
There are 2 ways how you can pass generated JWT to the report embedded with IFRAME:
SeekTable_ST__PublicReport__AuthJwtUrlParameter setting)SeekTable_ST__PublicReport__AuthJwtCookieName)Important notes:
You can generate a scoped JWT to grant access to only the concrete report or dashboard. To do that add
seektable_report_id into JWT payload, for example (C#):
new Claim("seektable_report_id", "public_link_id")
If you want to offer to users of your app a higher level of reports interactivity and allow them to make ad-hoc queries you can embed SeekTable's "app" view (read-only access to some user account) - to get the point just imagine that whole demo.seektable.com view is embedded (without top-menu):
Technically this works in this way:
seektable_user_email with a login email of 'embedded' SeekTable user account.
This JWT may contain additional name-value pairs to override appropriate report parameters (end-users will not be able to change these report parameters).
auth) or a cookie.
This URL can be just a base URL (to show default account's screen with list of cubes) or this may be an URL of the concrete report.
seektable_user_readonly = false into JWT's payload.
seektable_app_page_css_class claim to apply
any custom CSS class to app's page <body> tag: in this way CSS styles can be customized only for this concrete embedding (you can add your own custom app's CSS styles).
seektable_user_theme JWT claim (possible values are: "light", "dark" and "auto").