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 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 to use encrypted JWT also add:
SeekTable_ST__PublicReport__AuthJwt__TokenDecryptionKeyString=your_secret_decryption_key_min_16_chars
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:
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,value3
Parameter["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:
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
to apply
any custom CSS class to app's page <body>
tag - in this way it is possible to apply CSS styles that are specific for this concrete embedding (you can add your own custom app's CSS styles).
Also you can use a predefined CSS class no-left-menu
(useful if you want to show only a concrete report and do not allow end-users to navigate to another reports).