Files
nebula.js/commands/serve/lib/oauth-router.js
Tobias Åström a0dc0f0ce1 fix(cli-serve): OAuth instance cache issue (#1500)
* fix: client id cache issue

* chore: fix originurl

---------

Co-authored-by: a-m-dev <a.mirzaei.dev@gmail.com>
2024-03-05 16:39:36 +01:00

122 lines
3.5 KiB
JavaScript

const express = require('express');
const { Auth, AuthType } = require('@qlik/sdk');
let prevHost = null;
let prevClientId = null;
let authInstance = null;
const getAuthInstance = (returnToOrigin, host, clientId) => {
if (authInstance && prevHost === host && prevClientId === clientId) {
return authInstance;
}
prevHost = host;
prevClientId = clientId;
authInstance = new Auth({
authType: AuthType.OAuth2,
host,
clientId,
redirectUri: `${returnToOrigin}/auth/login/callback`,
});
return authInstance;
};
const OAuthRouter = ({ originUrl }) => {
const router = express.Router();
let cachedHost = null;
let cachedClientId = null;
router.get('/oauth', async (req, res) => {
const { host: qHost, clientId: qClientId } = req.query;
if (!cachedHost && !cachedClientId) {
cachedHost = qHost;
cachedClientId = qClientId;
}
const returnTo = `${req.protocol}://${req.get('host')}`;
const instacne = getAuthInstance(returnTo, qHost, qClientId);
const isAuthorized = await instacne.isAuthorized();
if (!isAuthorized) {
const { url: redirectUrl } = await instacne.generateAuthorizationUrl();
res.status(200).json({ redirectUrl });
} else {
const reqHost = req.get('host');
const redirectUrl = `${req.protocol}://${reqHost}/app-list?engine_url=wss://${cachedHost}&qlik-client-id=${cachedClientId}&shouldFetchAppList=true`;
cachedHost = null;
cachedClientId = null;
res.redirect(redirectUrl);
}
});
router.get('/login/callback', async (req, res) => {
const authLink = new URL(req.url, `http://${req.headers.host}`).href;
try {
// TODO:
// this is a temp fix in nebula side
// (temp workaround of not presisting origin while backend tries to authorize user)
// they need to handle this in qlik-sdk-typescript repo
// and will notify us about when they got fixed it,
// but until then, we need to take care of it here!
authInstance.rest.interceptors.request.use((_req) => {
// eslint-disable-next-line no-param-reassign, dot-notation
_req[1]['headers'] = { origin: originUrl };
return _req;
});
await authInstance.authorize(authLink);
res.redirect(301, `/auth/oauth?host=${cachedHost}&clientId=${cachedClientId}`);
} catch (err) {
console.log({ err });
res.status(401).send({
message: 'Auth failed in callback redirecting, based on the provided auth link!',
});
}
});
router.get('/deauthorize', async (req, res) => {
try {
prevHost = null;
prevClientId = null;
authInstance = null;
cachedHost = null;
cachedClientId = null;
await authInstance?.deauthorize();
res.status(200).json({
deauthorize: true,
});
} catch (error) {
console.log({ error });
}
});
router.get('/isAuthorized', async (req, res) => {
if (!authInstance) {
res.status(200).json({
isAuthorized: false,
});
} else {
const isAuthorized = await authInstance.isAuthorized();
res.status(200).json({
isAuthorized,
});
}
});
router.get('/getSocketUrl/:appId', async (req, res) => {
const { appId } = req.params;
const webSocketUrl = await authInstance.generateWebsocketUrl(appId, true);
res.status(200).json({ webSocketUrl });
});
return router;
};
const getAvailableAuthInstance = () => authInstance;
module.exports = { OAuthRouter, getAvailableAuthInstance };