Skip to main content
Announcements
NEW: Seamless Public Data Sharing with Qlik's New Anonymous Access Capability: TELL ME MORE!
cancel
Showing results for 
Search instead for 
Did you mean: 
FernandoOliveiraAE
Contributor
Contributor

JWT authentication in mashup error 401 AUTH-1

Could anyone help me identify what might be wrong with this code, as it's returning error 401 AUTH-1

const fs = require("fs");
const uid = require("uid-safe");
const jwt = require("jsonwebtoken");

const payload = {
  jti: uid.sync(32), // 32 bytes random string
  sub: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  subType: "user",
  name: "XXXXXX",
  email: "XXXXXXXXXXXXXXXXXXXXXX",
  email_verified: true,
  groups: ["Administrators", "Sales", "Marketing"],
};

const privateKeyPath = "./privatekey.pem";
const privateKey = fs.readFileSync(privateKeyPath, "utf8");

const headerOptions = {
  algorithm: "HS256",
  keyid: "XXXXXXXXXX",
};

const signOptions = {
  issuer: "XXXXXXXXX.us.qlikcloud.com",
  expiresIn: "5m",
  notBefore: "1s",
  audience: "qlik.api/login/jwt-session",
};

function generateToken() {
  const myToken = jwt.sign(payload, privateKey, {
    ...headerOptions,
    ...signOptions,
  });
  return myToken;
}

let token = generateToken();

var config = {
  host: "XXXXXXXX.us.qlikcloud.com",
  prefix: "/",
  port: 443,
  isSecure: true,
  webIntegrationId: "XXXXXXXXXXXXXXXXXXXXXXXXX",
};

async function login() {
  const response = await fetch(
    `https://${config.host}/login/jwt-session?qlik-web-integration-id=${config.webIntegrationId}`,
    {
      method: "POST",
      credentials: "include",
      mode: "cors",
      headers: {
        "content-type": "application/json",
        Authorization: `Bearer ${token}`,
        "qlik-web-integration-id": config.webIntegrationId
      },
      rejectunAuthorized: false
    }
  );

  console.log(await response.text());

  if ((response.status) !== 200) {
    console.log(await response.text());
    throw new Error("Failed to login via JWT");
  }
}

async function initialize() {
  try {
      await login();
      configureQlik();
  } catch (error) {
      console.error("Error during initialization:", error.message);
  }
}

function configureQlik() {
  require.config({
      baseUrl: `${config.isSecure ? "https://" : "http://"}${config.host}${config.port ? ":" + config.port : ""}${config.prefix}resources`,
      webIntegrationId: config.webIntegrationId
  });

  require(["js/qlik"], function (qlik) {
      qlik.on("error", function (error) {
          $('#popupText').append(error.message + "<br>");
          $('#popup').fadeIn(1000);
      });
      $("#closePopup").click(function () {
          $('#popup').hide();
      });

      var app = qlik.openApp('XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', config);
      app.visualization.get('XXXXXXXX').then(function (vis) {
          vis.show("QV01");
      });
  });
}

(async function() {
  try {
    await initialize();
  } catch (error) {
    console.error("Initialization failed:", error);
  }
})();
Labels (2)
2 Replies
Levi_Turner
Employee
Employee

I'd recommend consulting this doc (https://qlik.dev/authenticate/jwt/implement-jwt-authorization/), in a quick scan through (by someone not particularly talented at JavaScript), you're using HS256 whereas we want RS256. Given that we do public / private validation, you can't swap the algos. I would work through known good then adapt to your use case.

FernandoOliveiraAE
Contributor
Contributor
Author

Thanks, but I had already made the change and still couldn't get it to work as expected.
I saw that I need to do it object by object and not as I would like, which would be to take the entire app