Implement JWT Authorization
JWT solutions leverage cookies for auth, which are blocked by some browser vendors. If you can’t use OAuth2 impersonation in your solution, you may need to use a JWT proxy.
Overview
In this tutorial, you are going to learn how to configure a web application to create a JWT token and send it to Qlik Cloud to authorize a user to view embedded content from a Qlik Sense application.
This tutorial focuses on the authorization flow for working with JWTs and Qlik Cloud. While it demonstrates the process through coded examples in JavaScript, it is not plug-and-play code.
Before you begin
-
Only a user with the
Tenant Admin
role may access the management console settings and configure JWT identity provider settings. If you aren’t theTenant Admin
of your Qlik Cloud tenant, contact yourTenant Admin
and direct them to this tutorial. -
Complete the JWT identity provider configuration in your Qlik Cloud tenant before continuing this tutorial. You may learn how to configure your tenant to use JWT authorization here.
-
This tutorial is based upon an example custom web application written with node.js. This tutorial does not provide instructions on how to adapt this code to your own custom web application. The intent of the tutorial is explain the authentication flow required to use JWT authorization capabilities with Qlik Cloud. The example code referenced in this tutorial is available as a live example on glitch.com.
-
Make sure to have the following information at the ready before completing this tutorial:
- The
keyid
value for the JWT identity provider configuration - The
issuer
value for the JWT identity provider configuration - A copy of the private key used for signing JWTs sent to Qlik Cloud. This private key pairs with the public key used for configuring the JWT identity provider.
- The fully qualified domain name of the Qlik Cloud tenant where the JWT identity provider configuration is set.
- The
Configure a web integration id
Web integrations are a security mechanism allowing websites that present a valid id associated with an URL inclusion list the capability to render embedded visualizations.
-
Open a web browser and navigate to your Qlik Cloud tenant. Once authenticated to your tenant, click the waffle icon and select Management Console.
-
Select Web in the Integration section of the side menu. Click the Create new button on the right side of the screen.
-
In the configuration window, give the web integration a name, and provide the URL for the web applications containing the references to embedded visualizations.
-
Press the Add button to add the URL - also known as an origin - to the Allowed origins list. Then click the Create button.
-
Copy the generated web integration id and put it aside for use in your project later on in this tutorial.
Configure JWT authorization project
This project uses the qlik-cloud-jwt boilerplate repository to show you how to implement JWT authorization in your web application.
Project directory structure
.+-- README+-- package.json+-- config| +-- config.js # configuration file of references for Qlik tenant connection+-- data| +-- private.key.txt # JWT signing certificate+-- token| +-- token.js # JWT creation code+-- src| +-- app.js # code for showing content for demo purposes| +-- auth.js # the authorization flow| +-- configuration.js # code for defining nebula visualization| +-- connectQlikApp.js # code for websocket connection to Qlik| +-- index.html # html for demo purposes| +-- server.js # backend for serving code for demo purposes| +-- styles.css # css for demo purposes
This tutorial focuses on the config.js
, token.js
, and auth.js
files so
that you learn the authorization flow for working with JWTs and Qlik Cloud.
Configure config.js
Begin setting up your project with a config.js file. In this file, you set the attributes that are used in the rest of the project to make it go.
The boilerplate starts with definitions for the different log in types available on Qlik Cloud. This is nice to have as you troubleshoot your code because you can switch between forcing an interactive log in - logging in with a userId and password - and using the JWT token you pass through to the tenant.
-
Create a
config.js
file. Add the loginTypes object to the file if you want to toggle between interactive and JWT based authentication experiences.const loginTypes = {INTERACTIVE_LOGIN: 'interactive-login',JWT_LOGIN: 'jwt-login'} -
Add
loginTypes
andcurrentLoginType
to a new JSON object if you plan to use them.This next part of the config.js file is the section where you add information about your tenant, the Qlik Sense application id you want to embed content from,and the JWT configuration settings from your tenant. In addition, this is where you set the currentLoginType to use.
Set the
currentLoginType
property to the log in you want the project to support.module.exports = {loginTypes,currentLoginType: loginTypes.JWT_LOGIN, -
Create the
qlikWebIntegrationId
property and add the web integration id you obtained in the Configure a web integration id section.qlikWebIntegrationId: "ENTER_WEB_INTEGRATION_ID_HERE", -
Add the
tenantDomain
property and provide the hostname of your Qlik Cloud tenant. You can find the hostname of your tenant by logging into Qlik Cloud and reviewing the address bar in the browser.tenantDomain: "example.region.qlikcloud.com", -
Add the
appId
property and supply the GUID found in the URL.Embedding content from a Qlik Sense application requires knowing the unique identifier for that app on your Qlik Cloud tenant. The easiest way to obtain this
appId
is to sign in to your tenant and open the app. The app id appears in the address bar of the browserhttps://tenant.region.qlikcloud.com/sense/app/04c0e6e0-b979-4956-b65d-2122082127a1/overview
as the GUID in between app and overview.appId: "bc97609f-523b-4fe9-91f6-78aa0bd1b989", -
Next create properties for the
issuer
andkeyid
from the JWT identity provider configuration you established because you read the tutorial here before this one.// token configissuer: "ISSUER_VALUE_FROM_JWT_IDP_CONFIGURATION",keyid: "KEYID_VALUE_FROM_JWT_IDP_CONFIGURATION" -
The completed
config.js
file should look like this:module.exports = {loginTypes,currentLoginType: loginTypes.AUTOMATIC_LOGIN,// app configqlikWebIntegrationId: "ENTER_WEB_INTEGRATION_ID_HERE",tenantDomain: "example.region.qlikcloud.com",appId: "bc97609f-523b-4fe9-91f6-78aa0bd1b989",// token configissuer: "ISSUER_VALUE_FROM_JWT_IDP_CONFIGURATION",keyid: "KEYID_VALUE_FROM_JWT_IDP_CONFIGURATION"};
Add the private key file to the project
The private key you generated from the tutorial
Create Signed Tokens for JWT Authorization
is needed in the project to sign the token you are going to create in the next
section. Place the private key file into a folder named .data
.
If you are using a remix of the qlik-cloud-jwt boilerplate on Glitch the data folder is a hidden folder you have to reference whenever you want to add a file to it. This is so when projects are remixed, the contents of the data folder do not remix along with the rest of the project.
See the appendix here to learn how to add your private key to the .data
folder.
Configuring the token.js file
The token.js
module is the code for generating the JWT (JSON Web Token) used
to authorize users to Qlik Cloud. The code requires the config.js
file and
reads the private key so it can sign the JWT and ensure the data inside is
verifiable by the JWT identity provider configuration. Signing the JWT is
handled by the jsonwebtoken
module found on npm.
Here are the lines that import those components into token.js
.
const jsonWebToken = require("jsonwebtoken"); const fs = require("fs"); const uid = require('uid-safe'); const config = require("../config/config");
const key = fs.readFileSync(".data/private.key.pem", "utf8");
The generate
function does all the heavy lifting in this file and there are
two important variables to make note of; the signingOptions
and the payload
.
The signingOptions
variable is a JSON object providing the information used to
verify the JWT and how long the JWT can be used.
For Qlik Cloud to validate the JWT, the signing options must include all the
properties in the code below. The keyid
and issuer
come from the JWT
identity provider configuration. The algorithm
must be set to "RS256"
and
the audience must be set to "qlik.api/login/jwt-session"
.
The expiresIn
property defines the expiration date/time of the
JWT. This property does not determine the session cookie Qlik Cloud returns to
provide access to content.
Here is an example of a valid signingOptions
object.
const signingOptions = { "keyid": config.keyid, "algorithm": "RS256", "issuer": config.issuer, "expiresIn": "30s", //Expires 30 seconds after the issue date/time. "notBefore": "1s", //JWT is valid 1 second after the issue date/time. "audience": "qlik.api/login/jwt-session" };
The time between the notBefore
and expiresIn
must not exceed
sixty minutes.
The payload
variable is a JSON object containing information describing the
user seeking authorization to Qlik Cloud.
The required claims for a Qlik JWT payload are the following:
- jti - (JWT ID) claim provides a unique identifier for the JWT
- iat - The issued at date of the JWT provided as a numeric timestamp.
- sub - The main identifier (aka subject) of the user.
- subType - The type of identifier the sub represents. In this case,
user
is the only applicable value. - name - The friendly name to apply to the user.
- email - The email address of the user.
- email_verified - A claim indicating to Qlik that the JWT source has verified that the email address belongs to the subject.
It’s possible to send additional claims in the JWT. Today,
only the optional claim groups
is read.
Here is a sample JWT payload including the groups attribute:
{ "jti": "k5bU_cFI4_-vFfpJ3DjDsIZK-ZhJGRbBfusUWZ0ifBI", "iat": 1658416389, "sub": "SomeSampleSeedValue", //e.g. 0hEhiPyhMBdtOCv2UZKoLo4G24p-7R6eeGdZUQHF0-c "subType": "user", "name": "Hardcore Harry", "email": "harry@example.com", "email_verified": true, "groups": ["Administrators", "Sales", "Marketing"]}
Depending on the library you use to sign JWTs, you may have to
manually assign an iat
value to the JWT payload. Many JWT signing libraries -
like JSONWebToken for Node - add the iat
attribute automatically upon JWT
signing. Please refer to the documentation for the JWT signing library you are
using to determine iat
handling.
In the token.js
code, the generate
function requires sending in the sub,
name, email, and groups as an array.
const payload = { jti: uid.sync(32), // 32 bytes random string sub: sub, subType: "user", name: name, email: email email_verified: true, groups: groups };
With the signing options and the payload configured, use jsonWebToken.sign
supplying it with both objects and the private key to generate the JWT token.
Then return the token so that it can be used to authorize the use to Qlik Cloud.
const token = jsonWebToken.sign(payload, key, signingOptions); return token;
auth.js file review
The auth.js
file sends the authorization token to Qlik Cloud and obtains the
required response information to render content. The code works this way:
-
Gets the configuration information from
config.js
to begin the authorization process.const { tenantDomain, qlikWebIntegrationId, appId, currentLoginType, loginTypes } = await fetch("config").then((resp) => resp.json()); -
Checks which authentication and authorization method to use; interactive or JWT.
if(currentLoginType === loginTypes.JWT_LOGIN) await handleAutomaticLogin()else if (currentLoginType === loginTypes.INTERACTIVE_LOGIN) await handleUserLogin() -
Performs the appropriate log in based on the method set in
config.js
.-
In
JWT_LOGIN
mode, the code requests a token and performs the authorization with Qlik Cloud.async function handleAutomaticLogin() {const { token } = await fetch("token").then(resp =>resp.json());const login = await fetch(`https://${tenantDomain}/login/jwt-session?qlik-web-integration-id=${qlikWebIntegrationId}`,{method: "POST",credentials: "include",mode: "cors",headers: {"content-type": "application/json",Authorization: `Bearer ${token}`,"qlik-web-integration-id": qlikWebIntegrationId},rejectunAuthorized: false});} -
In
INTERACTIVE_LOGIN
mode, the code redirects the browser to the log in page for the tenant. Upon successful authentication, Qlik Cloud redirects back to the web application.async function handleUserLogin() {const response = await fetch(`https://${tenantDomain}/api/v1/csrf-token`, {credentials: 'include',headers: { 'qlik-web-integration-id': qlikWebIntegrationId }})if(response.status === 401) {shouldLoginBox.style.display = 'block'const loginUrl = new URL(`https://${tenantDomain}/login`);loginUrl.searchParams.append('returnto', window.location.href);loginUrl.searchParams.append('qlik-web-integration-id', qlikWebIntegrationId);loginLink.href = loginUrl.href;}}
-
-
Before requesting any content from Qlik Cloud, the web application needs to obtain a cross-site request forgery token. The CSRF token acts as an additional handshake between the web application and Qlik Cloud that requests coming from the web application are valid.
const csrfTokenInfo = await (await fetch(`https://${tenantDomain}/api/v1/csrf-token?qlik-web-integration-id=${qlikWebIntegrationId}`,{credentials: "include",headers: {"Qlik-Web-Integration-ID": qlikWebIntegrationId}}));
The code requires the double use of await
to ensure the
browser completes the preflight request to the csrf-token endpoint and the
GET request to return the cross-site scripting token.
It’s now possible to make a request for content from Qlik Cloud by including
the web integration id and CSRF token in the URL. Refer to the
qlik-cloud-jwt project on Glitch
and review the app.js
and connectQlikApp.js
files.
Configuring Qlik Cloud to allow iframe embedding in your web application
If the solution includes embedding Qlik Sense visualizations using iframe technology, the tenant hosting the analytic content must have an entry added to the Content Security Policy section in the management console.
- Open a web browser and navigate to your Qlik Cloud tenant. Once authenticated to your tenant, click the waffle icon and select Management Console.

Content Security Policy (CSP) is a browser mechanism for mitigating and preventing cross-site scripting (XSS) attacks. Setting a CSP header in the management console enables Qlik components embedded in external web applications to render and work properly.
- Select Content Security Policy in the Integration section of the side menu. Click the Add button on the right side of the screen.

- In the Add origin window, give the entry a name and provide the
origin for the web application, for example
glitch.com
). Under the origin, select theframe-ancestors
directive.

By selecting the frame-ancestors
directive, the web application with the
iframe tag containing a reference to Qlik Cloud renders the requested content.
For more information on content security policy, visit this website on the topic.
Conclusion
The aim of this tutorial is to help provide understanding for configuring JWT authorization to Qlik Cloud through a web application. To experience a complete example, please visit the project qlik-cloud-jwt.
Get started with Catalog integration
Learn the basics of using the Catalog API.
Get started with Lineage integration
Learn the basics using the lineage API.
Build a web app for the Insight Advisor API
Learn how to access the Insight Advisor API using a web app.