diff --git a/README.md b/README.md index aef883d..80b1935 100644 --- a/README.md +++ b/README.md @@ -97,4 +97,14 @@ The command `make build` creates a docker image with the name `mojaloop-payment- ### Running the docker image -The command `make run` runs the docker image binding the port 8080. \ No newline at end of file +The command `make run` runs the docker image binding the port 8080. + +## Using external authentication + +Set the environment variables, before running the server (or Docker image): + +- `CHECK_SESSION_URL`: URL to check if the session is still valid +- `LOGIN_URL`: - URL to redirect to when the session is not valid +- `LOGIN_PROVIDER`: - The name of the login provider. When specified, the app will redirect to the login provider URL. + +These will override the in-app login form and redirect to the provided URL. diff --git a/package.json b/package.json index 2cc764d..6042c29 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mojaloop-payment-manager-ui", - "version": "1.13.0", + "version": "1.14.0", "private": true, "proxy": "http://localhost:10000", "engines": { diff --git a/server/index.js b/server/index.js index ec7da8a..dc4da18 100644 --- a/server/index.js +++ b/server/index.js @@ -7,6 +7,9 @@ app.use(express.static(path.join(__dirname, 'build'))); app.get('/config', function (req, res) { res.send({ API_BASE_URL: process.env.API_BASE_URL, + CHECK_SESSION_URL: process.env.CHECK_SESSION_URL, + LOGIN_URL: process.env.LOGIN_URL, + LOGIN_PROVIDER: process.env.LOGIN_PROVIDER, }); }); diff --git a/src/utils/authentication.ts b/src/utils/authentication.ts index b817c6d..7553360 100644 --- a/src/utils/authentication.ts +++ b/src/utils/authentication.ts @@ -1,7 +1,73 @@ import axios from 'axios'; -export default async function getUserInfo(config: { apiBaseUrl: string }) { +export default async function getUserInfo(config: { + apiBaseUrl: string; + checkSession: string; + loginUrl: string; + loginProvider: string; +}) { try { + if (config.checkSession && config.loginUrl) { + // check for active session + const session = await axios({ + method: 'GET', + url: config.checkSession, + validateStatus: (code) => { + console.log({ code }); + return (code > 199 && code < 300) || code === 401; + }, + withCredentials: true, + }); + + if (session.status === 401) { + const loginUrl = `${config.loginUrl}?return_to=${window.location.href}`; + if (!config.loginProvider) { + window.location.assign(loginUrl); + return false; + } + // obtain login flow + const flow = await axios({ + method: 'GET', + url: loginUrl, + validateStatus: (code) => code > 199 && code < 300, + }); + const { + ui: { method, action, nodes }, + ui, + } = flow.data; + const form = document.createElement('form'); + form.method = method; + form.action = action; + let submit: HTMLInputElement | undefined; + + nodes.forEach( + ({ + attributes: { type, name, node_type, value }, + }: { + attributes: Record; + }) => { + if (name === 'provider' && value !== config.loginProvider) return; + const element = document.createElement(node_type) as HTMLInputElement; + if (name === 'provider') submit = element; + element.type = type; + element.value = value; + element.name = name; + form.appendChild(element); + } + ); + + if (submit) { + // submit flow with configured provider + document.body.appendChild(form); + submit.click(); + } else { + // navigate to login url + window.location.assign(loginUrl); + } + return false; + } + } + const response = await axios({ method: 'GET', url: `${config.apiBaseUrl}/userInfo`, diff --git a/src/utils/config.ts b/src/utils/config.ts index 052d34f..26f5be5 100644 --- a/src/utils/config.ts +++ b/src/utils/config.ts @@ -4,6 +4,9 @@ const getConfig = async () => { const { protocol, host } = window.location; const configURL = `${protocol}//${host}/config`; let apiBaseUrl = 'http://localhost:4010'; + let checkSession; + let loginUrl; + let loginProvider; try { const { headers, data } = await axios(configURL); @@ -12,13 +15,16 @@ const getConfig = async () => { console.info('Config was invalid. Falling back to default values'); } else { apiBaseUrl = data.API_BASE_URL; + checkSession = data.CHECK_SESSION_URL; + loginUrl = data.LOGIN_URL; + loginProvider = data.LOGIN_PROVIDER; } } catch (err) { // eslint-disable-next-line console.info('Config not found. Falling back to default values'); } - return { apiBaseUrl }; + return { apiBaseUrl, checkSession, loginUrl, loginProvider }; }; export default getConfig;