Skip to main content
Announcements
See why Qlik was named a Leader in the 2024 Gartner® Magic Quadrant™ for Data Integration Tools for the ninth year in a row: Get the report
cancel
Showing results for 
Search instead for 
Did you mean: 
cristian_dalsanto
Partner - Contributor III
Partner - Contributor III

How to obtain CSRF token from Qlik Cloud

Hi all,

I’m currently migrating a mashup from Qlik On-Premise to Qlik Cloud.

My mashup uses Enigma.js and Nebula.js for visualizations, but I’m running into issues while trying to obtain the CSRF token. I’ve tried two different approaches:

1. Qlik Cloud with standard Identity Provider and frontend with Keycloak as Identity Provider

Here’s the scenario:

  • The frontend authenticates users through Keycloak.
  • The frontend calls a Node.js API, passing the Qlik userId as parameter, and retrieves a web token via OAuth impersonation.
  • After obtaining the web token, the frontend calls a separate Node.js API to retrieve the CSRF token. However, this results in a 404 error ("token not found").

2. Qlik Cloud with Keycloak as Identity Provider

In this scenario:

  • The frontend authenticates users through Keycloak.
  • The frontend calls a Node.js API, passing the Keycloak session token to obtain the CSRF token. Unfortunately, I’m still getting the same 404 error.

I suspect the issue might be that the /api/v1/csrf-token endpoint isn’t designed to issue a CSRF token when a web token is used as an authorization bearer token. The documentation includes an example with an API key, but that solution isn’t feasible in my case because multiple users need access to the mashup.

 

Can anyone offer some guidance on this?

Thanks for the support!

Cristian

Labels (4)
18 Replies
mpc
Partner - Specialist II
Partner - Specialist II

Hi, 

Following this post, you're right, you cannot use bearer auth token .  Solved: How can i fetch a csrf token with an access token? - Qlik Community - 1900614

Regards

From Next Decision and mpc with love
It helps, like it, It solves, mark it
alex_colombo
Employee
Employee

Hey @cristian_dalsanto , if you are using a M2M impersonation token you should not need to use CRSF token. What is your goal? You want to get a CSRF token for doing what?

cristian_dalsanto
Partner - Contributor III
Partner - Contributor III
Author

Hi @alex_colombo 

The M2M impersonation token works well when embedding visualizations using the Qlik-embed framework—I’ve successfully used it in a different mashup scenario.

Here, though, I need to establish a WebSocket connection to Qlik Cloud, and from what I read in the documentation, a CSRF token is required for this connection. Am I mistaken? Is it possible to create a WebSocket connection directly using the M2M impersonation token? If so, could you please point me to any documentation on that?

Thank you very much for your support!

Cristian

 

alex_colombo
Employee
Employee

You are referring to this article about CRSF token? This is needed only for onprem version of the product, and not Qlik Cloud.

What are you using for creating WebSocket connection? enigma.js, qlik/api or custom code? In any case, you should be able to use M2M impersonation token without CSRF token. Please give it a try.

cristian_dalsanto
Partner - Contributor III
Partner - Contributor III
Author

I create the web socket using enigma.create method as the following code:

 const session = enigma.create({
    schema,
    // url: `wss://${environment.QLIK_URL}/app/${environment.QLIK_APPID}`,
    url: `wss://${environment.QLIK_URL}/app/${environment.QLIK_APPID}?qlik-web-integration-id=${environment.WEBINTEGRATIONID}`,
    responseInterceptors: [{
      // We only want to handle failed responses from QIX Engine:
      onRejected: function retryAbortedError(sessionReference, request: any, error: any) {
        console.log('Request: Rejected', error);

        if (error.code == -1) {
          console.log('not connected to qlik - app refresh');
          window.location.reload();
        }
        // We only want to handle aborted QIX errors:
        if (error.code === schema.enums.LocalizedErrorCode.LOCERR_GENERIC_ABORTED) {
          // We keep track of how many consecutive times we have tried to do this call:
          request.tries = (request.tries || 0) + 1;
          console.log(`Request: Retry #${request.tries}`);
          // We do not want to get stuck in an infinite loop here if something has gone
          // awry, so we only retry until we have reached MAX_RETRIES:
          if (request.tries <= MAX_RETRIES) {
            return request.retry();
          }
        }
        // If it was not an aborted QIX call, or if we reached MAX_RETRIES, we let the error
        // trickle down to potential other interceptors, and finally down to resolving/rejecting
        // the initial promise that the user got when invoking the QIX method:
        return (error);
      },
    }],
  });

I tried 2 different scenario.

1. Qlik and Mashup using the same Identity provider (keycloak). 

2. Qlik with standard IdP and Mashup under Keycloak. In this case, before creating the web socket I retrieve a M2M impersonation token from a node.js backend. But I don't know how to pass it to the enigma.create method...

Any suggestions would be greatly appreciated.

Thanks

Cris

alex_colombo
Employee
Employee

If you are using enigma.js, just update enigma at latest version and enigma will take care about CRSF token. For M2M impersonation, try to attach it to websocket header. For using websocket header try to do this like did it here.

cristian_dalsanto
Partner - Contributor III
Partner - Contributor III
Author

Thanks Alex for the support.

However, despite trying different methods, I still can't find the right way to authenticate my WebSocket without going through the login process.

I'll try to describe my situation more clearly:

My mashup is an Angular application that uses Keycloak for security management. When the application starts, during the initialization phase, a Keycloak service checks if I'm authenticated. If not, it redirects me to the Keycloak login page. After logging in, I can obtain the Qlik Cloud user ID among the attributes of the logged-in user.

With this user ID, I can call a backend service (node.js) that, through an M2M OAuth2 impersonation, provides me with an access token.

In my previous mashup, where I used qlik-embed, I passed this web token directly to Qlik Embed following this example:

<script
  crossorigin="anonymous"
  type="application/javascript"
  src="https://cdn.jsdelivr.net/npm/@qlik/embed-web-components@1/dist/index.min.js"
  data-host="https://tenantName.region.qlikcloud.com"
  data-client-id="OAuth impersonation client Id"
  data-get-access-token="getAccessToken"
  data-auth-type="Oauth2"
></script>
<script>
  async function getAccessToken() {
    const response = await fetch("/access-token", {
      method: "POST",
      credentials: "include",
      mode: "same-origin",
      redirect: "follow",
    });
    if (response.status === 200) {
      return response.text();
    }
    const err = new Error("Unexpected serverside authentication error");
    err.status = response.status;
    err.detail;
    throw err;
  }
</script>

and everything worked fine.

In this case, however, I need to interact with the engine, as I require variables and hypercubes. So I need to establish a WebSocket connection to the engine. But I can’t find a way to do this without having to go through Qlik Cloud’s login again.

Am I perhaps using the wrong approach? Is enigma.js on the client side maybe not the best choice?

I’ve also looked at @qlik/api, which does roughly the same thing, but even there, authentication via token isn’t supported (at most, @qlik/api accepts an API key, which isn’t suitable for my case).

Do you have any suggestions for me?

Many Thanks

Cristian

alex_colombo
Employee
Employee

Ok now it is more clear. The right approach is to use qlik/api and using Engine APIs. I know, it is not documented yet but you can use OAuth M2M token with qlik/api. Below how to do it (replace oauthToken variable with your M2M token):

const config = {
    authType: "oauth2",
    host: configParams.tenantHostname,
    clientId: configParams.oAuthClientId,
    getAccessToken: oauthToken
};

qlikApi.auth.setDefaultHostConfig(config);

//Open an app using qix
const appSession = qlikApi.qix.openAppSession(configParams.appId);
// get the "qix document (qlik app)"
const app = await appSession.getDoc();

 

cristian_dalsanto
Partner - Contributor III
Partner - Contributor III
Author

Thanks Alex,

I was looking for a method just like this.
I’ve just implemented it as follows:

async function getEnigmaSessionAndApp2(webToken: string) {
  const hostConfig: any = {
    authType: "oauth2",
    host: environment.QLIK_PARAMETERS.QLIK_URL,
    clientId: environment.QLIK_PARAMETERS.CLIENT_ID,
    getAccessToken: webToken
  }
  auth.setDefaultHostConfig(hostConfig);
  const session = qix.openAppSession({ appId: environment.QLIK_PARAMETERS.QLIK_APPID });
  const app = await session.getDoc();
  return [session, app];
}


Unfortunately, I’m getting a 401 error when I do

session.getDoc(); 

as if the token were invalid...
Am I missing something? 
And here’s the returned error.

cristian_dalsanto_0-1731421989642.png

Thanks,

Cris