@rivm-loculus-tools/common-frontend 0.8.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_chunks/LoculusService.js +1049 -0
- package/dist/_chunks/LoculusService.js.map +1 -0
- package/dist/_chunks/decorateParam.js +7 -0
- package/dist/_chunks/keycloak-dpop.js +241 -0
- package/dist/_chunks/keycloak-dpop.js.map +1 -0
- package/dist/classes/services/EmotionCacheService/index.js +27 -1
- package/dist/classes/services/EmotionCacheService/index.js.map +1 -0
- package/dist/classes/services/LoculusService/LoculusService.d.ts +26 -0
- package/dist/classes/services/LoculusService/index.d.ts +1 -0
- package/dist/classes/services/LoculusService/index.js +1 -0
- package/dist/classes/services/UrlService/UrlService.d.ts +18 -0
- package/dist/classes/services/UrlService/index.d.ts +1 -0
- package/dist/classes/services/UrlService/index.js +45 -0
- package/dist/classes/services/UrlService/index.js.map +1 -0
- package/dist/components/app/App/App.d.ts +4 -2
- package/dist/components/app/App/index.js +35 -34
- package/dist/components/app/App/index.js.map +1 -1
- package/dist/components/authentication/AuthenticationLoader/AuthenticationLoader.d.ts +3 -0
- package/dist/components/authentication/AuthenticationLoader/index.d.ts +1 -0
- package/dist/components/authentication/AuthenticationLoader/index.js +31 -0
- package/dist/components/authentication/AuthenticationLoader/index.js.map +1 -0
- package/dist/components/fasta/FastaDataImportDialog/FastaDataImportDialog.d.ts +1 -0
- package/dist/components/fasta/FastaDataImportDialog/index.js +80 -80
- package/dist/components/fasta/FastaDataImportDialog/index.js.map +1 -1
- package/dist/components/fasta/FastaDataImportDialogLoader/FastaDataImportDialogLoader.d.ts +2 -1
- package/dist/components/fasta/FastaDataImportDialogLoader/index.js +61 -52
- package/dist/components/fasta/FastaDataImportDialogLoader/index.js.map +1 -1
- package/dist/components/fasta/FastaPageHeaderResetButton/index.js +27 -24
- package/dist/components/fasta/FastaPageHeaderResetButton/index.js.map +1 -1
- package/dist/components/loculus/UploadToLoculusModal/UploadToLoculusModal.d.ts +11 -0
- package/dist/components/loculus/UploadToLoculusModal/index.d.ts +1 -0
- package/dist/components/loculus/UploadToLoculusModal/index.js +159 -0
- package/dist/components/loculus/UploadToLoculusModal/index.js.map +1 -0
- package/dist/components/ui/ButtonWithMenu/ButtonWithMenu.d.ts +1 -0
- package/dist/components/ui/ButtonWithMenu/index.js +5 -4
- package/dist/components/ui/ButtonWithMenu/index.js.map +1 -1
- package/dist/components/ui/PageCommon/index.js +2 -2
- package/dist/components/ui/PageCommon/index.js.map +1 -1
- package/dist/components/ui/PageCommonDrawer/index.js +1 -1
- package/dist/components/ui/SearchBar/index.js +1 -0
- package/dist/components/ui/SearchBar/index.js.map +1 -1
- package/dist/constants/page.constants.d.ts +1 -1
- package/dist/constants/page.constants.js +1 -1
- package/dist/constants/page.constants.js.map +1 -1
- package/dist/models/url.models.d.ts +9 -0
- package/dist/models/url.models.js +0 -0
- package/dist/utils/MetaDataUtil/MetaDataUtil.d.ts +2 -1
- package/dist/utils/MetaDataUtil/index.js +5 -2
- package/dist/utils/MetaDataUtil/index.js.map +1 -1
- package/dist/utils/UrlUtil/UrlUtil.d.ts +2 -1
- package/dist/utils/UrlUtil/index.js +8 -5
- package/dist/utils/UrlUtil/index.js.map +1 -1
- package/package.json +23 -2
- package/dist/_chunks/EmotionCacheService.js +0 -32
- package/dist/_chunks/EmotionCacheService.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LoculusService.js","names":["_decorate","__decorate","emitted","logDeprecation","code","message","deprecatedBoundMethods","name","methods","original","instance","args","CONTENT_TYPE_JSON","Keycloak","#createLogger","config","isObject","requiredProperties","property","#logWarn","#config","#callbackStorage","createCallbackStorage","#adapter","initOptions","#loadAdapter","#useNonce","#loginIframe","#loadConfig","issuerUrl","#getIssuerUrl","#dpopProvider","DPoPSignatureProvider","BrowserSignatureAlgs","#logInfo","#check3pCookiesSupported","#processInit","type","#loadDefaultAdapter","#loadCordovaAdapter","#loadCordovaNativeAdapter","redirectUri","options","form","data","value","input","accountUrl","cordovaOpenWindowWrapper","loginUrl","target","shallowCloneCordovaOptions","userOptions","optionName","formatCordovaOptions","cordovaOptions","createCordovaOptions","getCordovaRedirectUri","ref","completed","closed","closeBrowser","event","callback","#parseCallback","#processCallback","resolve","error","reject","logoutUrl","registerUrl","oauth","jsonConfig","fetchJsonConfig","#setupEndpoints","#loadOidcConfig","url","stripTrailingSlash","openIdConfig","fetchOpenIdConfig","#getRealmUrl","oidcProvider","#setupOidcEndpoints","iframe","applyTimeoutToPromise","messageCallback","#setupCheckLoginIframe","doLogin","prompt","onLoad","#checkLoginIframe","#checkSsoSilently","#setToken","#scheduleCheckIframe","callbacks","authUrl","origin","result","src","#parseCallbackUrl","oauthState","newUrl","supportedParams","urlString","parsed","#parseCallbackParams","params","paramsString","oauthParams","param","entry","key","timeLocal","authSuccess","accessToken","refreshToken","idToken","errorData","response","#fetchAccessToken","waitForTimeout","state","createUUID","nonce","redirectUrl","appHash","callbackState","scope","scopeValues","buildClaimsParameter","codeVerifier","generateCodeVerifier","pkceChallenge","generatePkceChallenge","logoutMethod","access","role","resource","realmUrl","profile","fetchJSON","buildAuthorizationHeader","userInfo","expiresIn","minValidity","#refreshQueue","#fetchRefreshToken","p","NetworkError","promise","dpopProvider","init","requestUrl","method","resourceNonce","resp","#fetchWithDPoPProof","newNonce","wwwAuth","retryResp","retryNonce","body","clientId","pkceCodeVerifier","#fetchDPoPToken","tokenType","tokenResponse","proof","headers","fetchToken","fetchWithErrorHandling","#validateDPoPTokenType","ex","dpopNonce","decodeToken","token","fn","requestedAcr","generateRandomString","len","pkceMethod","bytesToBase64","sha256Digest","randomData","generateRandomData","chars","alphabet","timeoutHandle","timeoutPromise","errorMessage","timeout","LocalStorage","CookieStorage","STORAGE_KEY_PREFIX","#clearInvalidValues","#clearAllValues","currentTime","#getStoredEntries","expiry","#parseExpiry","parsedValue","#getCookie","#setCookie","#cookieExpiration","ca","i","c","cookie","expirationDate","exp","minutes","binString","bytes","payload","decoded","base64UrlDecode","output","b64DecodeUnicode","delay","_LoculusService","LoculusService","SubscribableAbstract","Subject","fasta","parsedFasta","FastaUtil","parsedRawFasta","rawFasta","hasMetadataMatch","metaData","recordsByValue","sequenceId","editedSequenceIds","sequence","originalSequenceIds","matchingSequences","matchingIds","metadataRows","record","MetaDataUtil","column","kwArgs","authenticated","initializedKeycloak","keycloak","authClientId","authRealm","authEndpoint","revisedSequences","returnUrl","organism","abortController","errorText","singleton"],"sources":["../../../../../node_modules/.pnpm/keycloak-js@26.2.5/node_modules/keycloak-js/lib/deprecations.js","../../../../../node_modules/.pnpm/keycloak-js@26.2.5/node_modules/keycloak-js/lib/keycloak.js","../../src/classes/services/LoculusService/LoculusService.ts"],"sourcesContent":["/** @type {Set<string>} */\nconst emitted = new Set()\n\n/**\n * Emit a deprecation warning. Each code is only warned once per page load.\n * @param {string} code Unique deprecation identifier (e.g. \"KC-DEP-001\").\n * @param {string} message Human-readable deprecation message.\n */\nexport function logDeprecation (code, message) {\n if (emitted.has(code)) {\n return\n }\n\n emitted.add(code)\n console.warn(`[KEYCLOAK] ${code}: ${message}`)\n}\n\n/**\n * Replaces each listed method on the instance with a bound wrapper that\n * emits a deprecation warning when called with an unbound `this`.\n * @param {object} instance\n * @param {string} code\n * @param {string[]} methods\n */\nexport function deprecatedBoundMethods (instance, code, methods) {\n for (const name of methods) {\n const original = instance[name]\n instance[name] = function (...args) {\n if (this !== instance) {\n logDeprecation(\n `${code}:${name}`,\n `Calling '${name}()' without a bound 'this' is deprecated and will stop working in a future major version.`\n )\n }\n return original.apply(instance, args)\n }\n }\n}\n","// @ts-check\n/**\n * @import {Acr, KeycloakAccountOptions, KeycloakAdapter, KeycloakConfig, KeycloakError, KeycloakFlow, KeycloakInitOptions, KeycloakLoginOptions, KeycloakLogoutOptions, KeycloakPkceMethod, KeycloakProfile, KeycloakRegisterOptions, KeycloakResourceAccess, KeycloakResponseMode, KeycloakResponseType, KeycloakRoles, KeycloakTokenParsed, OpenIdProviderMetadata} from \"./keycloak.ts\"\n */\n/*\n * Copyright 2016 Red Hat, Inc. and/or its affiliates\n * and other contributors as indicated by the @author tags.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { deprecatedBoundMethods, logDeprecation } from './deprecations.js'\n\nconst CONTENT_TYPE_JSON = 'application/json'\n\n/**\n * @typedef {Object} Endpoints\n * @property {() => string} authorize\n * @property {() => string} token\n * @property {() => string} logout\n * @property {() => string} checkSessionIframe\n * @property {() => string=} thirdPartyCookiesIframe\n * @property {() => string} register\n * @property {() => string} userinfo\n */\n\n/**\n * @typedef {Object} LoginIframe\n * @property {boolean} enable\n * @property {((error: Error | null, value?: boolean) => void)[]} callbackList\n * @property {number} interval\n * @property {HTMLIFrameElement=} iframe\n * @property {string=} iframeOrigin\n */\n\nexport default class Keycloak {\n /** @type {Pick<PromiseWithResolvers<boolean>, 'resolve' | 'reject'>[]} */\n #refreshQueue = []\n /** @type {KeycloakAdapter} */\n #adapter\n /** @type {boolean} */\n #useNonce = true\n /** @type {CallbackStorage} */\n #callbackStorage\n #logInfo = this.#createLogger(console.info)\n #logWarn = this.#createLogger(console.warn)\n /** @type {LoginIframe} */\n #loginIframe = {\n enable: true,\n callbackList: [],\n interval: 5\n }\n\n /** @type {import('./keycloak-dpop.js').DPoPSignatureProvider=} */\n #dpopProvider\n\n /** @type {KeycloakConfig} config */\n #config\n didInitialize = false\n authenticated = false\n loginRequired = false\n /** @type {KeycloakResponseMode} */\n responseMode = 'fragment'\n /** @type {KeycloakResponseType} */\n responseType = 'code'\n /** @type {KeycloakFlow} */\n flow = 'standard'\n /** @type {number?} */\n timeSkew = null\n /** @type {string=} */\n redirectUri\n /** @type {string=} */\n silentCheckSsoRedirectUri\n /** @type {boolean} */\n silentCheckSsoFallback = true\n /** @type {KeycloakPkceMethod} */\n pkceMethod = 'S256'\n enableLogging = false\n /** @type {'GET' | 'POST'} */\n logoutMethod = 'GET'\n /** @type {string=} */\n scope\n messageReceiveTimeout = 10000\n /** @type {string=} */\n idToken\n /** @type {KeycloakTokenParsed=} */\n idTokenParsed\n /** @type {string=} */\n token\n /** @type {KeycloakTokenParsed=} */\n tokenParsed\n /** @type {string=} */\n refreshToken\n /** @type {KeycloakTokenParsed=} */\n refreshTokenParsed\n /** @type {string=} */\n clientId\n /** @type {string=} */\n sessionId\n /** @type {string=} */\n subject\n /** @type {string=} */\n authServerUrl\n /** @type {string=} */\n realm\n /** @type {KeycloakRoles=} */\n realmAccess\n /** @type {KeycloakResourceAccess=} */\n resourceAccess\n /** @type {KeycloakProfile=} */\n profile\n /** @type {{}=} */\n userInfo\n /** @type {Endpoints} */\n endpoints\n /** @type {number=} */\n tokenTimeoutHandle\n /** @type {() => void=} */\n onAuthSuccess\n /** @type {(errorData?: KeycloakError) => void=} */\n onAuthError\n /** @type {() => void=} */\n onAuthRefreshSuccess\n /** @type {() => void=} */\n onAuthRefreshError\n /** @type {() => void=} */\n onTokenExpired\n /** @type {() => void=} */\n onAuthLogout\n /** @type {(authenticated: boolean) => void=} */\n onReady\n /** @type {(status: 'success' | 'cancelled' | 'error', action: string) => void=} */\n onActionUpdate\n\n /**\n * @param {KeycloakConfig} config\n */\n constructor (config) {\n if (typeof config !== 'string' && !isObject(config)) {\n throw new Error(\"The 'Keycloak' constructor must be provided with a configuration object, or a URL to a JSON configuration file.\")\n }\n\n if (isObject(config)) {\n const requiredProperties = 'oidcProvider' in config\n ? ['clientId']\n : ['url', 'realm', 'clientId']\n\n for (const property of requiredProperties) {\n if (!(property in config)) {\n throw new Error(`The configuration object is missing the required '${property}' property.`)\n }\n }\n }\n\n if (!globalThis.isSecureContext) {\n this.#logWarn(\n \"[KEYCLOAK] Keycloak JS must be used in a 'secure context' to function properly as it relies on browser APIs that are otherwise not available.\\n\" +\n 'Continuing to run your application insecurely will lead to unexpected behavior and breakage.\\n\\n' +\n 'For more information see: https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts'\n )\n }\n\n this.#config = config\n\n deprecatedBoundMethods(this, 'KC-DEP-003', [\n 'init', 'login', 'createLoginUrl', 'logout', 'createLogoutUrl', 'register',\n 'createRegisterUrl', 'createAccountUrl', 'accountManagement', 'hasRealmRole',\n 'hasResourceRole', 'loadUserProfile', 'loadUserInfo', 'isTokenExpired',\n 'updateToken', 'clearToken'\n ])\n }\n\n /**\n * @param {KeycloakInitOptions} initOptions\n * @returns {Promise<boolean>}\n */\n async init (initOptions = {}) {\n if (this.didInitialize) {\n throw new Error(\"A 'Keycloak' instance can only be initialized once.\")\n }\n\n this.didInitialize = true\n this.#callbackStorage = createCallbackStorage()\n\n const adapters = ['default', 'cordova', 'cordova-native']\n\n if (typeof initOptions.adapter === 'string' && adapters.includes(initOptions.adapter)) {\n this.#adapter = this.#loadAdapter(initOptions.adapter)\n } else if (typeof initOptions.adapter === 'object') {\n this.#adapter = initOptions.adapter\n } else if ('Cordova' in window || 'cordova' in window) {\n this.#adapter = this.#loadAdapter('cordova')\n } else {\n this.#adapter = this.#loadAdapter('default')\n }\n\n if (typeof initOptions.useNonce !== 'undefined') {\n this.#useNonce = initOptions.useNonce\n }\n\n if (typeof initOptions.checkLoginIframe !== 'undefined') {\n this.#loginIframe.enable = initOptions.checkLoginIframe\n }\n\n if (initOptions.checkLoginIframeInterval) {\n this.#loginIframe.interval = initOptions.checkLoginIframeInterval\n }\n\n if (initOptions.onLoad === 'login-required') {\n this.loginRequired = true\n }\n\n if (initOptions.responseMode) {\n if (initOptions.responseMode === 'query' || initOptions.responseMode === 'fragment') {\n this.responseMode = initOptions.responseMode\n } else {\n throw new Error('Invalid value for responseMode')\n }\n }\n\n if (initOptions.flow) {\n switch (initOptions.flow) {\n case 'standard':\n this.responseType = 'code'\n break\n case 'implicit':\n this.responseType = 'id_token token'\n break\n case 'hybrid':\n this.responseType = 'code id_token token'\n break\n default:\n throw new Error('Invalid value for flow')\n }\n this.flow = initOptions.flow\n }\n\n if (typeof initOptions.timeSkew === 'number') {\n this.timeSkew = initOptions.timeSkew\n }\n\n if (initOptions.redirectUri) {\n this.redirectUri = initOptions.redirectUri\n }\n\n if (initOptions.silentCheckSsoRedirectUri) {\n this.silentCheckSsoRedirectUri = initOptions.silentCheckSsoRedirectUri\n }\n\n if (typeof initOptions.silentCheckSsoFallback === 'boolean') {\n this.silentCheckSsoFallback = initOptions.silentCheckSsoFallback\n }\n\n if (typeof initOptions.pkceMethod !== 'undefined') {\n if (initOptions.pkceMethod !== 'S256' && initOptions.pkceMethod !== false) {\n throw new TypeError(`Invalid value for pkceMethod', expected 'S256' or false but got ${initOptions.pkceMethod}.`)\n }\n\n this.pkceMethod = initOptions.pkceMethod\n }\n\n if (typeof initOptions.enableLogging === 'boolean') {\n this.enableLogging = initOptions.enableLogging\n }\n\n if (initOptions.logoutMethod === 'POST') {\n this.logoutMethod = 'POST'\n }\n\n if (typeof initOptions.scope === 'string') {\n this.scope = initOptions.scope\n }\n\n if (typeof initOptions.messageReceiveTimeout === 'number' && initOptions.messageReceiveTimeout > 0) {\n this.messageReceiveTimeout = initOptions.messageReceiveTimeout\n }\n\n if (initOptions.dpopConfig) {\n this.dpopConfig = initOptions.dpopConfig\n }\n\n await this.#loadConfig()\n\n if (this.dpopConfig?.mode === 'strict' && (!this.dpopSigningAlgValuesSupported || this.dpopSigningAlgValuesSupported.length === 0)) {\n throw new Error('DPoP is set to strict mode but the server does not advertise DPoP support (dpop_signing_alg_values_supported is missing or empty).')\n }\n\n // Initialize DPoP if enabled and server supports it\n if (this.dpopConfig && this.dpopSigningAlgValuesSupported?.length) {\n const issuerUrl = this.#getIssuerUrl()\n if (!issuerUrl) throw new Error('Cannot initialize DPoP: issuer URL is not available. Ensure authServerUrl and realm are configured, or use OIDC provider mode with a valid issuer.')\n if (!this.clientId) throw new Error('Cannot initialize DPoP: clientId is not configured.')\n\n const { DPoPSignatureProvider, BrowserSignatureAlgs } = await import('./keycloak-dpop.js')\n this.#dpopProvider = new DPoPSignatureProvider({\n issuerUrl: new URL(issuerUrl),\n clientId: this.clientId,\n serverSupportedAlgorithms: this.dpopSigningAlgValuesSupported,\n requestedAlgorithm: !this.dpopConfig.alg ? BrowserSignatureAlgs.ES256 : BrowserSignatureAlgs[this.dpopConfig.alg],\n strictStorage: this.dpopConfig.strictStorage ?? false,\n getTimeSkew: () => this.timeSkew ?? 0\n })\n await this.#dpopProvider.init()\n this.#logInfo('[KEYCLOAK] DPoP initialized')\n }\n\n await this.#check3pCookiesSupported()\n await this.#processInit(initOptions)\n\n this.onReady?.(this.authenticated)\n\n return this.authenticated\n }\n\n /**\n * @param {\"default\" | \"cordova\" | \"cordova-native\"} type\n * @returns {KeycloakAdapter}\n */\n #loadAdapter (type) {\n if (type === 'default') {\n return this.#loadDefaultAdapter()\n }\n\n if (type === 'cordova') {\n logDeprecation('KC-DEP-001', \"The 'cordova' adapter is deprecated and will be removed in a future version. Use a custom adapter instead.\")\n this.#loginIframe.enable = false\n return this.#loadCordovaAdapter()\n }\n\n if (type === 'cordova-native') {\n logDeprecation('KC-DEP-002', \"The 'cordova-native' adapter is deprecated and will be removed in a future version. Use a custom adapter instead.\")\n this.#loginIframe.enable = false\n return this.#loadCordovaNativeAdapter()\n }\n\n throw new Error('invalid adapter type: ' + type)\n }\n\n /**\n * @returns {KeycloakAdapter}\n */\n #loadDefaultAdapter () {\n /** @type {KeycloakAdapter['redirectUri']}{} */\n const redirectUri = (options) => {\n return options?.redirectUri || this.redirectUri || globalThis.location.href\n }\n\n return {\n login: async (options) => {\n window.location.assign(await this.createLoginUrl(options))\n return await new Promise(() => {})\n },\n\n logout: async (options) => {\n const logoutMethod = options?.logoutMethod ?? this.logoutMethod\n\n if (logoutMethod === 'GET') {\n window.location.replace(this.createLogoutUrl(options))\n return\n }\n\n // Create form to send POST request.\n const form = document.createElement('form')\n\n form.setAttribute('method', 'POST')\n form.setAttribute('action', this.createLogoutUrl(options))\n form.style.display = 'none'\n\n // Add data to form as hidden input fields.\n const data = {\n id_token_hint: this.idToken,\n client_id: this.clientId,\n post_logout_redirect_uri: redirectUri(options)\n }\n\n for (const [name, value] of Object.entries(data)) {\n const input = document.createElement('input')\n\n input.setAttribute('type', 'hidden')\n input.setAttribute('name', name)\n input.setAttribute('value', /** @type {string} */ (value))\n\n form.appendChild(input)\n }\n\n // Append form to page and submit it to perform logout and redirect.\n document.body.appendChild(form)\n form.submit()\n },\n\n register: async (options) => {\n window.location.assign(await this.createRegisterUrl(options))\n return await new Promise(() => {})\n },\n\n accountManagement: async () => {\n const accountUrl = this.createAccountUrl()\n if (typeof accountUrl !== 'undefined') {\n window.location.href = accountUrl\n } else {\n throw new Error('Not supported by the OIDC server')\n }\n return await new Promise(() => {})\n },\n\n redirectUri\n }\n }\n\n /**\n * @returns {KeycloakAdapter}\n */\n #loadCordovaAdapter () {\n /**\n * @param {string} loginUrl\n * @param {string} target\n * @param {string} options\n * @returns {WindowProxy | null}\n */\n const cordovaOpenWindowWrapper = (loginUrl, target, options) => {\n if (window.cordova && window.cordova.InAppBrowser) {\n // Use inappbrowser for IOS and Android if available\n return window.cordova.InAppBrowser.open(loginUrl, target, options)\n } else {\n return window.open(loginUrl, target, options)\n }\n }\n\n const shallowCloneCordovaOptions = (userOptions) => {\n if (userOptions && userOptions.cordovaOptions) {\n return Object.keys(userOptions.cordovaOptions).reduce((options, optionName) => {\n options[optionName] = userOptions.cordovaOptions[optionName]\n return options\n }, {})\n } else {\n return {}\n }\n }\n\n const formatCordovaOptions = (cordovaOptions) => {\n return Object.keys(cordovaOptions).reduce((options, optionName) => {\n options.push(optionName + '=' + cordovaOptions[optionName])\n return options\n }, []).join(',')\n }\n\n const createCordovaOptions = (userOptions) => {\n const cordovaOptions = shallowCloneCordovaOptions(userOptions)\n cordovaOptions.location = 'no'\n if (userOptions && userOptions.prompt === 'none') {\n cordovaOptions.hidden = 'yes'\n }\n return formatCordovaOptions(cordovaOptions)\n }\n\n const getCordovaRedirectUri = () => {\n return this.redirectUri || 'http://localhost'\n }\n\n return {\n login: async (options) => {\n const cordovaOptions = createCordovaOptions(options)\n const loginUrl = await this.createLoginUrl(options)\n const ref = cordovaOpenWindowWrapper(loginUrl, '_blank', cordovaOptions)\n let completed = false\n let closed = false\n\n function closeBrowser () {\n closed = true\n ref.close()\n };\n\n return await new Promise((resolve, reject) => {\n ref.addEventListener('loadstart', async (event) => {\n if (event.url.indexOf(getCordovaRedirectUri()) === 0) {\n const callback = this.#parseCallback(event.url)\n completed = true\n closeBrowser()\n\n if (!callback || !callback.valid) {\n reject(new Error('Invalid OAuth state in login callback.'))\n return\n }\n\n try {\n await this.#processCallback(callback)\n resolve()\n } catch (error) {\n reject(error)\n }\n }\n })\n\n ref.addEventListener('loaderror', async (event) => {\n if (!completed) {\n if (event.url.indexOf(getCordovaRedirectUri()) === 0) {\n const callback = this.#parseCallback(event.url)\n completed = true\n closeBrowser()\n\n if (!callback || !callback.valid) {\n reject(new Error('Invalid OAuth state in login callback.'))\n return\n }\n\n try {\n await this.#processCallback(callback)\n resolve()\n } catch (error) {\n reject(error)\n }\n } else {\n reject(new Error('Unable to process login.'))\n closeBrowser()\n }\n }\n })\n\n ref.addEventListener('exit', function (event) {\n if (!closed) {\n reject(new Error('User closed the login window.'))\n }\n })\n })\n },\n\n logout: async (options) => {\n const logoutUrl = this.createLogoutUrl(options)\n const ref = cordovaOpenWindowWrapper(logoutUrl, '_blank', 'location=no,hidden=yes,clearcache=yes')\n let error = false\n\n ref.addEventListener('loadstart', (event) => {\n if (event.url.indexOf(getCordovaRedirectUri()) === 0) {\n ref.close()\n }\n })\n\n ref.addEventListener('loaderror', (event) => {\n if (event.url.indexOf(getCordovaRedirectUri()) === 0) {\n ref.close()\n } else {\n error = true\n ref.close()\n }\n })\n\n await new Promise((resolve, reject) => {\n ref.addEventListener('exit', () => {\n if (error) {\n reject(new Error('User closed the login window.'))\n } else {\n this.clearToken()\n resolve()\n }\n })\n })\n },\n\n register: async (options) => {\n const registerUrl = await this.createRegisterUrl()\n const cordovaOptions = createCordovaOptions(options)\n const ref = cordovaOpenWindowWrapper(registerUrl, '_blank', cordovaOptions)\n\n /** @type {Promise<void>} */\n const promise = new Promise((resolve, reject) => {\n ref.addEventListener('loadstart', async (event) => {\n if (event.url.indexOf(getCordovaRedirectUri()) === 0) {\n ref.close()\n const oauth = this.#parseCallback(event.url)\n\n if (!oauth || !oauth.valid) {\n reject(new Error('Invalid OAuth state in register callback.'))\n return\n }\n\n try {\n await this.#processCallback(oauth)\n resolve()\n } catch (error) {\n reject(error)\n }\n }\n })\n })\n\n await promise\n },\n\n accountManagement: async () => {\n const accountUrl = this.createAccountUrl()\n if (typeof accountUrl !== 'undefined') {\n const ref = cordovaOpenWindowWrapper(accountUrl, '_blank', 'location=no')\n ref.addEventListener('loadstart', function (event) {\n if (event.url.indexOf(getCordovaRedirectUri()) === 0) {\n ref.close()\n }\n })\n } else {\n throw new Error('Not supported by the OIDC server')\n }\n },\n\n redirectUri: () => {\n return getCordovaRedirectUri()\n }\n }\n }\n\n /**\n * @returns {KeycloakAdapter}\n */\n #loadCordovaNativeAdapter () {\n /* global universalLinks */\n return {\n login: async (options) => {\n const loginUrl = await this.createLoginUrl(options)\n\n await new Promise((resolve, reject) => {\n universalLinks.subscribe('keycloak', async (event) => {\n universalLinks.unsubscribe('keycloak')\n window.cordova.plugins.browsertab.close()\n const oauth = this.#parseCallback(event.url)\n\n if (!oauth || !oauth.valid) {\n reject(new Error('Invalid OAuth state in login callback.'))\n return\n }\n\n try {\n await this.#processCallback(oauth)\n resolve()\n } catch (error) {\n reject(error)\n }\n })\n\n window.cordova.plugins.browsertab.openUrl(loginUrl)\n })\n },\n\n logout: async (options) => {\n const logoutUrl = this.createLogoutUrl(options)\n\n await new Promise((resolve) => {\n universalLinks.subscribe('keycloak', () => {\n universalLinks.unsubscribe('keycloak')\n window.cordova.plugins.browsertab.close()\n this.clearToken()\n resolve()\n })\n\n window.cordova.plugins.browsertab.openUrl(logoutUrl)\n })\n },\n\n register: async (options) => {\n const registerUrl = await this.createRegisterUrl(options)\n\n await new Promise((resolve, reject) => {\n universalLinks.subscribe('keycloak', async (event) => {\n universalLinks.unsubscribe('keycloak')\n window.cordova.plugins.browsertab.close()\n const oauth = this.#parseCallback(event.url)\n\n if (!oauth || !oauth.valid) {\n reject(new Error('Invalid OAuth state in register callback.'))\n return\n }\n\n try {\n await this.#processCallback(oauth)\n resolve()\n } catch (error) {\n reject(error)\n }\n })\n\n window.cordova.plugins.browsertab.openUrl(registerUrl)\n })\n },\n\n accountManagement: async () => {\n const accountUrl = this.createAccountUrl()\n if (typeof accountUrl !== 'undefined') {\n window.cordova.plugins.browsertab.openUrl(accountUrl)\n } else {\n throw new Error('Not supported by the OIDC server')\n }\n },\n\n redirectUri: (options) => {\n if (options && options.redirectUri) {\n return options.redirectUri\n } else if (this.redirectUri) {\n return this.redirectUri\n } else {\n return 'http://localhost'\n }\n }\n }\n }\n\n /**\n * @returns {Promise<void>}\n */\n async #loadConfig () {\n if (typeof this.#config === 'string') {\n const jsonConfig = await fetchJsonConfig(this.#config)\n this.authServerUrl = jsonConfig['auth-server-url']\n this.realm = jsonConfig.realm\n this.clientId = jsonConfig.resource\n await this.#setupEndpoints()\n } else {\n this.clientId = this.#config.clientId\n\n if ('oidcProvider' in this.#config) {\n await this.#loadOidcConfig(this.#config.oidcProvider)\n } else {\n this.authServerUrl = this.#config.url\n this.realm = this.#config.realm\n await this.#setupEndpoints()\n }\n }\n }\n\n /**\n * @returns {Promise<void>}\n */\n async #setupEndpoints () {\n // Fetch OIDC metadata to get DPoP supported algorithms (only if DPoP is enabled)\n if (this.dpopConfig) {\n const issuerUrl = this.#getIssuerUrl()\n if (!issuerUrl) {\n this.#logWarn('[KEYCLOAK] Cannot fetch OIDC metadata: issuer URL is not available')\n } else {\n const url = `${stripTrailingSlash(issuerUrl)}/.well-known/openid-configuration`\n try {\n const openIdConfig = await fetchOpenIdConfig(url)\n this.dpopSigningAlgValuesSupported = openIdConfig.dpop_signing_alg_values_supported ? openIdConfig.dpop_signing_alg_values_supported : undefined\n } catch (error) {\n this.#logWarn('[KEYCLOAK] Failed to fetch OIDC metadata for DPoP configuration: ' + (error instanceof Error ? error.message : error))\n }\n }\n }\n\n this.endpoints = {\n authorize: () => {\n return this.#getRealmUrl() + '/protocol/openid-connect/auth'\n },\n token: () => {\n return this.#getRealmUrl() + '/protocol/openid-connect/token'\n },\n logout: () => {\n return this.#getRealmUrl() + '/protocol/openid-connect/logout'\n },\n checkSessionIframe: () => {\n return this.#getRealmUrl() + '/protocol/openid-connect/login-status-iframe.html'\n },\n thirdPartyCookiesIframe: () => {\n return this.#getRealmUrl() + '/protocol/openid-connect/3p-cookies/step1.html'\n },\n register: () => {\n return this.#getRealmUrl() + '/protocol/openid-connect/registrations'\n },\n userinfo: () => {\n return this.#getRealmUrl() + '/protocol/openid-connect/userinfo'\n }\n }\n }\n\n /**\n * @param {string | OpenIdProviderMetadata} oidcProvider\n * @returns {Promise<void>}\n */\n async #loadOidcConfig (oidcProvider) {\n if (typeof oidcProvider === 'string') {\n const url = `${stripTrailingSlash(oidcProvider)}/.well-known/openid-configuration`\n const openIdConfig = await fetchOpenIdConfig(url)\n this.#setupOidcEndpoints(openIdConfig)\n } else {\n this.#setupOidcEndpoints(oidcProvider)\n }\n }\n\n /**\n * @param {OpenIdProviderMetadata} config\n * @returns {void}\n */\n #setupOidcEndpoints (config) {\n // Store DPoP supported algorithms if present\n this.dpopSigningAlgValuesSupported = config.dpop_signing_alg_values_supported\n this.issuer = config.issuer\n this.endpoints = {\n authorize () {\n return config.authorization_endpoint\n },\n token () {\n return config.token_endpoint\n },\n logout () {\n if (!config.end_session_endpoint) {\n throw new Error('Not supported by the OIDC server')\n }\n return config.end_session_endpoint\n },\n checkSessionIframe () {\n if (!config.check_session_iframe) {\n throw new Error('Not supported by the OIDC server')\n }\n return config.check_session_iframe\n },\n register () {\n throw new Error('Redirection to \"Register user\" page not supported in standard OIDC mode')\n },\n userinfo () {\n if (!config.userinfo_endpoint) {\n throw new Error('Not supported by the OIDC server')\n }\n return config.userinfo_endpoint\n }\n }\n }\n\n /**\n * @returns {Promise<void>}\n */\n async #check3pCookiesSupported () {\n if ((!this.#loginIframe.enable && !this.silentCheckSsoRedirectUri) || typeof this.endpoints.thirdPartyCookiesIframe !== 'function') {\n return\n }\n\n const iframe = document.createElement('iframe')\n iframe.setAttribute('src', this.endpoints.thirdPartyCookiesIframe())\n iframe.setAttribute('sandbox', 'allow-storage-access-by-user-activation allow-scripts allow-same-origin')\n iframe.setAttribute('title', 'keycloak-3p-check-iframe')\n iframe.style.display = 'none'\n document.body.appendChild(iframe)\n\n /** @type {Promise<void>} */\n const promise = new Promise((resolve) => {\n /**\n * @param {MessageEvent} event\n */\n const messageCallback = (event) => {\n if (iframe.contentWindow !== event.source) {\n return\n }\n\n if (event.data !== 'supported' && event.data !== 'unsupported') {\n return\n } else if (event.data === 'unsupported') {\n this.#logWarn(\n '[KEYCLOAK] Your browser is blocking access to 3rd-party cookies, this means:\\n\\n' +\n ' - It is not possible to retrieve tokens without redirecting to the Keycloak server (a.k.a. no support for silent authentication).\\n' +\n ' - It is not possible to automatically detect changes to the session status (such as the user logging out in another tab).\\n\\n' +\n 'For more information see: https://www.keycloak.org/securing-apps/javascript-adapter#_modern_browsers'\n )\n\n this.#loginIframe.enable = false\n if (this.silentCheckSsoFallback) {\n this.silentCheckSsoRedirectUri = undefined\n }\n }\n\n document.body.removeChild(iframe)\n window.removeEventListener('message', messageCallback)\n resolve()\n }\n\n window.addEventListener('message', messageCallback, false)\n })\n\n return await applyTimeoutToPromise(promise, this.messageReceiveTimeout, 'Timeout when waiting for 3rd party check iframe message.')\n }\n\n /**\n * @param {KeycloakInitOptions} initOptions\n * @returns {Promise<void>}\n */\n async #processInit (initOptions) {\n const callback = this.#parseCallback(window.location.href)\n\n if (callback?.newUrl) {\n window.history.replaceState(window.history.state, '', callback.newUrl)\n }\n\n if (callback && callback.valid) {\n await this.#setupCheckLoginIframe()\n await this.#processCallback(callback)\n return\n }\n\n /** @param {boolean} prompt */\n const doLogin = async (prompt) => {\n /** @type {KeycloakLoginOptions} */\n const options = {}\n\n if (!prompt) {\n options.prompt = 'none'\n }\n\n if (initOptions.locale) {\n options.locale = initOptions.locale\n }\n\n await this.login(options)\n }\n\n const onLoad = async () => {\n switch (initOptions.onLoad) {\n case 'check-sso':\n if (this.#loginIframe.enable) {\n await this.#setupCheckLoginIframe()\n const unchanged = await this.#checkLoginIframe()\n\n if (!unchanged) {\n this.silentCheckSsoRedirectUri ? await this.#checkSsoSilently() : await doLogin(false)\n }\n } else {\n this.silentCheckSsoRedirectUri ? await this.#checkSsoSilently() : await doLogin(false)\n }\n break\n case 'login-required':\n await doLogin(true)\n break\n default:\n throw new Error('Invalid value for onLoad')\n }\n }\n\n if (initOptions.token && initOptions.refreshToken) {\n this.#setToken(initOptions.token, initOptions.refreshToken, initOptions.idToken)\n\n if (this.#loginIframe.enable) {\n await this.#setupCheckLoginIframe()\n const unchanged = await this.#checkLoginIframe()\n\n if (unchanged) {\n this.onAuthSuccess?.()\n this.#scheduleCheckIframe()\n }\n } else {\n try {\n await this.updateToken(-1)\n this.onAuthSuccess?.()\n } catch (error) {\n this.onAuthError?.()\n if (initOptions.onLoad) {\n await onLoad()\n } else {\n throw error\n }\n }\n }\n } else if (initOptions.onLoad) {\n await onLoad()\n }\n }\n\n /**\n * @returns {Promise<void>}\n */\n async #setupCheckLoginIframe () {\n if (!this.#loginIframe.enable || this.#loginIframe.iframe) {\n return\n }\n\n const iframe = document.createElement('iframe')\n this.#loginIframe.iframe = iframe\n iframe.setAttribute('src', this.endpoints.checkSessionIframe())\n iframe.setAttribute('sandbox', 'allow-storage-access-by-user-activation allow-scripts allow-same-origin')\n iframe.setAttribute('title', 'keycloak-session-iframe')\n iframe.style.display = 'none'\n document.body.appendChild(iframe)\n\n /**\n * @param {MessageEvent} event\n */\n const messageCallback = (event) => {\n if (event.origin !== this.#loginIframe.iframeOrigin || this.#loginIframe.iframe?.contentWindow !== event.source) {\n return\n }\n\n if (!(event.data === 'unchanged' || event.data === 'changed' || event.data === 'error')) {\n return\n }\n\n if (event.data !== 'unchanged') {\n this.clearToken()\n }\n\n const callbacks = this.#loginIframe.callbackList\n this.#loginIframe.callbackList = []\n\n for (const callback of callbacks.reverse()) {\n if (event.data === 'error') {\n callback(new Error('Error while checking login iframe'))\n } else {\n callback(null, event.data === 'unchanged')\n }\n }\n }\n\n window.addEventListener('message', messageCallback, false)\n\n /** @type {Promise<void>} */\n const promise = new Promise((resolve) => {\n iframe.addEventListener('load', () => {\n const authUrl = this.endpoints.authorize()\n if (authUrl.startsWith('/')) {\n this.#loginIframe.iframeOrigin = globalThis.location.origin\n } else {\n this.#loginIframe.iframeOrigin = new URL(authUrl).origin\n }\n resolve()\n })\n })\n\n await promise\n }\n\n /**\n * @returns {Promise<boolean | undefined>}\n */\n async #checkLoginIframe () {\n if (!this.#loginIframe.iframe || !this.#loginIframe.iframeOrigin) {\n return\n }\n\n const message = `${this.clientId} ${(this.sessionId ? this.sessionId : '')}`\n const origin = this.#loginIframe.iframeOrigin\n\n /** @type {Promise<boolean>} */\n const promise = new Promise((resolve, reject) => {\n /** @type {(error: Error | null, value?: boolean) => void} */\n const callback = (error, result) => error ? reject(error) : resolve(/** @type {boolean} */ (result))\n\n this.#loginIframe.callbackList.push(callback)\n\n if (this.#loginIframe.callbackList.length === 1) {\n this.#loginIframe.iframe?.contentWindow?.postMessage(message, origin)\n }\n })\n\n return await promise\n }\n\n /**\n * @returns {Promise<void>}\n */\n async #checkSsoSilently () {\n const iframe = document.createElement('iframe')\n const src = await this.createLoginUrl({ prompt: 'none', redirectUri: this.silentCheckSsoRedirectUri })\n iframe.setAttribute('src', src)\n iframe.setAttribute('sandbox', 'allow-storage-access-by-user-activation allow-scripts allow-same-origin')\n iframe.setAttribute('title', 'keycloak-silent-check-sso')\n iframe.style.display = 'none'\n document.body.appendChild(iframe)\n\n return await new Promise((resolve, reject) => {\n /**\n * @param {MessageEvent} event\n */\n const messageCallback = async (event) => {\n if (event.origin !== window.location.origin || iframe.contentWindow !== event.source) {\n return\n }\n\n const oauth = this.#parseCallback(event.data)\n\n try {\n await this.#processCallback(oauth)\n resolve()\n } catch (error) {\n reject(error)\n }\n\n document.body.removeChild(iframe)\n window.removeEventListener('message', messageCallback)\n }\n\n window.addEventListener('message', messageCallback)\n })\n };\n\n /**\n * @param {string} url\n */\n #parseCallback (url) {\n const oauth = this.#parseCallbackUrl(url)\n if (!oauth) {\n return\n }\n\n const oauthState = this.#callbackStorage.get(oauth.state)\n\n if (oauthState) {\n oauth.valid = true\n oauth.redirectUri = oauthState.redirectUri\n oauth.storedNonce = oauthState.nonce\n oauth.prompt = oauthState.prompt\n oauth.pkceCodeVerifier = oauthState.pkceCodeVerifier\n oauth.loginOptions = oauthState.loginOptions\n\n if (oauthState.appHash) {\n const newUrl = new URL(oauth.newUrl || url)\n newUrl.hash = oauthState.appHash\n oauth.newUrl = newUrl.href\n }\n }\n\n return oauth\n }\n\n /**\n * @param {string} urlString\n */\n #parseCallbackUrl (urlString) {\n let supportedParams = []\n switch (this.flow) {\n case 'standard':\n supportedParams = ['code', 'state', 'session_state', 'kc_action_status', 'kc_action', 'iss']\n break\n case 'implicit':\n supportedParams = ['access_token', 'token_type', 'id_token', 'state', 'session_state', 'expires_in', 'kc_action_status', 'kc_action', 'iss']\n break\n case 'hybrid':\n supportedParams = ['access_token', 'token_type', 'id_token', 'code', 'state', 'session_state', 'expires_in', 'kc_action_status', 'kc_action', 'iss']\n break\n }\n\n supportedParams.push('error')\n supportedParams.push('error_description')\n supportedParams.push('error_uri')\n\n const url = new URL(urlString)\n let newUrl = ''\n let parsed\n\n if (this.responseMode === 'query' && url.searchParams.size > 0) {\n parsed = this.#parseCallbackParams(url.search, supportedParams)\n url.search = parsed.paramsString\n newUrl = url.toString()\n } else if (this.responseMode === 'fragment' && url.hash.length > 0) {\n parsed = this.#parseCallbackParams(url.hash.substring(1), supportedParams)\n url.hash = parsed.paramsString\n newUrl = url.toString()\n }\n\n if (parsed?.oauthParams) {\n if (this.flow === 'standard' || this.flow === 'hybrid') {\n if ((parsed.oauthParams.code || parsed.oauthParams.error) && parsed.oauthParams.state) {\n parsed.oauthParams.newUrl = newUrl\n return parsed.oauthParams\n }\n } else if (this.flow === 'implicit') {\n if ((parsed.oauthParams.access_token || parsed.oauthParams.error) && parsed.oauthParams.state) {\n parsed.oauthParams.newUrl = newUrl\n return parsed.oauthParams\n }\n }\n }\n }\n\n /**\n * @typedef {Object} ParsedCallbackParams\n * @property {string} paramsString\n * @property {Record<string, string | undefined>} oauthParams\n */\n\n /**\n * @param {string} paramsString\n * @param {string[]} supportedParams\n * @returns {ParsedCallbackParams}\n */\n #parseCallbackParams (paramsString, supportedParams) {\n const params = paramsString.split('&')\n /** @type {Record<string, string>} */\n const oauthParams = {}\n let result = ''\n\n for (const param of params.reverse()) {\n const entry = new URLSearchParams(param).entries().next().value\n\n if (!entry) {\n result = '&' + result\n continue\n }\n\n const [key, value] = entry\n\n if (supportedParams.includes(key) && !(key in oauthParams)) {\n oauthParams[key] = value\n } else {\n result = result.length === 0 ? param : param + '&' + result\n }\n }\n\n return {\n paramsString: result,\n oauthParams\n }\n }\n\n async #processCallback (oauth) {\n const { code, error, prompt } = oauth\n let timeLocal = new Date().getTime()\n\n /**\n * @param {string} accessToken\n * @param {string=} refreshToken\n * @param {string=} idToken\n */\n const authSuccess = (accessToken, refreshToken, idToken) => {\n timeLocal = (timeLocal + new Date().getTime()) / 2\n\n this.#setToken(accessToken, refreshToken, idToken, timeLocal)\n\n if (this.#useNonce && (this.idTokenParsed && this.idTokenParsed.nonce !== oauth.storedNonce)) {\n this.#logInfo('[KEYCLOAK] Invalid nonce, clearing token')\n this.clearToken()\n throw new Error('Invalid nonce.')\n }\n }\n\n if (oauth.kc_action_status) {\n this.onActionUpdate && this.onActionUpdate(oauth.kc_action_status, oauth.kc_action)\n }\n\n if (error) {\n if (prompt !== 'none') {\n if (oauth.error_description && oauth.error_description === 'authentication_expired') {\n await this.login(oauth.loginOptions)\n } else {\n const errorData = { error, error_description: oauth.error_description }\n this.onAuthError?.(errorData)\n throw errorData\n }\n }\n return\n } else if ((this.flow !== 'standard') && (oauth.access_token || oauth.id_token)) {\n authSuccess(oauth.access_token, undefined, oauth.id_token)\n this.onAuthSuccess?.()\n }\n\n if ((this.flow !== 'implicit') && code) {\n try {\n const response = await this.#fetchAccessToken(this.endpoints.token(), code, /** @type {string} */ (this.clientId), oauth.redirectUri, oauth.pkceCodeVerifier)\n authSuccess(response.access_token, response.refresh_token, response.id_token)\n\n if (this.flow === 'standard') {\n this.onAuthSuccess?.()\n }\n\n this.#scheduleCheckIframe()\n } catch (error) {\n this.onAuthError?.()\n throw error\n }\n }\n }\n\n async #scheduleCheckIframe () {\n if (this.#loginIframe.enable && this.token) {\n await waitForTimeout(this.#loginIframe.interval * 1000)\n const unchanged = await this.#checkLoginIframe()\n\n if (unchanged) {\n await this.#scheduleCheckIframe()\n }\n }\n }\n\n /**\n * @param {KeycloakLoginOptions} [options]\n * @returns {Promise<void>}\n */\n login (options) {\n return this.#adapter.login(options)\n }\n\n /**\n * @param {KeycloakLoginOptions} [options]\n * @returns {Promise<string>}\n */\n async createLoginUrl (options) {\n const state = createUUID()\n const nonce = createUUID()\n // OAuth 2.0 forbids a fragment in redirect_uri (RFC 6749 §3.1.2). Keycloak also\n // rejects redirect URIs that place OIDC response parameters in the fragment.\n // Preserve the application hash in callback storage and restore it after login.\n const redirectUrl = new URL(this.#adapter.redirectUri(options), globalThis.location?.href)\n const appHash = redirectUrl.hash\n redirectUrl.hash = ''\n const redirectUri = redirectUrl.href\n /** @type {CallbackState} */\n const callbackState = {\n state,\n nonce,\n redirectUri,\n appHash,\n loginOptions: options\n }\n\n if (options?.prompt) {\n callbackState.prompt = options.prompt\n }\n\n const url = options?.action === 'register'\n ? this.endpoints.register()\n : this.endpoints.authorize()\n\n let scope = options?.scope || this.scope\n const scopeValues = scope ? scope.split(' ') : []\n\n // Ensure the 'openid' scope is always included.\n if (!scopeValues.includes('openid')) {\n scopeValues.unshift('openid')\n }\n\n scope = scopeValues.join(' ')\n\n const params = new URLSearchParams([\n ['client_id', /** @type {string} */ (this.clientId)],\n ['redirect_uri', redirectUri],\n ['state', state],\n ['response_mode', this.responseMode],\n ['response_type', this.responseType],\n ['scope', scope]\n ])\n\n if (this.#useNonce) {\n params.append('nonce', nonce)\n }\n\n if (options?.prompt) {\n params.append('prompt', options.prompt)\n }\n\n if (typeof options?.maxAge === 'number') {\n params.append('max_age', options.maxAge.toString())\n }\n\n if (options?.loginHint) {\n params.append('login_hint', options.loginHint)\n }\n\n if (options?.idpHint) {\n params.append('kc_idp_hint', options.idpHint)\n }\n\n if (options?.action && options.action !== 'register') {\n params.append('kc_action', options.action)\n }\n\n if (options?.locale) {\n params.append('ui_locales', options.locale)\n }\n\n if (options?.acr) {\n params.append('claims', buildClaimsParameter(options.acr))\n }\n\n if (options?.acrValues) {\n params.append('acr_values', options.acrValues)\n }\n\n if (this.pkceMethod) {\n try {\n const codeVerifier = generateCodeVerifier(96)\n const pkceChallenge = await generatePkceChallenge(this.pkceMethod, codeVerifier)\n\n callbackState.pkceCodeVerifier = codeVerifier\n\n params.append('code_challenge', pkceChallenge)\n params.append('code_challenge_method', this.pkceMethod)\n } catch (error) {\n throw new Error('Failed to generate PKCE challenge.', { cause: error })\n }\n }\n\n this.#callbackStorage.add(callbackState)\n\n return `${url}?${params.toString()}`\n }\n\n /**\n * @param {KeycloakLogoutOptions} [options]\n * @returns {Promise<void>}\n */\n async logout (options) {\n await this.#dpopProvider?.flush()\n return this.#adapter.logout(options)\n }\n\n /**\n * @param {KeycloakLogoutOptions} [options]\n * @returns {string}\n */\n createLogoutUrl (options) {\n const logoutMethod = options?.logoutMethod ?? this.logoutMethod\n const url = this.endpoints.logout()\n\n if (logoutMethod === 'POST') {\n return url\n }\n\n const params = new URLSearchParams([\n ['client_id', /** @type {string} */ (this.clientId)],\n ['post_logout_redirect_uri', this.#adapter.redirectUri(options)]\n ])\n\n if (this.idToken) {\n params.append('id_token_hint', this.idToken)\n }\n\n return `${url}?${params.toString()}`\n }\n\n /**\n * @param {KeycloakRegisterOptions} [options]\n * @returns {Promise<void>}\n */\n register (options) {\n return this.#adapter.register(options)\n }\n\n /**\n * @param {KeycloakRegisterOptions} [options]\n * @returns {Promise<string>}\n */\n createRegisterUrl (options) {\n return this.createLoginUrl({ ...options, action: 'register' })\n }\n\n /**\n * @param {KeycloakAccountOptions} [options]\n * @returns {string}\n */\n createAccountUrl (options) {\n const url = this.#getRealmUrl()\n\n if (!url) {\n throw new Error('Unable to create account URL, make sure the adapter is not configured using a generic OIDC provider.')\n }\n\n const params = new URLSearchParams([\n ['referrer', /** @type {string} */ (this.clientId)],\n ['referrer_uri', this.#adapter.redirectUri(options)]\n ])\n\n return `${url}/account?${params.toString()}`\n }\n\n /**\n * @returns {Promise<void>}\n */\n accountManagement () {\n return this.#adapter.accountManagement()\n }\n\n /**\n * @param {string} role\n * @returns {boolean}\n */\n hasRealmRole (role) {\n const access = this.realmAccess\n return !!access && access.roles.indexOf(role) >= 0\n }\n\n /**\n * @param {string} role\n * @param {string} [resource]\n * @returns {boolean}\n */\n hasResourceRole (role, resource) {\n if (!this.resourceAccess) {\n return false\n }\n\n const access = this.resourceAccess[resource || /** @type {string} */ (this.clientId)]\n return !!access && access.roles.indexOf(role) >= 0\n }\n\n /**\n * @returns {Promise<KeycloakProfile>}\n */\n async loadUserProfile () {\n const realmUrl = this.#getRealmUrl()\n\n if (!realmUrl) {\n throw new Error('Unable to load user profile, make sure the adapter is not configured using a generic OIDC provider.')\n }\n\n const url = `${realmUrl}/account`\n /** @type {KeycloakProfile} */\n const profile = await fetchJSON(url, {\n headers: [buildAuthorizationHeader(this.token)]\n })\n\n return (this.profile = profile)\n }\n\n /**\n * @returns {Promise<{}>}\n */\n async loadUserInfo () {\n const url = this.endpoints.userinfo()\n /** @type {{}} */\n const userInfo = await fetchJSON(url, {\n headers: [buildAuthorizationHeader(this.token)]\n })\n\n return (this.userInfo = userInfo)\n }\n\n /**\n * @param {number} [minValidity]\n * @returns {boolean}\n */\n isTokenExpired (minValidity) {\n if (!this.tokenParsed || (!this.refreshToken && this.flow !== 'implicit')) {\n throw new Error('Not authenticated')\n }\n\n if (this.timeSkew == null) {\n this.#logInfo('[KEYCLOAK] Unable to determine if token is expired as timeskew is not set')\n return true\n }\n\n if (typeof this.tokenParsed.exp !== 'number') {\n return false\n }\n\n let expiresIn = this.tokenParsed.exp - Math.ceil(new Date().getTime() / 1000) + this.timeSkew\n if (minValidity) {\n if (isNaN(minValidity)) {\n throw new Error('Invalid minValidity')\n }\n expiresIn -= minValidity\n }\n return expiresIn < 0\n }\n\n /**\n * @param {number} minValidity\n * @returns {Promise<boolean>}\n */\n async updateToken (minValidity) {\n if (!this.refreshToken) {\n throw new Error('Unable to update token, no refresh token available.')\n }\n\n minValidity = minValidity || 5\n\n if (this.#loginIframe.enable) {\n await this.#checkLoginIframe()\n }\n\n let refreshToken = false\n\n if (minValidity === -1) {\n refreshToken = true\n this.#logInfo('[KEYCLOAK] Refreshing token: forced refresh')\n } else if (!this.tokenParsed || this.isTokenExpired(minValidity)) {\n refreshToken = true\n this.#logInfo('[KEYCLOAK] Refreshing token: token expired')\n }\n\n if (!refreshToken) {\n return false\n }\n\n /** @type {PromiseWithResolvers<boolean>} */\n const { promise, resolve, reject } = Promise.withResolvers()\n\n this.#refreshQueue.push({ resolve, reject })\n\n if (this.#refreshQueue.length === 1) {\n const url = this.endpoints.token()\n let timeLocal = new Date().getTime()\n\n try {\n const response = await this.#fetchRefreshToken(url, this.refreshToken, /** @type {string} */ (this.clientId))\n this.#logInfo('[KEYCLOAK] Token refreshed')\n\n timeLocal = (timeLocal + new Date().getTime()) / 2\n\n this.#setToken(response.access_token, response.refresh_token, response.id_token, timeLocal)\n\n this.onAuthRefreshSuccess?.()\n for (let p = this.#refreshQueue.pop(); p != null; p = this.#refreshQueue.pop()) {\n p.resolve(true)\n }\n } catch (error) {\n this.#logWarn('[KEYCLOAK] Failed to refresh token')\n\n if (error instanceof NetworkError && error.response.status === 400) {\n this.clearToken()\n }\n\n this.onAuthRefreshError?.()\n for (let p = this.#refreshQueue.pop(); p != null; p = this.#refreshQueue.pop()) {\n p.reject(error)\n }\n }\n }\n\n return await promise\n }\n\n async clearToken () {\n if (this.token) {\n await this.#dpopProvider?.flush()\n await this.#dpopProvider?.init()\n this.#setToken()\n this.onAuthLogout?.()\n if (this.loginRequired) {\n await this.login()\n }\n }\n }\n\n fetch = async (url, init = {}) => {\n const dpopProvider = this.#dpopProvider\n if (dpopProvider && this.authenticated && this.token) {\n const existingAuth = new Headers(init.headers).get('Authorization')\n const isOurBearerToken = existingAuth === `Bearer ${this.token}`\n\n if (!isOurBearerToken) {\n // Quick escape - didn't put this check in first if statement as it's more expensive than other checks\n return fetch(url, init)\n }\n\n const requestUrl = new URL(String(url), document.baseURI)\n const urlString = requestUrl.href\n const origin = requestUrl.origin\n const method = init.method ?? 'GET'\n const resourceNonce = dpopProvider.getResourceServerNonce(origin)\n const resp = await this.#fetchWithDPoPProof(url, init, urlString, method, resourceNonce)\n\n // Check for new nonce in response\n const newNonce = resp.headers.get('DPoP-Nonce')\n if (newNonce) {\n dpopProvider.updateResourceServerNonce(origin, newNonce)\n }\n\n // https://datatracker.ietf.org/doc/html/rfc9449#section-9\n // Resource servers signal via: WWW-Authenticate: DPoP error=\"use_dpop_nonce\"\n if (resp.status === 401 && newNonce) {\n const wwwAuth = resp.headers.get('WWW-Authenticate') ?? ''\n if (wwwAuth.includes('DPoP') && wwwAuth.includes('error=\"use_dpop_nonce\"')) {\n const retryResp = await this.#fetchWithDPoPProof(url, init, urlString, method, newNonce)\n // Capture nonce from retry response for future requests\n const retryNonce = retryResp.headers.get('DPoP-Nonce')\n if (retryNonce) {\n dpopProvider.updateResourceServerNonce(origin, retryNonce)\n }\n return retryResp\n }\n }\n return resp\n } else {\n return fetch(url, init)\n }\n }\n\n /**\n * @typedef {Object} AccessTokenResponse The successful token response from the authorization server, based on the {@link https://datatracker.ietf.org/doc/html/rfc6749#section-5.1 OAuth 2.0 Authorization Framework specification}.\n * @property {string} access_token The access token issued by the authorization server.\n * @property {string} token_type The type of the token issued by the authorization server.\n * @property {number} [expires_in] The lifetime in seconds of the access token.\n * @property {string} [refresh_token] The refresh token issued by the authorization server.\n * @property {string} [id_token] The ID token issued by the authorization server, if requested.\n * @property {string} [scope] The scope of the access token.\n */\n\n /**\n * Fetch the access token from the given URL.\n * @param {string} url\n * @param {string} code\n * @param {string} clientId\n * @param {string} redirectUri\n * @param {string} [pkceCodeVerifier]\n * @returns {Promise<AccessTokenResponse>}\n */\n async #fetchAccessToken (url, code, clientId, redirectUri, pkceCodeVerifier) {\n const body = new URLSearchParams([\n ['code', code],\n ['grant_type', 'authorization_code'],\n ['client_id', clientId],\n ['redirect_uri', redirectUri]\n ])\n\n if (pkceCodeVerifier) {\n body.append('code_verifier', pkceCodeVerifier)\n }\n\n if (this.#dpopProvider) {\n return await this.#fetchDPoPToken(url, body)\n } else {\n return await fetchJSON(url, {\n method: 'POST',\n credentials: 'include',\n body\n })\n }\n }\n\n /**\n * Validate token_type matches DPoP expectations.\n * Per RFC 9449 Section 5:\n * - If we sent DPoP proof but got Bearer, the token isn't bound (disable DPoP or error in strict mode)\n * @param {AccessTokenResponse} tokenResponse\n * @returns {AccessTokenResponse} The validated response\n * @throws {Error} If strict mode and token_type doesn't match expectations\n */\n #validateDPoPTokenType (tokenResponse) {\n const tokenType = tokenResponse.token_type?.toLowerCase()\n const hasDPoPProvider = !!this.#dpopProvider\n\n if (hasDPoPProvider && tokenType !== 'dpop') {\n // We sent a DPoP proof but server returned non-DPoP token\n if (this.dpopConfig?.mode === 'strict') {\n throw new Error('DPoP strict mode enabled but server returned non-DPoP token (token_type: ' + tokenResponse.token_type + ')')\n }\n // Auto mode: disable DPoP and fall back to Bearer\n this.#logWarn('[KEYCLOAK] Server returned token_type \"' + tokenResponse.token_type + '\" instead of \"DPoP\". Disabling DPoP for this session.')\n this.#dpopProvider = undefined\n }\n\n return tokenResponse\n }\n\n /**\n * @param {RequestInfo | URL} url\n * @param {RequestInit} init\n * @param {string} urlString\n * @param {string} method\n * @param {string} [nonce]\n * @returns {Promise<Response>}\n */\n async #fetchWithDPoPProof (url, init, urlString, method, nonce) {\n const dpopProvider = this.#dpopProvider\n if (!dpopProvider) {\n throw new Error('DPoP provider not initialized')\n }\n\n const proof = await dpopProvider.generateDPoPProof(urlString, method, this.token, nonce)\n const headers = new Headers(init.headers)\n headers.set('Authorization', `DPoP ${this.token}`)\n headers.set('DPoP', proof)\n return fetch(url, { ...init, headers })\n }\n\n /**\n * Fetch tokens from the authorization server with DPoP proof attached.\n * Handles nonce requirements per RFC 9449 Section 8.\n * @param {string} url\n * @param {URLSearchParams} body\n * @returns {Promise<AccessTokenResponse>}\n */\n async #fetchDPoPToken (url, body) {\n const dpopProvider = this.#dpopProvider\n if (!dpopProvider) {\n throw new Error('DPoP provider not initialized')\n }\n\n const fetchToken = async (nonce) => {\n const proof = await dpopProvider.generateDPoPProof(url, 'POST', undefined, nonce)\n const headers = new Headers()\n headers.set('DPoP', proof)\n headers.set('Accept', CONTENT_TYPE_JSON)\n const resp = await fetchWithErrorHandling(url, {\n method: 'POST',\n credentials: 'include',\n body,\n headers\n })\n // RFC 9449 Section 8.2: new nonce values may be returned in successful responses\n const newNonce = resp.headers.get('DPoP-Nonce')\n if (newNonce) {\n await dpopProvider.updateAuthServerNonce(newNonce)\n }\n const tokenResponse = await resp.json()\n return this.#validateDPoPTokenType(tokenResponse)\n }\n\n try {\n const nonce = await dpopProvider.getAuthServerNonce()\n return await fetchToken(nonce)\n } catch (ex) {\n // Check if this is a DPoP nonce error per RFC 9449 Section 8\n if (ex instanceof NetworkError && ex.response.status === 400) {\n const dpopNonce = ex.response.headers.get('DPoP-Nonce')\n if (dpopNonce) {\n const errorBody = await ex.response.json().catch(() => ({}))\n if (errorBody.error === 'use_dpop_nonce') {\n await dpopProvider.updateAuthServerNonce(dpopNonce)\n return await fetchToken(dpopNonce)\n }\n }\n }\n throw ex\n }\n }\n\n /**\n * Fetch the refresh token from the given URL.\n * @param {string} url\n * @param {string} refreshToken\n * @param {string} clientId\n * @returns {Promise<AccessTokenResponse>}\n */\n async #fetchRefreshToken (url, refreshToken, clientId) {\n const body = new URLSearchParams([\n ['grant_type', 'refresh_token'],\n ['refresh_token', refreshToken],\n ['client_id', clientId]\n ])\n\n if (this.#dpopProvider) {\n return await this.#fetchDPoPToken(url, body)\n } else {\n return await fetchJSON(url, {\n method: 'POST',\n credentials: 'include',\n body\n })\n }\n }\n\n /**\n * @param {string} [token]\n * @param {string} [refreshToken]\n * @param {string} [idToken]\n * @param {number} [timeLocal]\n */\n #setToken (token, refreshToken, idToken, timeLocal) {\n if (this.tokenTimeoutHandle) {\n clearTimeout(this.tokenTimeoutHandle)\n this.tokenTimeoutHandle = undefined\n }\n\n if (refreshToken) {\n this.refreshToken = refreshToken\n this.refreshTokenParsed = decodeToken(refreshToken)\n } else {\n delete this.refreshToken\n delete this.refreshTokenParsed\n }\n\n if (idToken) {\n this.idToken = idToken\n this.idTokenParsed = decodeToken(idToken)\n } else {\n delete this.idToken\n delete this.idTokenParsed\n }\n\n if (token) {\n this.token = token\n this.tokenParsed = decodeToken(token)\n this.sessionId = this.tokenParsed.sid\n this.authenticated = true\n this.subject = this.tokenParsed.sub\n this.realmAccess = this.tokenParsed.realm_access\n this.resourceAccess = this.tokenParsed.resource_access\n\n if (timeLocal) {\n this.timeSkew = Math.floor(timeLocal / 1000) - this.tokenParsed.iat\n }\n\n if (this.timeSkew !== null) {\n this.#logInfo('[KEYCLOAK] Estimated time difference between browser and server is ' + this.timeSkew + ' seconds')\n\n if (this.onTokenExpired) {\n const expiresIn = (this.tokenParsed.exp - (new Date().getTime() / 1000) + this.timeSkew) * 1000\n this.#logInfo('[KEYCLOAK] Token expires in ' + Math.round(expiresIn / 1000) + ' s')\n if (expiresIn <= 0) {\n this.onTokenExpired()\n } else {\n this.tokenTimeoutHandle = window.setTimeout(this.onTokenExpired, expiresIn)\n }\n }\n }\n } else {\n delete this.token\n delete this.tokenParsed\n delete this.subject\n delete this.realmAccess\n delete this.resourceAccess\n\n this.authenticated = false\n }\n }\n\n /**\n * @returns {string=}\n */\n #getRealmUrl () {\n if (typeof this.authServerUrl === 'undefined') {\n return\n }\n\n return `${stripTrailingSlash(this.authServerUrl)}/realms/${encodeURIComponent(/** @type {string} */ (this.realm))}`\n }\n\n /**\n * Gets the issuer URL.\n * Returns the OIDC issuer if available, otherwise constructs from realm URL.\n * @returns {string=}\n */\n #getIssuerUrl () {\n // For OIDC provider mode, use the issuer from metadata\n if (this.issuer) {\n return this.issuer\n }\n\n // For Keycloak mode, use the realm URL\n return this.#getRealmUrl()\n }\n\n /**\n * @param {Function} fn\n * @returns {(message: string) => void}\n */\n #createLogger (fn) {\n return (message) => {\n if (this.enableLogging) {\n fn.call(console, message)\n }\n }\n }\n}\n\n/**\n * @returns {string}\n */\nfunction createUUID () {\n if (typeof crypto === 'undefined' || typeof crypto.randomUUID === 'undefined') {\n throw new Error('Web Crypto API is not available.')\n }\n\n return crypto.randomUUID()\n}\n\n/**\n * @param {Acr} requestedAcr\n * @returns {string}\n */\nfunction buildClaimsParameter (requestedAcr) {\n return JSON.stringify({\n id_token: {\n acr: requestedAcr\n }\n })\n}\n\n/**\n * @param {number} len\n * @returns {string}\n */\nfunction generateCodeVerifier (len) {\n return generateRandomString(len, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789')\n}\n\n/**\n * @param {string} pkceMethod\n * @param {string} codeVerifier\n * @returns {Promise<string>}\n */\nasync function generatePkceChallenge (pkceMethod, codeVerifier) {\n if (pkceMethod !== 'S256') {\n throw new TypeError(`Invalid value for 'pkceMethod', expected 'S256' but got '${pkceMethod}'.`)\n }\n\n // hash codeVerifier, then encode as url-safe base64 without padding\n const hashBytes = new Uint8Array(await sha256Digest(codeVerifier))\n const encodedHash = bytesToBase64(hashBytes)\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=/g, '')\n\n return encodedHash\n}\n\n/**\n * @param {number} len\n * @param {string} alphabet\n * @returns {string}\n */\nfunction generateRandomString (len, alphabet) {\n const randomData = generateRandomData(len)\n const chars = new Array(len)\n for (let i = 0; i < len; i++) {\n chars[i] = alphabet.charCodeAt(randomData[i] % alphabet.length)\n }\n return String.fromCharCode.apply(null, chars)\n}\n\n/**\n * @param {number} len\n * @returns {Uint8Array<ArrayBuffer>}\n */\nfunction generateRandomData (len) {\n if (typeof crypto === 'undefined' || typeof crypto.getRandomValues === 'undefined') {\n throw new Error('Web Crypto API is not available.')\n }\n\n return crypto.getRandomValues(new Uint8Array(len))\n}\n\n/**\n * Function to extend existing native Promise with timeout\n *\n * @template T\n * @param {Promise<T>} promise\n * @param {number} timeout\n * @param {string} errorMessage\n * @returns {Promise<T>}\n */\nfunction applyTimeoutToPromise (promise, timeout, errorMessage) {\n /** @type {number} */\n let timeoutHandle\n const timeoutPromise = new Promise(function (resolve, reject) {\n timeoutHandle = window.setTimeout(function () {\n reject(new Error(errorMessage || 'Promise is not settled within timeout of ' + timeout + 'ms'))\n }, timeout)\n })\n\n return Promise.race([promise, timeoutPromise]).finally(function () {\n clearTimeout(timeoutHandle)\n })\n}\n\n/**\n * @returns {CallbackStorage}\n */\nfunction createCallbackStorage () {\n try {\n return new LocalStorage()\n } catch (err) {\n return new CookieStorage()\n }\n}\n\nconst STORAGE_KEY_PREFIX = 'kc-callback-'\n\n/**\n * @typedef {Object} CallbackState\n * @property {string} state\n * @property {string} nonce\n * @property {string} redirectUri\n * @property {string} [appHash] Application URL hash stripped from redirect_uri and restored after login.\n * @property {KeycloakLoginOptions} [loginOptions]\n * @property {KeycloakLoginOptions['prompt']} [prompt]\n * @property {string} [pkceCodeVerifier]\n */\n\n/**\n * @typedef {Object} CallbackStorage\n * @property {(state?: string) => CallbackState | null} get\n * @property {(state: CallbackState) => void} add\n */\n\n/**\n * @implements {CallbackStorage}\n */\nclass LocalStorage {\n constructor () {\n globalThis.localStorage.setItem('kc-test', 'test')\n globalThis.localStorage.removeItem('kc-test')\n }\n\n /**\n * @param {string} [state]\n * @returns {CallbackState | null}\n */\n get (state) {\n if (!state) {\n return null\n }\n\n this.#clearInvalidValues()\n\n const key = STORAGE_KEY_PREFIX + state\n const value = globalThis.localStorage.getItem(key)\n\n if (value) {\n globalThis.localStorage.removeItem(key)\n return JSON.parse(value)\n }\n\n return null\n };\n\n /**\n * @param {CallbackState} state\n */\n add (state) {\n this.#clearInvalidValues()\n\n const key = STORAGE_KEY_PREFIX + state.state\n const value = JSON.stringify({\n ...state,\n // Set the expiry time to 1 hour from now.\n expires: Date.now() + (60 * 60 * 1000)\n })\n\n try {\n globalThis.localStorage.setItem(key, value)\n } catch (error) {\n // If the storage is full, clear all known values and try again.\n this.#clearAllValues()\n globalThis.localStorage.setItem(key, value)\n }\n };\n\n /**\n * Clears all values from local storage that are no longer valid.\n */\n #clearInvalidValues () {\n const currentTime = Date.now()\n\n for (const [key, value] of this.#getStoredEntries()) {\n // Attempt to parse the expiry time from the value.\n const expiry = this.#parseExpiry(value)\n\n // Discard the value if it is malformed or expired.\n if (expiry === null || expiry < currentTime) {\n globalThis.localStorage.removeItem(key)\n }\n }\n }\n\n /**\n * Clears all known values from local storage.\n */\n #clearAllValues () {\n for (const [key] of this.#getStoredEntries()) {\n globalThis.localStorage.removeItem(key)\n }\n }\n\n /**\n * Gets all entries stored in local storage that are known to be managed by this class.\n * @returns {[string, string][]} An array of key-value pairs.\n */\n #getStoredEntries () {\n return Object.entries(globalThis.localStorage).filter(([key]) => key.startsWith(STORAGE_KEY_PREFIX))\n }\n\n /**\n * Parses the expiry time from a value stored in local storage.\n * @param {string} value\n * @returns {number | null} The expiry time in milliseconds, or `null` if the value is malformed.\n */\n #parseExpiry (value) {\n let parsedValue\n\n // Attempt to parse the value as JSON.\n try {\n parsedValue = JSON.parse(value)\n } catch (error) {\n return null\n }\n\n // Attempt to extract the 'expires' property.\n if (isObject(parsedValue) && 'expires' in parsedValue && typeof parsedValue.expires === 'number') {\n return parsedValue.expires\n }\n\n return null\n }\n}\n\n/**\n * @implements {CallbackStorage}\n */\nclass CookieStorage {\n /**\n * @param {string} [state]\n * @returns {CallbackState | null}\n */\n get (state) {\n if (!state) {\n return null\n }\n\n const value = this.#getCookie(STORAGE_KEY_PREFIX + state)\n this.#setCookie(STORAGE_KEY_PREFIX + state, '', this.#cookieExpiration(-100))\n if (value) {\n return JSON.parse(value)\n }\n\n return null\n }\n\n /**\n * @param {CallbackState} state\n */\n add (state) {\n this.#setCookie(STORAGE_KEY_PREFIX + state.state, JSON.stringify(state), this.#cookieExpiration(60))\n }\n\n /**\n * @param {string} key\n * @returns\n */\n #getCookie (key) {\n const name = key + '='\n const ca = document.cookie.split(';')\n for (let i = 0; i < ca.length; i++) {\n let c = ca[i]\n while (c.charAt(0) === ' ') {\n c = c.substring(1)\n }\n if (c.indexOf(name) === 0) {\n return c.substring(name.length, c.length)\n }\n }\n return ''\n }\n\n /**\n * @param {string} key\n * @param {string} value\n * @param {Date} expirationDate\n */\n #setCookie (key, value, expirationDate) {\n const cookie = key + '=' + value + '; ' +\n 'expires=' + expirationDate.toUTCString() + '; '\n document.cookie = cookie\n }\n\n /**\n * @param {number} minutes\n * @returns {Date}\n */\n #cookieExpiration (minutes) {\n const exp = new Date()\n exp.setTime(exp.getTime() + (minutes * 60 * 1000))\n return exp\n }\n}\n\n/**\n * @param {Uint8Array<ArrayBuffer>} bytes\n * @see https://developer.mozilla.org/en-US/docs/Glossary/Base64#the_unicode_problem\n */\nfunction bytesToBase64 (bytes) {\n const binString = String.fromCodePoint(...bytes)\n return btoa(binString)\n}\n\n/**\n * @param {string} message\n * @see https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest#basic_example\n */\nasync function sha256Digest (message) {\n const encoder = new TextEncoder()\n const data = encoder.encode(message)\n\n if (typeof crypto === 'undefined' || typeof crypto.subtle === 'undefined') {\n throw new Error('Web Crypto API is not available.')\n }\n\n return await crypto.subtle.digest('SHA-256', data)\n}\n\n/**\n * @param {string} token\n * @returns {KeycloakTokenParsed}\n */\nfunction decodeToken (token) {\n const [, payload] = token.split('.')\n\n if (typeof payload !== 'string') {\n throw new Error('Unable to decode token, payload not found.')\n }\n\n let decoded\n\n try {\n decoded = base64UrlDecode(payload)\n } catch (error) {\n throw new Error('Unable to decode token, payload is not a valid Base64URL value.', { cause: error })\n }\n\n try {\n return JSON.parse(decoded)\n } catch (error) {\n throw new Error('Unable to decode token, payload is not a valid JSON value.', { cause: error })\n }\n}\n\n/**\n * @param {string} input\n */\nfunction base64UrlDecode (input) {\n let output = input\n .replaceAll('-', '+')\n .replaceAll('_', '/')\n\n switch (output.length % 4) {\n case 0:\n break\n case 2:\n output += '=='\n break\n case 3:\n output += '='\n break\n default:\n throw new Error('Input is not of the correct length.')\n }\n\n try {\n return b64DecodeUnicode(output)\n } catch (error) {\n return atob(output)\n }\n}\n\n/**\n * @param {string} input\n */\nfunction b64DecodeUnicode (input) {\n return decodeURIComponent(atob(input).replace(/(.)/g, (m, p) => {\n let code = p.charCodeAt(0).toString(16).toUpperCase()\n\n if (code.length < 2) {\n code = '0' + code\n }\n\n return '%' + code\n }))\n}\n\n/**\n * Check if the input is an object that can be operated on.\n * @param {unknown} input\n */\nfunction isObject (input) {\n return typeof input === 'object' && input !== null\n}\n\n/**\n * @typedef {Object} JsonConfig The JSON version of the adapter configuration.\n * @property {string} auth-server-url The URL of the authentication server.\n * @property {string} realm The name of the realm.\n * @property {string} resource The name of the resource, usually the client ID.\n */\n\n/**\n * Fetch the adapter configuration from the given URL.\n * @param {string} url\n * @returns {Promise<JsonConfig>}\n */\nasync function fetchJsonConfig (url) {\n return await fetchJSON(url)\n}\n\n/**\n * Fetch the OpenID configuration from the given URL.\n * @param {string} url\n * @returns {Promise<OpenIdProviderMetadata>}\n */\nasync function fetchOpenIdConfig (url) {\n return await fetchJSON(url)\n}\n\n/**\n * @template [T=unknown]\n * @param {string} url\n * @param {RequestInit} init\n * @returns {Promise<T>}\n */\nasync function fetchJSON (url, init = {}) {\n const headers = new Headers(init.headers)\n headers.set('Accept', CONTENT_TYPE_JSON)\n\n const response = await fetchWithErrorHandling(url, {\n ...init,\n headers\n })\n\n return await response.json()\n}\n\n/**\n * @param {string} url\n * @param {RequestInit} [init]\n * @returns {Promise<Response>}\n */\nasync function fetchWithErrorHandling (url, init) {\n const response = await fetch(url, init)\n\n if (!response.ok) {\n throw new NetworkError('Server responded with an invalid status.', { response })\n }\n\n return response\n}\n\n/**\n * @param {string} [token]\n * @returns {[string, string]}\n */\nfunction buildAuthorizationHeader (token) {\n if (!token) {\n throw new Error('Unable to build authorization header, token is not set, make sure the user is authenticated.')\n }\n\n return ['Authorization', `bearer ${token}`]\n}\n\n/**\n * @param {string} url\n * @returns {string}\n */\nfunction stripTrailingSlash (url) {\n return url.endsWith('/') ? url.slice(0, -1) : url\n}\n\n/**\n * @typedef {Object} NetworkErrorOptionsProperties\n * @property {Response} response\n * @typedef {ErrorOptions & NetworkErrorOptionsProperties} NetworkErrorOptions\n */\n\nexport class NetworkError extends Error {\n /** @type {Response} */\n response\n\n /**\n * @param {string} message\n * @param {NetworkErrorOptions} options\n */\n constructor (message, options) {\n super(message, options)\n this.response = options.response\n }\n}\n\n/**\n * @param {number} delay\n * @returns {Promise<void>}\n */\nconst waitForTimeout = (delay) => new Promise((resolve) => setTimeout(resolve, delay))\n","import { singleton } from 'tsyringe';\nimport { SubscribableAbstract } from '@gen-epix/ui-core/classes/abstracts/SubscribableAbstract';\nimport { Subject } from '@gen-epix/ui-core/classes/Subject';\nimport Keycloak from 'keycloak-js';\n\nimport type { MetadataParseResult } from '../../../models/metadata.models';\nimport { FastaUtil } from '../../../utils/FastaUtil';\nimport { MetaDataUtil } from '../../../utils/MetaDataUtil';\n\nexport type LoculusServiceSubject = {\n authenticated: boolean;\n};\n\nexport type RevisedSequences = {\n addedSequencesWithoutMetadata: string[];\n fasta: string;\n groupId: string;\n metadata: string;\n removedSequences: string[];\n sequenceCount: number;\n};\n\n@singleton()\nexport class LoculusService extends SubscribableAbstract<LoculusServiceSubject> {\n public get code(): null | string {\n return this.keycloak?.idToken ?? null;\n }\n private keycloak: Keycloak | null = null;\n\n public constructor() {\n super(new Subject<LoculusServiceSubject>({\n authenticated: false,\n }));\n }\n\n public static createRevisedSequences(\n fasta: string,\n metaData: MetadataParseResult,\n rawFasta: string = fasta,\n ): RevisedSequences {\n const parsedFasta = FastaUtil.parseFasta(fasta);\n if (parsedFasta.error) {\n throw new Error(parsedFasta.error);\n }\n const parsedRawFasta = FastaUtil.parseFasta(rawFasta);\n if (parsedRawFasta.error) {\n throw new Error(parsedRawFasta.error);\n }\n\n const hasMetadataMatch = (sequenceId: string) => (\n Object.values(metaData.recordsByColumn).some((recordsByValue) => recordsByValue[sequenceId])\n );\n const editedSequenceIds = new Set(parsedFasta.sequences.map((sequence) => sequence.id));\n const originalSequenceIds = new Set(parsedRawFasta.sequences.map((sequence) => sequence.id));\n const matchingSequences = parsedFasta.sequences.filter((sequence) => hasMetadataMatch(sequence.id));\n const matchingIds = new Set(matchingSequences.map((sequence) => sequence.id));\n const metadataRows = metaData.records.filter((record) => (\n Object.values(record).some((value) => matchingIds.has(value))\n ));\n\n return {\n addedSequencesWithoutMetadata: parsedFasta.sequences\n .filter((sequence) => !originalSequenceIds.has(sequence.id) && !hasMetadataMatch(sequence.id))\n .map((sequence) => sequence.id),\n fasta: matchingSequences.map((sequence) => `>${sequence.header}\\n${sequence.sequence}`).join('\\n'),\n groupId: MetaDataUtil.getGroupId(metaData),\n metadata: [\n metaData.columns.join('\\t'),\n ...metadataRows.map((record) => metaData.columns.map((column) => record[column] ?? '').join('\\t')),\n ].join('\\n'),\n removedSequences: parsedRawFasta.sequences\n .filter((sequence) => !editedSequenceIds.has(sequence.id))\n .map((sequence) => sequence.id),\n sequenceCount: matchingSequences.length,\n };\n }\n\n public clear(): void {\n this.keycloak = null;\n this.next({\n authenticated: false,\n });\n }\n\n public async init(kwArgs: { authClientId: string; authEndpoint: string; authRealm: string }): Promise<void> {\n const { authClientId, authEndpoint, authRealm } = kwArgs;\n let authenticated = false;\n let initializedKeycloak: Keycloak | null = null;\n\n try {\n const keycloak = new Keycloak({\n clientId: authClientId,\n realm: authRealm,\n url: authEndpoint,\n });\n initializedKeycloak = keycloak;\n this.keycloak = keycloak;\n keycloak.onAuthLogout = () => {\n this.next({\n authenticated: false,\n });\n };\n keycloak.onTokenExpired = () => {\n if (this.keycloak !== keycloak) {\n return;\n }\n\n void keycloak.updateToken(-1).catch((error: unknown) => {\n console.error('Failed to refresh Keycloak token:', error);\n void keycloak.clearToken();\n });\n };\n\n authenticated = await keycloak.init({\n enableLogging: true,\n onLoad: 'check-sso',\n pkceMethod: 'S256',\n silentCheckSsoFallback: false,\n silentCheckSsoRedirectUri: `${window.location.origin}/silent-check-sso.html`,\n useNonce: true,\n });\n } catch (error) {\n console.error('Failed to initialize Keycloak:', error);\n }\n\n if (initializedKeycloak && this.keycloak !== initializedKeycloak) {\n return;\n }\n\n this.next({\n authenticated,\n });\n }\n\n public async reviseSequences(\n fasta: string,\n metaData: MetadataParseResult,\n returnUrl: string,\n organism: string,\n abortController: AbortController,\n ): Promise<void> {\n\n const revisedSequences = LoculusService.createRevisedSequences(fasta, metaData);\n\n const body = new FormData();\n body.append('sequenceFile', new File([revisedSequences.fasta], 'sequences.fasta', { type: 'text/plain' }));\n body.append(\n 'metadataFile',\n new File([revisedSequences.metadata], 'metadata.tsv', { type: 'text/tab-separated-values' }),\n );\n\n const url = `${returnUrl.replace(/\\/$/, '')}/${encodeURIComponent(organism)}/revise?${new URLSearchParams({\n dataUseTermsType: 'OPEN',\n groupId: revisedSequences.groupId,\n })}`;\n\n const response = await this.keycloak?.fetch(url, {\n body,\n method: 'POST',\n signal: abortController.signal,\n });\n\n if (!response?.ok) {\n if (response?.status === 401 || response?.status === 403) {\n throw new Error('Your Loculus session is no longer valid. Please log in to Loculus again in a separate tab, then try uploading again.');\n }\n\n const errorText = await response?.text();\n throw new Error(`Failed to revise sequences: ${errorText}`);\n }\n }\n}\n"],"ignoreList":[0,1],"mappings":"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"}
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
// ../../../node_modules/.pnpm/keycloak-js@26.2.5/node_modules/keycloak-js/lib/keycloak-dpop.js
|
|
2
|
+
var e = {
|
|
3
|
+
ES256: "ES256",
|
|
4
|
+
ES384: "ES384",
|
|
5
|
+
ES512: "ES512",
|
|
6
|
+
EdDSA: "EdDSA"
|
|
7
|
+
}, t = 1, n = "main", r = "dpopState", i = 512, a = /^[\x21-\x7E]+$/;
|
|
8
|
+
function o(e) {
|
|
9
|
+
return typeof e == "string" && e.length > 0 && e.length <= i && a.test(e);
|
|
10
|
+
}
|
|
11
|
+
function s(e) {
|
|
12
|
+
if (typeof e != "string" || e.length === 0) throw Error("DPoP nonce must be a non-empty string");
|
|
13
|
+
if (e.length > i) throw Error(`DPoP nonce exceeds maximum length of ${i} characters`);
|
|
14
|
+
if (!a.test(e)) throw Error("DPoP nonce contains invalid characters");
|
|
15
|
+
}
|
|
16
|
+
async function c(e) {
|
|
17
|
+
let t = new TextEncoder().encode(e), n = await crypto.subtle.digest("SHA-256", t);
|
|
18
|
+
return Array.from(new Uint8Array(n).slice(0, 8)).map((e) => e.toString(16).padStart(2, "0")).join("");
|
|
19
|
+
}
|
|
20
|
+
var l = {
|
|
21
|
+
ES256: {
|
|
22
|
+
name: "ECDSA",
|
|
23
|
+
namedCurve: "P-256"
|
|
24
|
+
},
|
|
25
|
+
ES384: {
|
|
26
|
+
name: "ECDSA",
|
|
27
|
+
namedCurve: "P-384"
|
|
28
|
+
},
|
|
29
|
+
ES512: {
|
|
30
|
+
name: "ECDSA",
|
|
31
|
+
namedCurve: "P-521"
|
|
32
|
+
},
|
|
33
|
+
EdDSA: { name: "Ed25519" }
|
|
34
|
+
}, u = {
|
|
35
|
+
ES256: {
|
|
36
|
+
name: "ECDSA",
|
|
37
|
+
hash: "SHA-256"
|
|
38
|
+
},
|
|
39
|
+
ES384: {
|
|
40
|
+
name: "ECDSA",
|
|
41
|
+
hash: "SHA-384"
|
|
42
|
+
},
|
|
43
|
+
ES512: {
|
|
44
|
+
name: "ECDSA",
|
|
45
|
+
hash: "SHA-512"
|
|
46
|
+
},
|
|
47
|
+
EdDSA: { name: "Ed25519" }
|
|
48
|
+
}, d = [
|
|
49
|
+
e.ES256,
|
|
50
|
+
e.ES384,
|
|
51
|
+
e.ES512
|
|
52
|
+
];
|
|
53
|
+
async function f(e, t) {
|
|
54
|
+
let [n, r] = await Promise.all([c(e), c(t)]);
|
|
55
|
+
return `dpop:${n}:${r}`;
|
|
56
|
+
}
|
|
57
|
+
var p = class {
|
|
58
|
+
#e = "";
|
|
59
|
+
#t = null;
|
|
60
|
+
#n = !1;
|
|
61
|
+
#r = void 0;
|
|
62
|
+
#i;
|
|
63
|
+
#a;
|
|
64
|
+
#o;
|
|
65
|
+
constructor(e, t, n = !1) {
|
|
66
|
+
this.#i = e, this.#a = t, this.#o = n;
|
|
67
|
+
}
|
|
68
|
+
async init() {
|
|
69
|
+
if (this.#t || this.#n) return this;
|
|
70
|
+
try {
|
|
71
|
+
this.#e = await f(this.#i, this.#a), this.#t = await this.#s();
|
|
72
|
+
} catch (e) {
|
|
73
|
+
if (this.#o) throw Error("DPoP requires IndexedDB for secure key storage, but it is unavailable.", { cause: e });
|
|
74
|
+
console.warn("[KEYCLOAK] IndexedDB unavailable, falling back to in-memory storage:", e), this.#n = !0;
|
|
75
|
+
}
|
|
76
|
+
return this;
|
|
77
|
+
}
|
|
78
|
+
#s() {
|
|
79
|
+
return new Promise((e, r) => {
|
|
80
|
+
if (globalThis.indexedDB === void 0) {
|
|
81
|
+
r(/* @__PURE__ */ Error("IndexedDB is not available"));
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
let i = globalThis.indexedDB.open(this.#e, t);
|
|
85
|
+
i.onerror = () => {
|
|
86
|
+
r(i.error);
|
|
87
|
+
}, i.onsuccess = () => {
|
|
88
|
+
e(i.result);
|
|
89
|
+
}, i.onupgradeneeded = (e) => {
|
|
90
|
+
let t = e.target.result;
|
|
91
|
+
e.oldVersion < 1 && t.createObjectStore(n);
|
|
92
|
+
};
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
async get() {
|
|
96
|
+
if (this.#n) return this.#r;
|
|
97
|
+
if (!this.#t) throw Error("DPoPStoreManager not initialized. Call init() first.");
|
|
98
|
+
return new Promise((e, t) => {
|
|
99
|
+
let i = this.#t.transaction(n, "readonly").objectStore(n).get(r);
|
|
100
|
+
i.onerror = () => {
|
|
101
|
+
t(i.error);
|
|
102
|
+
}, i.onsuccess = () => {
|
|
103
|
+
e(i.result);
|
|
104
|
+
};
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
async set(e) {
|
|
108
|
+
if (this.#n) this.#r = e;
|
|
109
|
+
else {
|
|
110
|
+
if (!this.#t) throw Error("DPoPStoreManager not initialized. Call init() first.");
|
|
111
|
+
return new Promise((t, i) => {
|
|
112
|
+
let a = this.#t.transaction(n, "readwrite").objectStore(n).put(e, r);
|
|
113
|
+
a.onerror = () => {
|
|
114
|
+
i(a.error);
|
|
115
|
+
}, a.onsuccess = () => {
|
|
116
|
+
t();
|
|
117
|
+
};
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
async flush() {
|
|
122
|
+
if (this.#n) this.#r = void 0;
|
|
123
|
+
else {
|
|
124
|
+
if (!this.#t) throw Error("DPoPStoreManager not initialized. Call init() first.");
|
|
125
|
+
return new Promise((e, t) => {
|
|
126
|
+
let i = this.#t.transaction(n, "readwrite").objectStore(n).delete(r);
|
|
127
|
+
i.onerror = () => {
|
|
128
|
+
t(i.error);
|
|
129
|
+
}, i.onsuccess = () => {
|
|
130
|
+
e();
|
|
131
|
+
};
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
async updateNonce(e) {
|
|
136
|
+
s(e);
|
|
137
|
+
let t = await this.get();
|
|
138
|
+
t && (t.nonce = e, await this.set(t));
|
|
139
|
+
}
|
|
140
|
+
close() {
|
|
141
|
+
this.#t &&= (this.#t.close(), null);
|
|
142
|
+
}
|
|
143
|
+
}, m = class {
|
|
144
|
+
#e;
|
|
145
|
+
#t;
|
|
146
|
+
#n;
|
|
147
|
+
#r = /* @__PURE__ */ new Map();
|
|
148
|
+
#i;
|
|
149
|
+
constructor(t) {
|
|
150
|
+
let { issuerUrl: n, clientId: r, serverSupportedAlgorithms: i, requestedAlgorithm: a, strictStorage: o = !1, getTimeSkew: s } = t;
|
|
151
|
+
if (this.#i = s, typeof crypto > "u" || !crypto.subtle) throw Error("DPoP requires Web Crypto API (crypto.subtle) which is not available in this environment.");
|
|
152
|
+
if (!n) throw Error("DPoP requires issuerUrl");
|
|
153
|
+
if (!r) throw Error("DPoP requires clientId");
|
|
154
|
+
if (!i || !Array.isArray(i)) throw Error("DPoP requires serverSupportedAlgorithms array");
|
|
155
|
+
this.#n = i;
|
|
156
|
+
let c = e.ES256;
|
|
157
|
+
if (a !== void 0) {
|
|
158
|
+
if (!this.#n.includes(a)) throw Error(`Requested algorithm '${a}' is not supported by the server. Server supports: ${this.#n.join(", ")}`);
|
|
159
|
+
c = a;
|
|
160
|
+
}
|
|
161
|
+
this.#e = c, this.#t = new p(n.toString(), r, o);
|
|
162
|
+
}
|
|
163
|
+
async init() {
|
|
164
|
+
await this.#t.init();
|
|
165
|
+
let e = await this.#t.get();
|
|
166
|
+
if (e) {
|
|
167
|
+
let t = l[this.#e], n = e.keys.publicKey.algorithm;
|
|
168
|
+
(n.name !== t.name || t.namedCurve && n.namedCurve !== t.namedCurve) && (console.warn("[KEYCLOAK] Stored DPoP key algorithm does not match requested algorithm, regenerating key pair."), await this.#t.flush(), e = void 0);
|
|
169
|
+
}
|
|
170
|
+
e || (e = { keys: await this.#a() }, await this.#t.set(e));
|
|
171
|
+
}
|
|
172
|
+
async #a() {
|
|
173
|
+
let t = l[this.#e];
|
|
174
|
+
if (!t) throw Error(`Unknown signature algorithm: ${this.#e}`);
|
|
175
|
+
try {
|
|
176
|
+
return await crypto.subtle.generateKey(t, !1, ["sign"]);
|
|
177
|
+
} catch (t) {
|
|
178
|
+
if (!(t instanceof DOMException && t.name === "NotSupportedError") || this.#e !== e.EdDSA) throw t;
|
|
179
|
+
let n = d.find((e) => this.#n.includes(e));
|
|
180
|
+
if (!n) throw Error("No supported algorithm available in this browser");
|
|
181
|
+
return this.#e = n, this.#a();
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
async #o(e, t) {
|
|
185
|
+
let n = u[this.#e];
|
|
186
|
+
if (!n) throw Error(`Unknown signature algorithm: ${this.#e}`);
|
|
187
|
+
return await crypto.subtle.sign(n, t, e);
|
|
188
|
+
}
|
|
189
|
+
async flush() {
|
|
190
|
+
await this.#t.flush();
|
|
191
|
+
}
|
|
192
|
+
async getAuthServerNonce() {
|
|
193
|
+
return (await this.#t.get())?.nonce;
|
|
194
|
+
}
|
|
195
|
+
async updateAuthServerNonce(e) {
|
|
196
|
+
await this.#t.updateNonce(e);
|
|
197
|
+
}
|
|
198
|
+
getResourceServerNonce(e) {
|
|
199
|
+
return this.#r.get(e);
|
|
200
|
+
}
|
|
201
|
+
updateResourceServerNonce(e, t) {
|
|
202
|
+
o(t) && this.#r.set(e, t);
|
|
203
|
+
}
|
|
204
|
+
async generateDPoPProof(e, t, n, r) {
|
|
205
|
+
let i = {
|
|
206
|
+
jti: crypto.randomUUID(),
|
|
207
|
+
htm: t,
|
|
208
|
+
htu: (() => {
|
|
209
|
+
let t = new URL(e);
|
|
210
|
+
return t.origin + t.pathname;
|
|
211
|
+
})(),
|
|
212
|
+
iat: Math.floor(Date.now() / 1e3) - (this.#i?.() ?? 0),
|
|
213
|
+
...n !== void 0 && { ath: g(await h(n)) },
|
|
214
|
+
...r !== void 0 && { nonce: r }
|
|
215
|
+
}, a = await this.#t.get();
|
|
216
|
+
if (a === void 0) throw Error("DPoP not initialized");
|
|
217
|
+
let o = await crypto.subtle.exportKey("jwk", a.keys.publicKey), s = {
|
|
218
|
+
alg: this.#e,
|
|
219
|
+
typ: "dpop+jwt",
|
|
220
|
+
jwk: {
|
|
221
|
+
crv: o.crv,
|
|
222
|
+
kty: o.kty,
|
|
223
|
+
x: o.x,
|
|
224
|
+
y: o.y
|
|
225
|
+
}
|
|
226
|
+
}, c = new TextEncoder(), l = `${g(c.encode(JSON.stringify(s)))}.${g(c.encode(JSON.stringify(i)))}`;
|
|
227
|
+
return `${l}.${g(await this.#o(c.encode(l), a.keys.privateKey))}`;
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
async function h(e) {
|
|
231
|
+
let t = new TextEncoder().encode(e);
|
|
232
|
+
if (typeof crypto > "u" || crypto.subtle === void 0) throw Error("Web Crypto API is not available.");
|
|
233
|
+
return await crypto.subtle.digest("SHA-256", t);
|
|
234
|
+
}
|
|
235
|
+
function g(e) {
|
|
236
|
+
let t = e instanceof Uint8Array ? e : new Uint8Array(e), n = String.fromCharCode(...t);
|
|
237
|
+
return btoa(n).replaceAll("+", "-").replaceAll("/", "_").replaceAll("=", "");
|
|
238
|
+
}
|
|
239
|
+
export { e as BrowserSignatureAlgs, m as DPoPSignatureProvider };
|
|
240
|
+
|
|
241
|
+
//# sourceMappingURL=keycloak-dpop.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keycloak-dpop.js","names":["BrowserSignatureAlgs","DB_VERSION","STORE_NAME","STATE_KEY","MAX_NONCE_LENGTH","VALID_NONCE_PATTERN","isValidNonce","nonce","assertValidNonce","hashPrefix","data","value","hashBuffer","b","KEY_GEN_PARAMS","SIGN_PARAMS","ECDSA_FALLBACK_ORDER","createDbName","issuerHash","clientHash","issuer","clientId","DPoPStoreManager","#issuer","#clientId","#strictStorage","strictStorage","#db","#useMemoryFallback","#dbName","#openDatabase","error","request","db","event","#memoryStore","state","DPoPSignatureProvider","options","#getTimeSkew","getTimeSkew","issuerUrl","serverSupportedAlgorithms","#serverAllowedAlgorithms","chosenAlgorithm","requestedAlgorithm","#alg","#store","expectedParams","storedAlg","#generateKeyPair","params","ex","fallback","alg","#sign","key","msg","#resourceNonces","origin","payload","httpMethod","urlObj","url","accessToken","base64UrlEncodeBuffer","sha256Digest","exportedJwk","header","te","unsignedToken","message","bytes","buffer","binary"],"sources":["../../../../../node_modules/.pnpm/keycloak-js@26.2.5/node_modules/keycloak-js/lib/keycloak-dpop.js"],"sourcesContent":["// @ts-check\n/**\n * @import { DPoPState, DPoPSignatureProviderOptions } from \"./keycloak-dpop.ts\"\n */\n\n/** @enum {string} */\nexport const BrowserSignatureAlgs = {\n ES256: 'ES256',\n ES384: 'ES384',\n ES512: 'ES512',\n EdDSA: 'EdDSA'\n}\n\nconst DB_VERSION = 1\nconst STORE_NAME = 'main'\nconst STATE_KEY = 'dpopState'\nconst MAX_NONCE_LENGTH = 512\n// RFC 9449 doesn't specify format, but nonces should be printable ASCII for HTTP headers\nconst VALID_NONCE_PATTERN = /^[\\x21-\\x7E]+$/\n\n/**\n * @param {string} nonce\n * @returns {boolean}\n */\nfunction isValidNonce (nonce) {\n return typeof nonce === 'string' &&\n nonce.length > 0 &&\n nonce.length <= MAX_NONCE_LENGTH &&\n VALID_NONCE_PATTERN.test(nonce)\n}\n\n/**\n * @param {string} nonce\n * @throws {Error} If nonce fails validation\n */\nfunction assertValidNonce (nonce) {\n if (typeof nonce !== 'string' || nonce.length === 0) {\n throw new Error('DPoP nonce must be a non-empty string')\n }\n if (nonce.length > MAX_NONCE_LENGTH) {\n throw new Error(`DPoP nonce exceeds maximum length of ${MAX_NONCE_LENGTH} characters`)\n }\n if (!VALID_NONCE_PATTERN.test(nonce)) {\n throw new Error('DPoP nonce contains invalid characters')\n }\n}\n\n/**\n * @param {string} value\n * @returns {Promise<string>}\n */\nasync function hashPrefix (value) {\n const data = new TextEncoder().encode(value)\n const hashBuffer = await crypto.subtle.digest('SHA-256', data)\n return Array.from(new Uint8Array(hashBuffer).slice(0, 8))\n .map(b => b.toString(16).padStart(2, '0'))\n .join('')\n}\n\n/** @type {Record<string, EcKeyGenParams | AlgorithmIdentifier>} */\nconst KEY_GEN_PARAMS = {\n ES256: { name: 'ECDSA', namedCurve: 'P-256' },\n ES384: { name: 'ECDSA', namedCurve: 'P-384' },\n ES512: { name: 'ECDSA', namedCurve: 'P-521' },\n EdDSA: { name: 'Ed25519' }\n}\n\n/** @type {Record<string, EcdsaParams | AlgorithmIdentifier>} */\nconst SIGN_PARAMS = {\n ES256: { name: 'ECDSA', hash: 'SHA-256' },\n ES384: { name: 'ECDSA', hash: 'SHA-384' },\n ES512: { name: 'ECDSA', hash: 'SHA-512' },\n EdDSA: { name: 'Ed25519' }\n}\n\n/** Fallback order when EdDSA is unsupported */\nconst ECDSA_FALLBACK_ORDER = [\n BrowserSignatureAlgs.ES256,\n BrowserSignatureAlgs.ES384,\n BrowserSignatureAlgs.ES512\n]\n\n/**\n * Creates a safe database name from issuer and clientId.\n * Uses SHA-256 hash of both issuer and clientId to avoid special characters\n * and prevent injection attacks via malicious clientId values.\n * @param {string} issuer - The authorization server issuer URL\n * @param {string} clientId - The OIDC client identifier\n * @returns {Promise<string>} A sanitized database name\n */\nasync function createDbName (issuer, clientId) {\n const [issuerHash, clientHash] = await Promise.all([\n hashPrefix(issuer),\n hashPrefix(clientId)\n ])\n\n return `dpop:${issuerHash}:${clientHash}`\n}\n\n/**\n * Manages persistent storage of DPoP key pairs and nonces in IndexedDB.\n * Falls back to in-memory storage when IndexedDB is unavailable.\n *\n * Database is named using a hash of the issuer URL + clientId to ensure\n * isolation between different authorization servers.\n *\n * @see https://datatracker.ietf.org/doc/html/rfc9449\n */\nclass DPoPStoreManager {\n /** @type {string} */\n #dbName = ''\n\n /** @type {IDBDatabase | null} */\n #db = null\n\n /** @type {boolean} */\n #useMemoryFallback = false\n\n /** @type {DPoPState | undefined} */\n #memoryStore = undefined\n\n /** @type {string} */\n #issuer\n\n /** @type {string} */\n #clientId\n\n /** @type {boolean} */\n #strictStorage\n\n /**\n * @param {string} issuer - The authorization server issuer URL\n * @param {string} clientId - The OIDC client identifier\n * @param {boolean} [strictStorage=false] - If true, throws error when IndexedDB is unavailable instead of falling back to memory\n */\n constructor (issuer, clientId, strictStorage = false) {\n this.#issuer = issuer\n this.#clientId = clientId\n this.#strictStorage = strictStorage\n }\n\n /**\n * Initialize the store manager. Must be called before other operations.\n * @returns {Promise<DPoPStoreManager>}\n */\n async init () {\n if (this.#db || this.#useMemoryFallback) {\n return this // Already initialized\n }\n\n try {\n this.#dbName = await createDbName(this.#issuer, this.#clientId)\n this.#db = await this.#openDatabase()\n } catch (error) {\n if (this.#strictStorage) {\n throw new Error('DPoP requires IndexedDB for secure key storage, but it is unavailable.', { cause: error })\n }\n console.warn('[KEYCLOAK] IndexedDB unavailable, falling back to in-memory storage:', error)\n this.#useMemoryFallback = true\n }\n return this\n }\n\n /**\n * Opens or creates the IndexedDB database.\n * @returns {Promise<IDBDatabase>}\n */\n #openDatabase () {\n return new Promise((resolve, reject) => {\n if (typeof globalThis.indexedDB === 'undefined') {\n reject(new Error('IndexedDB is not available'))\n return\n }\n\n const request = globalThis.indexedDB.open(this.#dbName, DB_VERSION)\n\n request.onerror = () => {\n reject(request.error)\n }\n\n request.onsuccess = () => {\n resolve(request.result)\n }\n\n request.onupgradeneeded = (event) => {\n /** @type {IDBDatabase} */\n const db = /** @type {IDBOpenDBRequest} */ (event.target).result\n const oldVersion = event.oldVersion\n\n // Version 0 -> 1: Initial schema creation\n if (oldVersion < 1) {\n db.createObjectStore(STORE_NAME)\n }\n\n // Future migrations:\n // if (oldVersion < 2) {\n // // Example: Add an index to the store\n // const store = event.target.transaction.objectStore(STORE_NAME)\n // store.createIndex('indexName', 'keyPath')\n // }\n }\n })\n }\n\n /**\n * Retrieve the stored key pair and nonce.\n * @returns {Promise<DPoPState | undefined>}\n */\n async get () {\n if (this.#useMemoryFallback) {\n return this.#memoryStore\n }\n\n if (!this.#db) {\n throw new Error('DPoPStoreManager not initialized. Call init() first.')\n }\n\n return new Promise((resolve, reject) => {\n const transaction = /** @type {IDBDatabase} */ (this.#db).transaction(STORE_NAME, 'readonly')\n const store = transaction.objectStore(STORE_NAME)\n const request = store.get(STATE_KEY)\n\n request.onerror = () => {\n reject(request.error)\n }\n\n request.onsuccess = () => {\n resolve(request.result)\n }\n })\n }\n\n /**\n * Store or overwrite the key pair and optional nonce.\n * @param {DPoPState} state - The state to store\n * @returns {Promise<void>}\n */\n async set (state) {\n if (this.#useMemoryFallback) {\n this.#memoryStore = state\n return\n }\n\n if (!this.#db) {\n throw new Error('DPoPStoreManager not initialized. Call init() first.')\n }\n\n return new Promise((resolve, reject) => {\n const transaction = /** @type {IDBDatabase} */ (this.#db).transaction(STORE_NAME, 'readwrite')\n const store = transaction.objectStore(STORE_NAME)\n const request = store.put(state, STATE_KEY)\n\n request.onerror = () => {\n reject(request.error)\n }\n\n request.onsuccess = () => {\n resolve()\n }\n })\n }\n\n /**\n * Delete all stored data. Called on logout.\n * @returns {Promise<void>}\n */\n async flush () {\n if (this.#useMemoryFallback) {\n this.#memoryStore = undefined\n return\n }\n\n if (!this.#db) {\n throw new Error('DPoPStoreManager not initialized. Call init() first.')\n }\n\n return new Promise((resolve, reject) => {\n const transaction = /** @type {IDBDatabase} */ (this.#db).transaction(STORE_NAME, 'readwrite')\n const store = transaction.objectStore(STORE_NAME)\n const request = store.delete(STATE_KEY)\n\n request.onerror = () => {\n reject(request.error)\n }\n\n request.onsuccess = () => {\n resolve()\n }\n })\n }\n\n /**\n * Update only the nonce while preserving existing keys.\n * Convenience method for handling DPoP-Nonce header responses.\n * @param {string} nonce - The new nonce from the authorization server\n * @returns {Promise<void>}\n * @throws {Error} If nonce fails validation\n */\n async updateNonce (nonce) {\n assertValidNonce(nonce)\n\n const state = await this.get()\n if (state) {\n state.nonce = nonce\n await this.set(state)\n }\n }\n\n /**\n * Close the database connection.\n */\n close () {\n if (this.#db) {\n this.#db.close()\n this.#db = null\n }\n }\n}\n\nexport class DPoPSignatureProvider {\n /** @type {BrowserSignatureAlgs} */\n #alg\n /** @type {DPoPStoreManager} */\n #store\n /** @type {string[]} */\n #serverAllowedAlgorithms\n /** @type {Map<string, string>} Resource server nonces keyed by origin */\n #resourceNonces = new Map()\n /** @type {(() => number)|undefined} */\n #getTimeSkew\n /**\n * @param {DPoPSignatureProviderOptions} options\n */\n constructor (options) {\n const {\n issuerUrl,\n clientId,\n serverSupportedAlgorithms,\n requestedAlgorithm,\n strictStorage = false,\n getTimeSkew\n } = options\n this.#getTimeSkew = getTimeSkew\n\n // Check for Web Crypto API availability\n if (typeof crypto === 'undefined' || !crypto.subtle) {\n throw new Error('DPoP requires Web Crypto API (crypto.subtle) which is not available in this environment.')\n }\n\n // Validate required options\n if (!issuerUrl) {\n throw new Error('DPoP requires issuerUrl')\n }\n if (!clientId) {\n throw new Error('DPoP requires clientId')\n }\n if (!serverSupportedAlgorithms || !Array.isArray(serverSupportedAlgorithms)) {\n throw new Error('DPoP requires serverSupportedAlgorithms array')\n }\n this.#serverAllowedAlgorithms = serverSupportedAlgorithms\n\n let chosenAlgorithm = BrowserSignatureAlgs.ES256 // default value (due to high availability in browsers)\n\n if (requestedAlgorithm !== undefined) {\n // Check to see if requestedAlgorithm is supported by the server\n if (!this.#serverAllowedAlgorithms.includes(requestedAlgorithm)) {\n throw new Error(`Requested algorithm '${requestedAlgorithm}' is not supported by the server. Server supports: ${this.#serverAllowedAlgorithms.join(', ')}`)\n }\n\n chosenAlgorithm = requestedAlgorithm\n }\n\n this.#alg = chosenAlgorithm\n\n this.#store = new DPoPStoreManager(issuerUrl.toString(), clientId, strictStorage)\n }\n\n async init () {\n await this.#store.init()\n\n // Check for existing keys or generate new ones\n let state = await this.#store.get()\n if (state) {\n const expectedParams = /** @type {EcKeyGenParams & Algorithm} */ (KEY_GEN_PARAMS[this.#alg])\n const storedAlg = /** @type {EcKeyAlgorithm} */ (state.keys.publicKey.algorithm)\n if (storedAlg.name !== expectedParams.name ||\n (expectedParams.namedCurve && storedAlg.namedCurve !== expectedParams.namedCurve)) {\n console.warn('[KEYCLOAK] Stored DPoP key algorithm does not match requested algorithm, regenerating key pair.')\n await this.#store.flush()\n state = undefined\n }\n }\n if (!state) {\n const keys = await this.#generateKeyPair()\n state = { keys }\n await this.#store.set(state)\n }\n }\n\n /**\n * @returns {Promise<CryptoKeyPair>}\n */\n async #generateKeyPair () {\n const params = KEY_GEN_PARAMS[this.#alg]\n if (!params) {\n throw new Error(`Unknown signature algorithm: ${this.#alg}`)\n }\n\n try {\n return /** @type {CryptoKeyPair} */ (\n await crypto.subtle.generateKey(params, false, ['sign'])\n )\n } catch (ex) {\n if (!(ex instanceof DOMException && ex.name === 'NotSupportedError')) {\n throw ex\n }\n // Only EdDSA needs fallback; ECDSA is universally supported\n if (this.#alg !== BrowserSignatureAlgs.EdDSA) {\n throw ex\n }\n // Find the next available algorithm that both the browser and server support\n const fallback = ECDSA_FALLBACK_ORDER.find(alg =>\n this.#serverAllowedAlgorithms.includes(alg)\n )\n if (!fallback) {\n throw new Error('No supported algorithm available in this browser')\n }\n this.#alg = fallback\n return this.#generateKeyPair()\n }\n }\n\n /**\n * @param {Uint8Array<ArrayBuffer>} msg\n * @param {CryptoKey} key\n * @returns {Promise<ArrayBuffer>}\n */\n async #sign (msg, key) {\n const params = SIGN_PARAMS[this.#alg]\n if (!params) {\n throw new Error(`Unknown signature algorithm: ${this.#alg}`)\n }\n return await crypto.subtle.sign(params, key, msg)\n }\n\n /**\n * Clear all stored DPoP state (keys and nonce) for this client. Called on logout.\n * Only affects the keys for this specific issuer+clientId combination.\n * @returns {Promise<void>}\n */\n async flush () {\n await this.#store.flush()\n }\n\n /**\n * Get the stored authorization server nonce.\n * @returns {Promise<string | undefined>}\n */\n async getAuthServerNonce () {\n const state = await this.#store.get()\n return state?.nonce\n }\n\n /**\n * Update the authorization server nonce. Called after receiving DPoP-Nonce header.\n * @param {string} nonce\n * @returns {Promise<void>}\n */\n async updateAuthServerNonce (nonce) {\n await this.#store.updateNonce(nonce)\n }\n\n /**\n * Get the stored resource server nonce for a given origin.\n * @param {string} origin - The resource server origin (e.g., \"https://api.example.com\")\n * @returns {string | undefined} The stored nonce, or undefined if none exists\n */\n getResourceServerNonce (origin) {\n return this.#resourceNonces.get(origin)\n }\n\n /**\n * Update the resource server nonce for a given origin. Called after receiving DPoP-Nonce header.\n * Silently ignores invalid nonces to prevent DoS attacks.\n * @param {string} origin - The resource server origin\n * @param {string} nonce - The nonce from the DPoP-Nonce response header\n */\n updateResourceServerNonce (origin, nonce) {\n if (!isValidNonce(nonce)) {\n return\n }\n\n this.#resourceNonces.set(origin, nonce)\n }\n\n /**\n * @param {string} url\n * @param {string} httpMethod\n * @param {string} [accessToken] Access token if calling resource server\n * @param {string} [nonce] Server-provided nonce\n * @returns {Promise<string>}\n */\n async generateDPoPProof (url, httpMethod, accessToken, nonce) {\n const payload = {\n jti: crypto.randomUUID(),\n htm: httpMethod,\n htu: (() => {\n const urlObj = new URL(url)\n return urlObj.origin + urlObj.pathname\n })(),\n iat: Math.floor(Date.now() / 1000) - (this.#getTimeSkew?.() ?? 0),\n\n ...(accessToken !== undefined && {\n ath: base64UrlEncodeBuffer(await sha256Digest(accessToken))\n }),\n\n ...(nonce !== undefined && { nonce })\n }\n\n const state = await this.#store.get()\n if (state === undefined) throw new Error('DPoP not initialized')\n const exportedJwk = await crypto.subtle.exportKey('jwk', state.keys.publicKey)\n const header = {\n alg: this.#alg,\n typ: 'dpop+jwt',\n // Note: `y` is undefined for EdDSA/OKP keys (RFC 8037) but present for EC keys.\n // JSON.stringify omits undefined values, so this produces valid JWKs for both.\n jwk: {\n crv: exportedJwk.crv,\n kty: exportedJwk.kty,\n x: exportedJwk.x,\n y: exportedJwk.y\n }\n }\n\n const te = new TextEncoder()\n const unsignedToken = `${base64UrlEncodeBuffer(te.encode(JSON.stringify(header)))}.${base64UrlEncodeBuffer(te.encode(JSON.stringify(payload)))}`\n const signature = await this.#sign(te.encode(unsignedToken), state.keys.privateKey)\n return `${unsignedToken}.${base64UrlEncodeBuffer(signature)}`\n }\n}\n\n/**\n * @param {string} message\n * @see https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest#basic_example\n */\nasync function sha256Digest (message) {\n const encoder = new TextEncoder()\n const data = encoder.encode(message)\n\n if (typeof crypto === 'undefined' || typeof crypto.subtle === 'undefined') {\n throw new Error('Web Crypto API is not available.')\n }\n\n return await crypto.subtle.digest('SHA-256', data)\n}\n\n/**\n * @param {ArrayBuffer | Uint8Array} buffer\n */\nfunction base64UrlEncodeBuffer (buffer) {\n const bytes = buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer)\n const binary = String.fromCharCode(...bytes)\n\n return btoa(binary)\n .replaceAll('+', '-')\n .replaceAll('/', '_')\n .replaceAll('=', '')\n}\n"],"ignoreList":[0],"mappings":"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"}
|