From 1ed53f9803369a8afeb812326524252ccfc0f814 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Souto?= Date: Fri, 24 Apr 2026 19:40:16 +0200 Subject: [PATCH 1/2] chore: update package-lock.json --- package-lock.json | 379 +++++++++++++++++++++++++--------------------- 1 file changed, 206 insertions(+), 173 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3b87ee65a..4ffb2cfbd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1169,15 +1169,15 @@ } }, "node_modules/@angular/build/node_modules/@types/node": { - "version": "24.3.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.0.tgz", - "integrity": "sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow==", + "version": "25.6.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.6.0.tgz", + "integrity": "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==", "dev": true, "license": "MIT", "optional": true, "peer": true, "dependencies": { - "undici-types": "~7.10.0" + "undici-types": "~7.19.0" } }, "node_modules/@angular/build/node_modules/@vitejs/plugin-basic-ssl": { @@ -1263,9 +1263,9 @@ } }, "node_modules/@angular/build/node_modules/undici-types": { - "version": "7.10.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz", - "integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==", + "version": "7.19.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.19.2.tgz", + "integrity": "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==", "dev": true, "license": "MIT", "optional": true, @@ -3561,18 +3561,6 @@ "node": ">=6.0.0" } }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", - "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", @@ -6758,86 +6746,6 @@ "node": ">= 0.8" } }, - "node_modules/cacache": { - "version": "21.0.0", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-20.0.3.tgz", - "integrity": "sha512-3pUp4e8hv07k1QlijZu6Kn7c9+ZpWWk4j3F8N3xPuCExULobqJydKYOTj1FTq58srkJsXvO7LbGAH4C0ZU3WGw==", - "dev": true, - "license": "ISC", - "dependencies": { - "@npmcli/fs": "^5.0.0", - "fs-minipass": "^3.0.0", - "glob": "^13.0.0", - "lru-cache": "^11.1.0", - "minipass": "^7.0.3", - "minipass-collect": "^2.0.1", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "p-map": "^7.0.2", - "ssri": "^13.0.0", - "unique-filename": "^5.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/cacache/node_modules/glob": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.0.tgz", - "integrity": "sha512-tvZgpqk6fz4BaNZ66ZsRaZnbHvP/jG3uKJvAZOwEVUL4RTA5nJeeLYfyN9/VA8NX/V3IBG+hkeuGpKjvELkVhA==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "minimatch": "^10.1.1", - "minipass": "^7.1.2", - "path-scurry": "^2.0.0" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/cacache/node_modules/lru-cache": { - "version": "11.2.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.2.tgz", - "integrity": "sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==", - "dev": true, - "license": "ISC", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/cacache/node_modules/minimatch": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.1.tgz", - "integrity": "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/brace-expansion": "^5.0.0" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/cacache/node_modules/ssri": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-13.0.0.tgz", - "integrity": "sha512-yizwGBpbCn4YomB2lzhZqrHLJoqFGXihNbib3ozhqF/cIp5ue+xSmOQrjNasEE62hFxsCcg/V/z23t4n8jMEng==", - "dev": true, - "license": "ISC", - "dependencies": { - "minipass": "^7.0.3" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, "node_modules/call-bind": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", @@ -10722,17 +10630,6 @@ "colors": "1.4.0" } }, - "node_modules/jiti": { - "version": "1.21.0", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", - "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", - "dev": true, - "optional": true, - "peer": true, - "bin": { - "jiti": "bin/jiti.js" - } - }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -11691,6 +11588,95 @@ "node": "^20.17.0 || >=22.9.0" } }, + "node_modules/make-fetch-happen/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/make-fetch-happen/node_modules/brace-expansion": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/make-fetch-happen/node_modules/cacache": { + "version": "20.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-20.0.4.tgz", + "integrity": "sha512-M3Lab8NPYlZU2exsL3bMVvMrMqgwCnMWfdZbK28bn3pK6APT/Te/I8hjRPNu1uwORY9a1eEQoifXbKPQMfMTOA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/fs": "^5.0.0", + "fs-minipass": "^3.0.0", + "glob": "^13.0.0", + "lru-cache": "^11.1.0", + "minipass": "^7.0.3", + "minipass-collect": "^2.0.1", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^7.0.2", + "ssri": "^13.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/make-fetch-happen/node_modules/glob": { + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/make-fetch-happen/node_modules/lru-cache": { + "version": "11.3.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.5.tgz", + "integrity": "sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/make-fetch-happen/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/make-fetch-happen/node_modules/negotiator": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", @@ -11850,11 +11836,11 @@ } }, "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "engines": { "node": ">=16 || 14 >=14.17" } @@ -12913,6 +12899,108 @@ "node": "^20.17.0 || >=22.9.0" } }, + "node_modules/pacote/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/pacote/node_modules/brace-expansion": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/pacote/node_modules/cacache": { + "version": "20.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-20.0.4.tgz", + "integrity": "sha512-M3Lab8NPYlZU2exsL3bMVvMrMqgwCnMWfdZbK28bn3pK6APT/Te/I8hjRPNu1uwORY9a1eEQoifXbKPQMfMTOA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/fs": "^5.0.0", + "fs-minipass": "^3.0.0", + "glob": "^13.0.0", + "lru-cache": "^11.1.0", + "minipass": "^7.0.3", + "minipass-collect": "^2.0.1", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^7.0.2", + "ssri": "^13.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/pacote/node_modules/cacache/node_modules/ssri": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-13.0.1.tgz", + "integrity": "sha512-QUiRf1+u9wPTL/76GTYlKttDEBWV1ga9ZXW8BG6kfdeyyM8LGPix9gROyg9V2+P0xNyF3X2Go526xKFdMZrHSQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/pacote/node_modules/glob": { + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/pacote/node_modules/lru-cache": { + "version": "11.3.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.5.tgz", + "integrity": "sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/pacote/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -13105,9 +13193,9 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, "node_modules/path-scurry": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.1.tgz", - "integrity": "sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { @@ -13115,7 +13203,7 @@ "minipass": "^7.1.2" }, "engines": { - "node": "20 || >=22" + "node": "18 || 20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -14753,35 +14841,6 @@ "node": ">=18" } }, - "node_modules/terser": { - "version": "5.43.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.43.1.tgz", - "integrity": "sha512-+6erLbBm0+LROX2sPXlUYx/ux5PyE9K/a92Wrt6oA+WDAoFTdpHE5tCYCI5PNzq2y8df4rA+QgHLJuR4jNymsg==", - "dev": true, - "license": "BSD-2-Clause", - "optional": true, - "peer": true, - "dependencies": { - "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.14.0", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/terser/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true, - "optional": true, - "peer": true - }, "node_modules/through2": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", @@ -15188,32 +15247,6 @@ "dev": true, "license": "MIT" }, - "node_modules/unique-filename": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-5.0.0.tgz", - "integrity": "sha512-2RaJTAvAb4owyjllTfXzFClJ7WsGxlykkPvCr9pA//LD9goVq+m4PPAeBgNodGZ7nSrntT/auWpJ6Y5IFXcfjg==", - "dev": true, - "license": "ISC", - "dependencies": { - "unique-slug": "^6.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/unique-slug": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-6.0.0.tgz", - "integrity": "sha512-4Lup7Ezn8W3d52/xBhZBVdx323ckxa7DEvd9kPQHppTkLoJXw6ltrBCyj5pnrxj0qKDxYMJ56CoxNuFCscdTiw==", - "dev": true, - "license": "ISC", - "dependencies": { - "imurmurhash": "^0.1.4" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, "node_modules/universalify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", From 0638f4f6a324011a170632a42f57598e2add4674 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Souto?= Date: Fri, 24 Apr 2026 16:23:34 +0200 Subject: [PATCH 2/2] fix: refresh authWellKnownEndpoints when the server updates them fix #1983 --- .../auth-well-known-data.service.spec.ts | 51 +++++++++-------- .../auth-well-known-data.service.ts | 8 +-- .../auth-well-known.service.spec.ts | 55 ++++++++++++++++++- .../auth-well-known.service.ts | 8 ++- .../src/lib/config/config.service.spec.ts | 22 ++------ .../src/lib/config/config.service.ts | 20 ------- 6 files changed, 96 insertions(+), 68 deletions(-) diff --git a/projects/angular-auth-oidc-client/src/lib/config/auth-well-known/auth-well-known-data.service.spec.ts b/projects/angular-auth-oidc-client/src/lib/config/auth-well-known/auth-well-known-data.service.spec.ts index 4e1f11035..8affab42f 100644 --- a/projects/angular-auth-oidc-client/src/lib/config/auth-well-known/auth-well-known-data.service.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/config/auth-well-known/auth-well-known-data.service.spec.ts @@ -216,12 +216,12 @@ describe('AuthWellKnownDataService', () => { }); })); - it('should merge the mapped endpoints with the provided endpoints', waitForAsync(() => { + it('maps only server-fetched endpoints without merging config overrides', waitForAsync(() => { spyOn(dataService, 'get').and.returnValue(of(DUMMY_WELL_KNOWN_DOCUMENT)); const expected: AuthWellKnownEndpoints = { - endSessionEndpoint: 'config-endSessionEndpoint', - revocationEndpoint: 'config-revocationEndpoint', + endSessionEndpoint: DUMMY_WELL_KNOWN_DOCUMENT.end_session_endpoint, + tokenEndpoint: DUMMY_WELL_KNOWN_DOCUMENT.token_endpoint, jwksUri: DUMMY_WELL_KNOWN_DOCUMENT.jwks_uri }; @@ -236,6 +236,10 @@ describe('AuthWellKnownDataService', () => { }) .subscribe((result) => { expect(result).toEqual(jasmine.objectContaining(expected)); + expect(result.endSessionEndpoint).not.toBe('config-endSessionEndpoint'); + expect(result.tokenEndpoint).toBe( + DUMMY_WELL_KNOWN_DOCUMENT.token_endpoint + ); }); })); @@ -324,7 +328,8 @@ describe('AuthWellKnownDataService', () => { }); })); - it('should merge the mapped endpoints with the provided endpoints and ignore issuer/authwellknownUrl mismatch', waitForAsync(() => { + it('throws error for issuer mismatch even when authWellknownEndpoints has issuer override', waitForAsync(() => { + const loggerSpy = spyOn(loggerService, 'logError'); const maliciousWellKnown = { ...DUMMY_WELL_KNOWN_DOCUMENT, issuer: DUMMY_MALICIOUS_URL @@ -332,26 +337,28 @@ describe('AuthWellKnownDataService', () => { spyOn(dataService, 'get').and.returnValue(of(maliciousWellKnown)); - const expected: AuthWellKnownEndpoints = { - endSessionEndpoint: 'config-endSessionEndpoint', - revocationEndpoint: 'config-revocationEndpoint', - jwksUri: DUMMY_WELL_KNOWN_DOCUMENT.jwks_uri, - issuer: DUMMY_WELL_KNOWN_DOCUMENT.issuer, + const config = { + configId: 'configId1', + authWellknownEndpointUrl: DUMMY_WELL_KNOWN_DOCUMENT.issuer, + authWellknownEndpoints: { + endSessionEndpoint: 'config-endSessionEndpoint', + revocationEndpoint: 'config-revocationEndpoint', + issuer: DUMMY_WELL_KNOWN_DOCUMENT.issuer + }, }; - service - .getWellKnownEndPointsForConfig({ - configId: 'configId1', - authWellknownEndpointUrl: DUMMY_WELL_KNOWN_DOCUMENT.issuer, - authWellknownEndpoints: { - endSessionEndpoint: 'config-endSessionEndpoint', - revocationEndpoint: 'config-revocationEndpoint', - issuer: DUMMY_WELL_KNOWN_DOCUMENT.issuer - }, - }) - .subscribe((result) => { - expect(result).toEqual(jasmine.objectContaining(expected)); - }); + service.getWellKnownEndPointsForConfig(config).subscribe({ + next: (result) => { + fail(`Retrieval was supposed to fail. Well known endpoints returned : ${JSON.stringify(result)}`); + }, + error: (error) => { + expect(loggerSpy).toHaveBeenCalledOnceWith( + config, + `Issuer mismatch. Well known issuer ${DUMMY_MALICIOUS_URL} does not match configured well known url ${DUMMY_WELL_KNOWN_DOCUMENT.issuer}` + ); + expect(error.message).toEqual(`Issuer mismatch. Well known issuer ${DUMMY_MALICIOUS_URL} does not match configured well known url ${DUMMY_WELL_KNOWN_DOCUMENT.issuer}`); + } + }); })); }); }); diff --git a/projects/angular-auth-oidc-client/src/lib/config/auth-well-known/auth-well-known-data.service.ts b/projects/angular-auth-oidc-client/src/lib/config/auth-well-known/auth-well-known-data.service.ts index 95509e5b7..865a35d26 100644 --- a/projects/angular-auth-oidc-client/src/lib/config/auth-well-known/auth-well-known-data.service.ts +++ b/projects/angular-auth-oidc-client/src/lib/config/auth-well-known/auth-well-known-data.service.ts @@ -16,7 +16,7 @@ export class AuthWellKnownDataService { getWellKnownEndPointsForConfig( config: OpenIdConfiguration ): Observable { - const { authWellknownEndpointUrl, authWellknownEndpoints = {} } = config; + const { authWellknownEndpointUrl } = config; if (!authWellknownEndpointUrl) { const errorMessage = 'no authWellknownEndpoint given!'; @@ -43,16 +43,12 @@ export class AuthWellKnownDataService { wellKnownEndpoints.pushed_authorization_request_endpoint, } as AuthWellKnownEndpoints) ), - map((mappedWellKnownEndpoints) => ({ - ...mappedWellKnownEndpoints, - ...authWellknownEndpoints, - })), tap( (wellKnownEndpoints) => { const issuer = wellKnownEndpoints.issuer || ""; const wellKnownSuffix = config.authWellknownUrlSuffix || WELL_KNOWN_SUFFIX; const configuredWellKnownEndpoint = authWellknownEndpointUrl.replace(wellKnownSuffix, ""); - + if (!config.strictIssuerValidationOnWellKnownRetrievalOff && issuer !== configuredWellKnownEndpoint && issuer !== `${configuredWellKnownEndpoint}/`) { const errorMessage = `Issuer mismatch. Well known issuer ${wellKnownEndpoints.issuer} does not match configured well known url ${authWellknownEndpointUrl}`; diff --git a/projects/angular-auth-oidc-client/src/lib/config/auth-well-known/auth-well-known.service.spec.ts b/projects/angular-auth-oidc-client/src/lib/config/auth-well-known/auth-well-known.service.spec.ts index 099d93ecb..971520212 100644 --- a/projects/angular-auth-oidc-client/src/lib/config/auth-well-known/auth-well-known.service.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/config/auth-well-known/auth-well-known.service.spec.ts @@ -48,7 +48,7 @@ describe('AuthWellKnownService', () => { }); })); - it('getAuthWellKnownEndPoints calls always dataservice', waitForAsync(() => { + it('calls dataservice when no explicit endpoints are configured', waitForAsync(() => { const dataServiceSpy = spyOn( dataService, 'getWellKnownEndPointsForConfig' @@ -106,5 +106,58 @@ describe('AuthWellKnownService', () => { }, }); })); + + it('does not call dataservice when authWellknownEndpoints is explicitly configured', waitForAsync(() => { + const explicitEndpoints = { issuer: 'https://explicit.example.com', tokenEndpoint: 'https://explicit.example.com/token' }; + const dataServiceSpy = spyOn(dataService, 'getWellKnownEndPointsForConfig'); + + service + .queryAndStoreAuthWellKnownEndPoints({ + configId: 'configId1', + authWellknownEndpoints: explicitEndpoints, + }) + .subscribe((result) => { + expect(dataServiceSpy).not.toHaveBeenCalled(); + expect(result).toEqual(explicitEndpoints); + }); + })); + + it('stores and returns explicit endpoints without discovery request', waitForAsync(() => { + const explicitEndpoints = { issuer: 'https://explicit.example.com', tokenEndpoint: 'https://explicit.example.com/token' }; + const storeSpy = spyOn(service, 'storeWellKnownEndpoints'); + + spyOn(dataService, 'getWellKnownEndPointsForConfig'); + + service + .queryAndStoreAuthWellKnownEndPoints({ + configId: 'configId1', + authWellknownEndpoints: explicitEndpoints, + }) + .subscribe((result) => { + expect(storeSpy).toHaveBeenCalledOnceWith( + jasmine.objectContaining({ configId: 'configId1' }), + explicitEndpoints + ); + expect(result).toEqual(explicitEndpoints); + }); + })); + + it('always fetches fresh endpoints in discovery mode, ignoring previously stored values', waitForAsync(() => { + const freshEndpoints = { issuer: 'https://server.example.com', tokenEndpoint: 'https://server.example.com/token/fresh' }; + const dataServiceSpy = spyOn(dataService, 'getWellKnownEndPointsForConfig').and.returnValue(of(freshEndpoints)); + const storeSpy = spyOn(service, 'storeWellKnownEndpoints'); + + // config has NO explicit authWellknownEndpoints → discovery path + service + .queryAndStoreAuthWellKnownEndPoints({ configId: 'configId1' }) + .subscribe((result) => { + expect(dataServiceSpy).toHaveBeenCalled(); + expect(storeSpy).toHaveBeenCalledOnceWith( + jasmine.objectContaining({ configId: 'configId1' }), + freshEndpoints + ); + expect(result).toEqual(freshEndpoints); + }); + })); }); }); diff --git a/projects/angular-auth-oidc-client/src/lib/config/auth-well-known/auth-well-known.service.ts b/projects/angular-auth-oidc-client/src/lib/config/auth-well-known/auth-well-known.service.ts index e2323d046..d29fe2ffd 100644 --- a/projects/angular-auth-oidc-client/src/lib/config/auth-well-known/auth-well-known.service.ts +++ b/projects/angular-auth-oidc-client/src/lib/config/auth-well-known/auth-well-known.service.ts @@ -1,5 +1,5 @@ import { inject, Injectable } from '@angular/core'; -import { Observable, throwError } from 'rxjs'; +import { Observable, of, throwError } from 'rxjs'; import { catchError, tap } from 'rxjs/operators'; import { EventTypes } from '../../public-events/event-types'; import { PublicEventsService } from '../../public-events/public-events.service'; @@ -39,6 +39,12 @@ export class AuthWellKnownService { ); } + if (config.authWellknownEndpoints) { + this.storeWellKnownEndpoints(config, config.authWellknownEndpoints); + + return of(config.authWellknownEndpoints); + } + return this.dataService.getWellKnownEndPointsForConfig(config).pipe( tap((mappedWellKnownEndpoints) => this.storeWellKnownEndpoints(config, mappedWellKnownEndpoints) diff --git a/projects/angular-auth-oidc-client/src/lib/config/config.service.spec.ts b/projects/angular-auth-oidc-client/src/lib/config/config.service.spec.ts index 394543e43..9d4e01bb1 100644 --- a/projects/angular-auth-oidc-client/src/lib/config/config.service.spec.ts +++ b/projects/angular-auth-oidc-client/src/lib/config/config.service.spec.ts @@ -4,7 +4,6 @@ import { mockAbstractProvider, mockProvider } from '../../test/auto-mock'; import { LoggerService } from '../logging/logger.service'; import { EventTypes } from '../public-events/event-types'; import { PublicEventsService } from '../public-events/public-events.service'; -import { StoragePersistenceService } from '../storage/storage-persistence.service'; import { PlatformProvider } from '../utils/platform-provider/platform.provider'; import { AuthWellKnownService } from './auth-well-known/auth-well-known.service'; import { ConfigurationService } from './config.service'; @@ -16,7 +15,6 @@ describe('Configuration Service', () => { let configService: ConfigurationService; let publicEventsService: PublicEventsService; let authWellKnownService: AuthWellKnownService; - let storagePersistenceService: StoragePersistenceService; let configValidationService: ConfigValidationService; let platformProvider: PlatformProvider; let stsConfigLoader: StsConfigLoader; @@ -27,7 +25,6 @@ describe('Configuration Service', () => { ConfigurationService, mockProvider(LoggerService), PublicEventsService, - mockProvider(StoragePersistenceService), ConfigValidationService, mockProvider(PlatformProvider), mockProvider(AuthWellKnownService), @@ -40,7 +37,6 @@ describe('Configuration Service', () => { configService = TestBed.inject(ConfigurationService); publicEventsService = TestBed.inject(PublicEventsService); authWellKnownService = TestBed.inject(AuthWellKnownService); - storagePersistenceService = TestBed.inject(StoragePersistenceService); stsConfigLoader = TestBed.inject(StsConfigLoader); platformProvider = TestBed.inject(PlatformProvider); configValidationService = TestBed.inject(ConfigValidationService); @@ -141,33 +137,24 @@ describe('Configuration Service', () => { }); })); - it(`sets authWellKnownEndPoints on config if authWellKnownEndPoints is stored`, waitForAsync(() => { + it(`does not set authWellknownEndpoints on config from storage`, waitForAsync(() => { const configs = [{ configId: 'configId1' }]; spyOn(configService as any, 'loadConfigs').and.returnValue(of(configs)); spyOn(configValidationService, 'validateConfig').and.returnValue(true); const consoleSpy = spyOn(console, 'warn'); - spyOn(storagePersistenceService, 'read').and.returnValue({ - issuer: 'auth-well-known', - }); - configService.getOpenIDConfiguration('configId1').subscribe((config) => { - expect(config?.authWellknownEndpoints).toEqual({ - issuer: 'auth-well-known', - }); - expect(consoleSpy).not.toHaveBeenCalled() + expect(config?.authWellknownEndpoints).toBeUndefined(); + expect(consoleSpy).not.toHaveBeenCalled(); }); })); - it(`fires ConfigLoaded if authWellKnownEndPoints is stored`, waitForAsync(() => { + it(`fires ConfigLoaded when configuration is loaded`, waitForAsync(() => { const configs = [{ configId: 'configId1' }]; spyOn(configService as any, 'loadConfigs').and.returnValue(of(configs)); spyOn(configValidationService, 'validateConfig').and.returnValue(true); - spyOn(storagePersistenceService, 'read').and.returnValue({ - issuer: 'auth-well-known', - }); const spy = spyOn(publicEventsService, 'fireEvent'); @@ -189,7 +176,6 @@ describe('Configuration Service', () => { spyOn(configService as any, 'loadConfigs').and.returnValue(of(configs)); spyOn(configValidationService, 'validateConfig').and.returnValue(true); - spyOn(storagePersistenceService, 'read').and.returnValue(null); const fireEventSpy = spyOn(publicEventsService, 'fireEvent'); const storeWellKnownEndpointsSpy = spyOn( diff --git a/projects/angular-auth-oidc-client/src/lib/config/config.service.ts b/projects/angular-auth-oidc-client/src/lib/config/config.service.ts index 9b10b5a87..eaab8fc87 100644 --- a/projects/angular-auth-oidc-client/src/lib/config/config.service.ts +++ b/projects/angular-auth-oidc-client/src/lib/config/config.service.ts @@ -4,7 +4,6 @@ import { concatMap, map } from 'rxjs/operators'; import { LoggerService } from '../logging/logger.service'; import { EventTypes } from '../public-events/event-types'; import { PublicEventsService } from '../public-events/public-events.service'; -import { StoragePersistenceService } from '../storage/storage-persistence.service'; import { PlatformProvider } from '../utils/platform-provider/platform.provider'; import { AuthWellKnownService } from './auth-well-known/auth-well-known.service'; import { DEFAULT_CONFIG } from './default-config'; @@ -18,9 +17,6 @@ export class ConfigurationService { private readonly loggerService = inject(LoggerService); private readonly publicEventsService = inject(PublicEventsService); - private readonly storagePersistenceService = inject( - StoragePersistenceService - ); private readonly platformProvider = inject(PlatformProvider); private readonly authWellKnownService = inject(AuthWellKnownService); private readonly loader = inject(StsConfigLoader); @@ -154,19 +150,6 @@ export class ConfigurationService { private enhanceConfigWithWellKnownEndpoint( configuration: OpenIdConfiguration ): OpenIdConfiguration { - const alreadyExistingAuthWellKnownEndpoints = - this.storagePersistenceService.read( - 'authWellKnownEndPoints', - configuration - ); - - if (!!alreadyExistingAuthWellKnownEndpoints) { - configuration.authWellknownEndpoints = - alreadyExistingAuthWellKnownEndpoints; - - return configuration; - } - const passedAuthWellKnownEndpoints = configuration.authWellknownEndpoints; if (!!passedAuthWellKnownEndpoints) { @@ -174,9 +157,6 @@ export class ConfigurationService { configuration, passedAuthWellKnownEndpoints ); - configuration.authWellknownEndpoints = passedAuthWellKnownEndpoints; - - return configuration; } return configuration;