Web app authentication with QSEoW (web ticket + session cookie)

In one of the previous post we saw how to use web ticket to establish connection with Qlik Sense Engine. And probably for most cases the approach there is enough.

But what if our web app have a requirement to communicate with other Qlik service(s) (in addition to the Engine)? For example, we want to list the reload tasks to which the user have access (this information is provided by Qlik Repository Service REST API)?

The problem with the web ticket is that once it is consumed it can't be used again. And if we use the ticket to open web socket Engine connection then we can't use the same ticket to get the list of the reload tasks. We'll end up with situation where the Engine connection is authenticated and established but upon requesting the list of reload tasks Qlik will response with Unauthenticated.

To overcome this we can "exchange" the web ticket for a Qlik session. The exchange will be in a form of a session cookie. We'll have the session cookie set in the browser and then our web app can freely open Engine connection (without web ticket) and communicate with other Qlik Sense services. In similar way the Hub is doing it.

Pre-requisites (QMC)

Couple of settings have to be set in the Virtual Proxy before we can start (if they are not set already):

  • White list - add the web app url to the host white list
  • SameSite attributes - make sure that the SameSite attributes are set to None (at least)

Code workflow

The code workflow is:

  • get web ticket from Qlik (in the same manner as in the previous post)
  • use the ticket to retrieve the content of any static Qlik resource via HTTP request. In this example I'm going to use /resources/autogenerated/qlik-styles.css but it can be any other static file that requires authentication in order to be viewed/downloaded
  • since we are using the ticket in HTTP request the response from Qlik will be the content of the requested resource + session cookie
  • once session cookie is set (the browser is taking care of this) we can continue and connect to the Engine and "ask" Qlik for different data (in our case get list of reload tasks)

Code

  • retrieve the static file content
export const load = async ({ url, params }) => {
  // look for "qlikTicket" query parameter
  const qlikTicket = url.searchParams.get("qlikTicket");

  // if "qlikTicket" is present
  // use the ticket to retrieve the content of "qlik-styles.css"
  // if all is ok Qlik will send the session cookie
  // and the browser will set it
  if (qlikTicket) {
   const qlikStylesURL = `https://${qsHost}/resources/autogenerated/qlik-styles.css?QlikTicket=${qlikTicket}`;
 
  const qlikStylesResponse = await fetch(qlikStylesURL, {
    credentials: "include",
   });
 }

  return true;
};
  • variables
const qsHost = "my-sense-instance.com";
const reloadURI = `http://localhost:3000`;
const xrfkey = "1234567890123456";
const qsReloadTasksURL = `https://${qsHost}/qrs/reloadtask?Xrfkey=${xrfkey}`;
 
let qlikApps = [];
let qlikReloadTasks = [];
  • Notification events
// redirect to the login page if the Engine connection response indicates that we have to authenticate
session.on("notification:OnAuthenticationInformation", (data) => {
 if (data.loginUri) goto(data.loginUri);
});

// once the Engine connection is established, get the list of the reload tasks (in the logged in user context)
session.on("notification:OnConnected", async () => {
 qlikReloadTasks = await fetch(qsReloadTasksURL, {
   credentials: "include",
   headers: {
     "X-Qlik-Xrfkey": `${xrfkey}`,
   },
 }).then((res) => res.json());
});
  • HTML structure
<main>
  <div>
    <h1>Qlik apps:</h1>

    {#each qlikApps as qlikApp}
      <div title={qlikApp.qDocId}>{qlikApp.qDocName}</div>
    {/each}
  </div>

  <div>
    <h1>Qlik Reload Tasks:</h1>

    {#each qlikReloadTasks as reloadTask}
      <div title={reloadTask.id}>{reloadTask.name}</div>
    {/each}
  </div>
</main>

Result

Once the whole process is complete we should see something like:

And if we inspect the network request will see:

  • the qlik-styles.css request is with attached QlikTicket the response is 200 OK and the response headers are containing the session cookie
qlik-styles.css response
qlik-styles.css response headers
  • we can see the cookie being set in the browser
Browser (session) cookie
  • both the Engine connection and Repository API request are made without any ticket added to the urls
Web Socket (Engine) connection
HTTP (Repository API) connection

Complete code

The full code is available at the repo below. Follow the readme there to install and run it.

GitHub - countnazgul/qseow-svelte-authentication-session
Contribute to countnazgul/qseow-svelte-authentication-session development by creating an account on GitHub.

Hope you liked it!

Stefan