diff --git a/app/configuration/ApplicationConfig.scala b/app/configuration/ApplicationConfig.scala
index cb10fecd3..059a01007 100644
--- a/app/configuration/ApplicationConfig.scala
+++ b/app/configuration/ApplicationConfig.scala
@@ -12,7 +12,10 @@ class ApplicationConfig @Inject() (configuration: Configuration) {
get("consignmentapi.url"),
get("environment"),
get("region"),
- get("upload.url")
+ get("upload.url"),
+ get("auth.url"),
+ get("auth.clientId"),
+ get("auth.realm")
)
val numberOfItemsOnViewTransferPage: Int = configuration.get[Int]("viewTransfers.numberOfItemsPerPage")
diff --git a/app/views/partials/frontEndInputs.scala.html b/app/views/partials/frontEndInputs.scala.html
index e5c683e17..9d0fcf8ff 100644
--- a/app/views/partials/frontEndInputs.scala.html
+++ b/app/views/partials/frontEndInputs.scala.html
@@ -5,3 +5,6 @@
+
+
+
diff --git a/app/viewsapi/FrontEndInfo.scala b/app/viewsapi/FrontEndInfo.scala
index adb56dc70..2e94e952b 100644
--- a/app/viewsapi/FrontEndInfo.scala
+++ b/app/viewsapi/FrontEndInfo.scala
@@ -4,5 +4,8 @@ case class FrontEndInfo(
apiUrl: String,
stage: String,
region: String,
- uploadUrl: String
+ uploadUrl: String,
+ authUrl: String,
+ clientId: String,
+ realm: String
)
diff --git a/conf/application.base.conf b/conf/application.base.conf
index 01a1f9133..d6582bb4b 100644
--- a/conf/application.base.conf
+++ b/conf/application.base.conf
@@ -7,6 +7,8 @@ pekko.actor.warn-about-java-serializer-usage = "off"
auth.secret = ${AUTH_SECRET}
read.auth.secret = ${READ_AUTH_SECRET}
auth.url=${AUTH_URL}
+auth.clientId="tdr-fe"
+auth.realm="tdr"
consignmentapi.url = ${consignmentapi.domain}"/graphql"
diff --git a/npm/package-lock.json b/npm/package-lock.json
index d5e241868..f89b6ba8e 100644
--- a/npm/package-lock.json
+++ b/npm/package-lock.json
@@ -19,7 +19,7 @@
"copyfiles": "^2.4.1",
"events": "^3.3.0",
"graphql": "^16.9.0",
- "keycloak-js": "25.0.6",
+ "keycloak-js": "26.0.4",
"minify": "^11.4.1",
"npm-run-all": "^4.1.5",
"sass": "^1.80.4",
@@ -12090,11 +12090,6 @@
"url": "https://github.com/sponsors/panva"
}
},
- "node_modules/js-sha256": {
- "version": "0.11.0",
- "resolved": "https://registry.npmjs.org/js-sha256/-/js-sha256-0.11.0.tgz",
- "integrity": "sha512-6xNlKayMZvds9h1Y1VWc0fQHQ82BxTXizWPEtEeGvmOUYpBRy4gbWroHLpzowe6xiQhHpelCQiE7HEdznyBL9Q=="
- },
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -12243,22 +12238,10 @@
"integrity": "sha512-cYofQu2Xpom82S6qD778jBDpwvvy39s1l/hrYij2u9AMdQcGRpaBu6kY4mVhuno5kJVi1DAz4aiphA2WI1/OAw==",
"dev": true
},
- "node_modules/jwt-decode": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-4.0.0.tgz",
- "integrity": "sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==",
- "engines": {
- "node": ">=18"
- }
- },
"node_modules/keycloak-js": {
- "version": "25.0.6",
- "resolved": "https://registry.npmjs.org/keycloak-js/-/keycloak-js-25.0.6.tgz",
- "integrity": "sha512-Km+dc+XfNvY6a4az5jcxTK0zPk52ns9mAxLrHj7lF3V+riVYvQujfHmhayltJDjEpSOJ4C8a57LFNNKnNnRP2g==",
- "dependencies": {
- "js-sha256": "^0.11.0",
- "jwt-decode": "^4.0.0"
- }
+ "version": "26.0.4",
+ "resolved": "https://registry.npmjs.org/keycloak-js/-/keycloak-js-26.0.4.tgz",
+ "integrity": "sha512-MBZCLYihYawrUDPjYvryfxWXJgquA5Kr3muWyIigWkNdIP8SBupiuuyKpZlzOMYqdk1eegG1OX0R3qqt1KUKdg=="
},
"node_modules/keyv": {
"version": "4.5.4",
@@ -25348,11 +25331,6 @@
"resolved": "https://registry.npmjs.org/jose/-/jose-5.9.6.tgz",
"integrity": "sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ=="
},
- "js-sha256": {
- "version": "0.11.0",
- "resolved": "https://registry.npmjs.org/js-sha256/-/js-sha256-0.11.0.tgz",
- "integrity": "sha512-6xNlKayMZvds9h1Y1VWc0fQHQ82BxTXizWPEtEeGvmOUYpBRy4gbWroHLpzowe6xiQhHpelCQiE7HEdznyBL9Q=="
- },
"js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -25460,19 +25438,10 @@
"integrity": "sha512-cYofQu2Xpom82S6qD778jBDpwvvy39s1l/hrYij2u9AMdQcGRpaBu6kY4mVhuno5kJVi1DAz4aiphA2WI1/OAw==",
"dev": true
},
- "jwt-decode": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-4.0.0.tgz",
- "integrity": "sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA=="
- },
"keycloak-js": {
- "version": "25.0.6",
- "resolved": "https://registry.npmjs.org/keycloak-js/-/keycloak-js-25.0.6.tgz",
- "integrity": "sha512-Km+dc+XfNvY6a4az5jcxTK0zPk52ns9mAxLrHj7lF3V+riVYvQujfHmhayltJDjEpSOJ4C8a57LFNNKnNnRP2g==",
- "requires": {
- "js-sha256": "^0.11.0",
- "jwt-decode": "^4.0.0"
- }
+ "version": "26.0.4",
+ "resolved": "https://registry.npmjs.org/keycloak-js/-/keycloak-js-26.0.4.tgz",
+ "integrity": "sha512-MBZCLYihYawrUDPjYvryfxWXJgquA5Kr3muWyIigWkNdIP8SBupiuuyKpZlzOMYqdk1eegG1OX0R3qqt1KUKdg=="
},
"keyv": {
"version": "4.5.4",
diff --git a/npm/package.json b/npm/package.json
index fc5ffb83a..e1a2e0eaa 100644
--- a/npm/package.json
+++ b/npm/package.json
@@ -51,7 +51,7 @@
"copyfiles": "^2.4.1",
"events": "^3.3.0",
"graphql": "^16.9.0",
- "keycloak-js": "25.0.6",
+ "keycloak-js": "26.0.4",
"minify": "^11.4.1",
"npm-run-all": "^4.1.5",
"sass": "^1.80.4",
diff --git a/npm/src/auth/index.ts b/npm/src/auth/index.ts
index 8f956de96..9e12984c2 100644
--- a/npm/src/auth/index.ts
+++ b/npm/src/auth/index.ts
@@ -1,12 +1,15 @@
import Keycloak from "keycloak-js"
import { IKeycloakTokenParsed } from "../upload"
+import {IFrontEndInfo} from "../index";
-export const getKeycloakInstance: () => Promise<
- Keycloak.KeycloakInstance | Error
-> = async () => {
- const keycloakInstance: Keycloak.KeycloakInstance = new Keycloak(
- `${window.location.origin}/keycloak.json`
- )
+export const getKeycloakInstance: (frontEndInfo: IFrontEndInfo) => Promise<
+ Keycloak | Error
+> = async (frontEndInfo: IFrontEndInfo) => {
+ const keycloakInstance = new Keycloak({
+ url: `${frontEndInfo.authUrl}`,
+ realm: `${frontEndInfo.realm}`,
+ clientId: `${frontEndInfo.clientId}`
+ })
const errorHandlingModule = await import("../errorhandling")
try {
const authenticated = await keycloakInstance.init({
@@ -38,7 +41,7 @@ const isRefreshTokenExpired: (
}
export const scheduleTokenRefresh: (
- keycloak: Keycloak.KeycloakInstance,
+ keycloak: Keycloak,
cookiesUrl: string,
idleSessionMinValiditySecs?: number
) => void = (keycloak, cookiesUrl, idleSessionMinValiditySecs = 60) => {
@@ -64,7 +67,7 @@ export const scheduleTokenRefresh: (
}
export const refreshOrReturnToken: (
- keycloak: Keycloak.KeycloakInstance,
+ keycloak: Keycloak,
tokenMinValidityInSecs?: number
) => Promise = async (
keycloak,
@@ -74,7 +77,7 @@ export const refreshOrReturnToken: (
if (isRefreshTokenExpired(keycloak.refreshTokenParsed)) {
const errorHandlingModule = await import("../errorhandling")
const error = new errorHandlingModule.LoggedOutError(
- keycloak.createLoginUrl(),
+ await keycloak.createLoginUrl(),
"Refresh token has expired: User is logged out"
)
errorHandlingModule.handleUploadError(error)
diff --git a/npm/src/auth/session-timeout.ts b/npm/src/auth/session-timeout.ts
index c0b6fb2f2..21a84606d 100644
--- a/npm/src/auth/session-timeout.ts
+++ b/npm/src/auth/session-timeout.ts
@@ -1,20 +1,21 @@
import Keycloak from "keycloak-js"
+import {IFrontEndInfo} from "../index";
const timeoutDialog: HTMLDialogElement | null =
document.querySelector(".timeout-dialog")
-export const initialiseSessionTimeout = async (): Promise => {
+export const initialiseSessionTimeout: (frontEndInfo: IFrontEndInfo) => Promise = async (frontEndInfo: IFrontEndInfo): Promise => {
const authModule = await import("./index")
const errorHandlingModule = await import("../errorhandling")
- const keycloak = await authModule.getKeycloakInstance()
+ const keycloak = await authModule.getKeycloakInstance(frontEndInfo)
const now: () => number = () => Math.round(new Date().getTime() / 1000)
//Set timeToShowDialog to how many seconds from expiry you want the dialog log box to appear
const timeToShowDialog = 300
- await setInterval(async () => {
+ setInterval(async () => {
if (!errorHandlingModule.isError(keycloak)) {
const timeUntilExpire = keycloak.refreshTokenParsed!.exp! - now()
if (timeUntilExpire < 0) {
- keycloak.logout()
+ await keycloak.logout()
} else if (timeUntilExpire < timeToShowDialog) {
await showModal(keycloak)
}
@@ -28,7 +29,7 @@ const showModal = async (keycloak: Keycloak): Promise => {
if (timeoutDialog && !timeoutDialog.open) {
timeoutDialog.showModal()
if (extendTimeout) {
- await extendTimeout.addEventListener("click", async (ev) => {
+ extendTimeout.addEventListener("click", async (ev) => {
ev.preventDefault()
await refreshToken(keycloak)
})
diff --git a/npm/src/index.ts b/npm/src/index.ts
index 7676349e4..b082cccbe 100644
--- a/npm/src/index.ts
+++ b/npm/src/index.ts
@@ -14,8 +14,11 @@ window.onload = async function () {
export interface IFrontEndInfo {
apiUrl: string
uploadUrl: string
+ authUrl: string
stage: string
region: string
+ clientId: string
+ realm: string
}
const getFrontEndInfo: () => IFrontEndInfo | Error = () => {
@@ -26,12 +29,21 @@ const getFrontEndInfo: () => IFrontEndInfo | Error = () => {
document.querySelector(".region")
const uploadUrlElement: HTMLInputElement | null =
document.querySelector(".upload-url")
- if (apiUrlElement && stageElement && regionElement && uploadUrlElement) {
+ const authUrlElement: HTMLInputElement | null =
+ document.querySelector(".auth-url")
+ const clientIdElement: HTMLInputElement | null =
+ document.querySelector(".client-id")
+ const realmElement: HTMLInputElement | null =
+ document.querySelector(".realm")
+ if (apiUrlElement && stageElement && regionElement && uploadUrlElement && authUrlElement && clientIdElement && realmElement) {
return {
apiUrl: apiUrlElement.value,
stage: stageElement.value,
region: regionElement.value,
- uploadUrl: uploadUrlElement.value
+ uploadUrl: uploadUrlElement.value,
+ authUrl: authUrlElement.value,
+ clientId: clientIdElement.value,
+ realm: realmElement.value
}
} else {
return Error("The front end information is missing")
@@ -63,7 +75,7 @@ export const renderModules = async () => {
const errorHandlingModule = await import("./errorhandling")
if (!errorHandlingModule.isError(frontEndInfo)) {
const authModule = await import("./auth")
- const keycloak = await authModule.getKeycloakInstance()
+ const keycloak = await authModule.getKeycloakInstance(frontEndInfo)
if (!errorHandlingModule.isError(keycloak)) {
const metadataUploadModule = await import("./clientfilemetadataupload")
const clientFileProcessing =
@@ -91,7 +103,7 @@ export const renderModules = async () => {
const errorHandlingModule = await import("./errorhandling")
if (!errorHandlingModule.isError(frontEndInfo)) {
const authModule = await import("./auth")
- const keycloak = await authModule.getKeycloakInstance()
+ const keycloak = await authModule.getKeycloakInstance(frontEndInfo)
if (!errorHandlingModule.isError(keycloak)) {
const isJudgmentUser = keycloak.tokenParsed?.judgment_user
const checksModule = await import("./checks")
@@ -122,7 +134,7 @@ export const renderModules = async () => {
const errorHandlingModule = await import("./errorhandling")
if (!errorHandlingModule.isError(frontEndInfo)) {
const authModule = await import("./auth")
- const keycloak = await authModule.getKeycloakInstance()
+ const keycloak = await authModule.getKeycloakInstance(frontEndInfo)
if (!errorHandlingModule.isError(keycloak)) {
const checksModule = await import("./checks")
const resultOrError =
@@ -139,8 +151,12 @@ export const renderModules = async () => {
}
if (timeoutDialog) {
+ const frontEndInfo = getFrontEndInfo()
const sessionTimeoutModule = await import("./auth/session-timeout")
- await sessionTimeoutModule.initialiseSessionTimeout()
+ const errorHandlingModule = await import("./errorhandling")
+ if (!errorHandlingModule.isError(frontEndInfo)) {
+ await sessionTimeoutModule.initialiseSessionTimeout(frontEndInfo)
+ }
}
if (fileSelectionTree) {
const trees: NodeListOf =
diff --git a/npm/tsconfig.json b/npm/tsconfig.json
index 4410f8835..0ebbb68f6 100644
--- a/npm/tsconfig.json
+++ b/npm/tsconfig.json
@@ -8,7 +8,7 @@
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"sourceMap": true,
- "moduleResolution": "node",
+ "moduleResolution": "bundler",
"strictFunctionTypes": true
},
"include": ["src/*"],
diff --git a/test/testUtils/CheckPageForStaticElements.scala b/test/testUtils/CheckPageForStaticElements.scala
index 7761cf83e..5524e5b3b 100644
--- a/test/testUtils/CheckPageForStaticElements.scala
+++ b/test/testUtils/CheckPageForStaticElements.scala
@@ -98,7 +98,11 @@ class CheckPageForStaticElements() {
"""
|
|
- |""".stripMargin
+ |
+ |
+ |
+ |
+ |""".stripMargin
)
}
}
diff --git a/test/testUtils/FrontEndTestHelper.scala b/test/testUtils/FrontEndTestHelper.scala
index 876b1f9cb..31666960e 100644
--- a/test/testUtils/FrontEndTestHelper.scala
+++ b/test/testUtils/FrontEndTestHelper.scala
@@ -871,7 +871,10 @@ trait FrontEndTestHelper extends PlaySpec with MockitoSugar with Injecting with
"https://mock-api-url.com/graphql",
"mockStage",
"mockRegion",
- "https://mock-upload-url.com"
+ "https://mock-upload-url.com",
+ "https://mock-auth-url.com",
+ "mockClientId",
+ "mockRealm"
)
)
frontEndInfoConfiguration