diff --git a/.github/workflows/deploy_commit_to_dev.yml b/.github/workflows/deploy_commit_to_dev.yml index f59770591..6731a02c0 100644 --- a/.github/workflows/deploy_commit_to_dev.yml +++ b/.github/workflows/deploy_commit_to_dev.yml @@ -40,6 +40,8 @@ jobs: run: export TZ=utc - name: Install dependencies run: npm ci --ignore-scripts + env: + NPM_AUTH_TOKEN: ${{ secrets.READER_TOKEN }} - name: Get jest cache directory run: | jest_command=node_modules/jest-cli/bin/jest.js # fordi å installere jest med npx tar ti sekunder diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml index 08e5c06d3..95d5092a9 100644 --- a/.github/workflows/master.yml +++ b/.github/workflows/master.yml @@ -28,6 +28,8 @@ jobs: run: export TZ=utc - name: Install dependencies run: npm ci --ignore-scripts + env: + NPM_AUTH_TOKEN: ${{ secrets.READER_TOKEN }} - name: Get jest cache directory run: | jest_command=node_modules/jest-cli/bin/jest.js # fordi å installere jest med npx tar ti sekunder diff --git a/.github/workflows/pull-requests.yml b/.github/workflows/pull-requests.yml index 5def12f95..84a686d57 100644 --- a/.github/workflows/pull-requests.yml +++ b/.github/workflows/pull-requests.yml @@ -15,6 +15,8 @@ jobs: cache-dependency-path: 'package-lock.json' - name: install dependencies run: npm ci --ignore-scripts + env: + NPM_AUTH_TOKEN: ${{ secrets.READER_TOKEN }} - name: test run: npm run test - name: build diff --git a/.npmrc b/.npmrc index b6f27f135..a7b3a4c8a 100644 --- a/.npmrc +++ b/.npmrc @@ -1 +1,4 @@ +@navikt:registry=https://npm.pkg.github.com +//npm.pkg.github.com/:_authToken=${NPM_AUTH_TOKEN} + engine-strict=true diff --git a/README.md b/README.md index 3785c291f..498548bcc 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,17 @@ SPESIALIST_WS_URL=ws://127.0.0.1:9001 EOF ``` +### Sett opp tilgang til Github Package Registry + +For å kunne laste dependencies fra Github Package Registry +må du ha et Github Personal Access satt i miljøvariabelen `NPM_AUTH_TOKEN`. + +Dette tokenet trenger scopet `package:read`. Legg til følgende i `~/.bashrc` eller `~/.zshrc`: + +```shell +export NPM_AUTH_TOKEN= +``` + ### Både frontend og backend med én kommando ```shell diff --git a/deploy/dev.yml b/deploy/dev.yml index ec5fbd433..c474f3133 100644 --- a/deploy/dev.yml +++ b/deploy/dev.yml @@ -52,6 +52,11 @@ spec: generatedConfig: mountPath: /app/dist/client/nais/nais azure: + sidecar: + enabled: true + autoLogin: true + autoLoginIgnorePaths: + - /static/* application: enabled: true tenant: nav.no diff --git a/deploy/prod.yml b/deploy/prod.yml index 8ab29908f..3149034d8 100644 --- a/deploy/prod.yml +++ b/deploy/prod.yml @@ -51,6 +51,11 @@ spec: generatedConfig: mountPath: /app/dist/client/nais/nais azure: + sidecar: + enabled: true + autoLogin: true + autoLoginIgnorePaths: + - /static/* application: enabled: true claims: diff --git a/package-lock.json b/package-lock.json index 8ccb6489c..a336db91e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2074,6 +2074,32 @@ "@floating-ui/utils": "^0.1.3" } }, + "node_modules/@floating-ui/react": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.25.4.tgz", + "integrity": "sha512-lWRQ/UiTvSIBxohn0/2HFHEmnmOVRjl7j6XcRJuLH0ls6f/9AyHMWVzkAJFuwx0n9gaEeCmg9VccCSCJzbEJig==", + "dependencies": { + "@floating-ui/react-dom": "^2.0.2", + "@floating-ui/utils": "^0.1.1", + "tabbable": "^6.0.1" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.0.tgz", + "integrity": "sha512-lNzj5EQmEKn5FFKc04+zasr09h/uX8RtJRNj5gUXsSQIXHVWTVh+hVAg1vOMCexkX8EgvemMvIFpQfkosnVNyA==", + "dependencies": { + "@floating-ui/dom": "^1.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, "node_modules/@floating-ui/utils": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.1.3.tgz", @@ -4354,35 +4380,79 @@ "node": ">=12" } }, + "node_modules/@navikt/aksel-icons": { + "version": "6.8.0", + "resolved": "https://npm.pkg.github.com/download/@navikt/aksel-icons/6.8.0/2644182b35d898d068d9978cf1620a0405770a70", + "integrity": "sha512-XiEr0Xb0BDaStrpGCuEPvNgvHalbL4dPh6HAA7jGV7cHnW6Zsb54Hsaq6dLMXIDYEpPQv2T27j25UvoRxVuk8g==" + }, "node_modules/@navikt/ds-css": { "version": "6.8.0", - "resolved": "https://registry.npmjs.org/@navikt/ds-css/-/ds-css-6.8.0.tgz", + "resolved": "https://npm.pkg.github.com/download/@navikt/ds-css/6.8.0/017d4c13ef3140df2509b0c4a6b1e25ad40ee20d", "integrity": "sha512-qHXpJL2TZTv3MELLTY+o16X+iqPsrKzZhVwI2obnDJUIYTMvZfwR7BQCofL7nj9pDm5Y/jvUeTxdvIxzDHnUtg==" }, "node_modules/@navikt/ds-css-internal": { "version": "2.9.8", - "resolved": "https://registry.npmjs.org/@navikt/ds-css-internal/-/ds-css-internal-2.9.8.tgz", + "resolved": "https://npm.pkg.github.com/download/@navikt/ds-css-internal/2.9.8/09baada0d399ca309c34bcfb3908276795fa1e96", "integrity": "sha512-fXyQnD9VdBqETb+X0RnMEB97uJZVwTkzeqZ4m6YvdakEGRKOZTs251v1PnT5menH5i5XL+Yg5KZp5RLjOaAzFQ==" }, "node_modules/@navikt/ds-icons": { "version": "2.9.8", - "resolved": "https://registry.npmjs.org/@navikt/ds-icons/-/ds-icons-2.9.8.tgz", + "resolved": "https://npm.pkg.github.com/download/@navikt/ds-icons/2.9.8/b6f22493a3b836e00762dcc0a4397c64beb634e0", "integrity": "sha512-5IdVN4rmpXnznQMUz5YPxDoY17nykV3Oy/YCpq6gF69JRbhjwgQ+4LI/eV1tFFLaM/EW73qFCaEzhP0DY3prEw==", "peerDependencies": { "@types/react": "^17.0.30 || ^18.0.0", "react": "^17.0.0 || ^18.0.0" + } + }, + "node_modules/@navikt/ds-react": { + "version": "6.8.0", + "resolved": "https://npm.pkg.github.com/download/@navikt/ds-react/6.8.0/86f903a76ac9f7ee9c3e2aa0c339932fc6dbb063", + "integrity": "sha512-FW2NndVzdVUTBselUzRa1vrkqpJDmHF6cG5A9bg5Y3Y4Aq2uQ07KvDUBzLP+rZz0i4bJ/gkrtoFF74nQRtmKkg==", + "dependencies": { + "@floating-ui/react": "0.25.4", + "@floating-ui/react-dom": "^2.0.9", + "@navikt/aksel-icons": "^6.8.0", + "@navikt/ds-tokens": "^6.8.0", + "clsx": "^2.1.0", + "date-fns": "^3.0.0", + "react-day-picker": "8.10.0" }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } + "peerDependencies": { + "@types/react": "^17.0.30 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0" + } + }, + "node_modules/@navikt/ds-react/node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "engines": { + "node": ">=6" } }, "node_modules/@navikt/ds-tokens": { "version": "6.8.0", - "resolved": "https://registry.npmjs.org/@navikt/ds-tokens/-/ds-tokens-6.8.0.tgz", + "resolved": "https://npm.pkg.github.com/download/@navikt/ds-tokens/6.8.0/01e24b0e8ed89349aeb5d4482dec14b5fb1a5df9", "integrity": "sha512-KK2RMX5yCnw8NdwmX5ZSA5LoFX0hQlkpba9CopUGOPxHdC0vOz0CfYwNqJgUhP/HPy2E2GHN37HOWkonqv7BCw==" }, + "node_modules/@navikt/oasis": { + "version": "3.3.0", + "resolved": "https://npm.pkg.github.com/download/@navikt/oasis/3.3.0/0d6116b68e84598184f94a86087eee68d8f929a1", + "integrity": "sha512-G7isyO9uTxFoPv6U7SgASfsxVJCrvNJMToDx5Lo3kP1OtczaM2oc41XB3ssDrqMMq9kz6PHKoUwGcGaRd0XxjA==", + "dependencies": { + "jose": "^5.2.3", + "openid-client": "^5.6.5", + "prom-client": "^15.1.0" + } + }, + "node_modules/@navikt/oasis/node_modules/jose": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/jose/-/jose-5.3.0.tgz", + "integrity": "sha512-IChe9AtAE79ru084ow8jzkN2lNrG3Ntfiv65Cvj9uOCE2m5LNsdHG+9EbxWxAoWRF9TgDOqLN5jm08++owDVRg==", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, "node_modules/@nicolo-ribaudo/chokidar-2": { "version": "2.1.8-no-fsevents.3", "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz", @@ -6391,18 +6461,6 @@ } } }, - "node_modules/@radix-ui/react-popper/node_modules/@floating-ui/react-dom": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.4.tgz", - "integrity": "sha512-CF8k2rgKeh/49UrnIBs4BdxPUV6vize/Db1d/YbCLyp9GiVZ0BEwf5AiDSxJRCr6yOkGqTFHtmrULxkEfYZ7dQ==", - "dependencies": { - "@floating-ui/dom": "^1.5.1" - }, - "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" - } - }, "node_modules/@radix-ui/react-popper/node_modules/@radix-ui/react-compose-refs": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.1.tgz", @@ -6981,64 +7039,6 @@ "@babel/runtime": "^7.13.10" } }, - "node_modules/@redis/bloom": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.2.0.tgz", - "integrity": "sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==", - "peerDependencies": { - "@redis/client": "^1.0.0" - } - }, - "node_modules/@redis/client": { - "version": "1.5.13", - "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.5.13.tgz", - "integrity": "sha512-epkUM9D0Sdmt93/8Ozk43PNjLi36RZzG+d/T1Gdu5AI8jvghonTeLYV69WVWdilvFo+PYxbP0TZ0saMvr6nscQ==", - "dependencies": { - "cluster-key-slot": "1.1.2", - "generic-pool": "3.9.0", - "yallist": "4.0.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@redis/client/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "node_modules/@redis/graph": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.1.1.tgz", - "integrity": "sha512-FEMTcTHZozZciLRl6GiiIB4zGm5z5F3F6a6FZCyrfxdKOhFlGkiAqlexWMBzCi4DcRoyiOsuLfW+cjlGWyExOw==", - "peerDependencies": { - "@redis/client": "^1.0.0" - } - }, - "node_modules/@redis/json": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.6.tgz", - "integrity": "sha512-rcZO3bfQbm2zPRpqo82XbW8zg4G/w4W3tI7X8Mqleq9goQjAGLL7q/1n1ZX4dXEAmORVZ4s1+uKLaUOg7LrUhw==", - "peerDependencies": { - "@redis/client": "^1.0.0" - } - }, - "node_modules/@redis/search": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/@redis/search/-/search-1.1.6.tgz", - "integrity": "sha512-mZXCxbTYKBQ3M2lZnEddwEAks0Kc7nauire8q20oA0oA/LoA+E/b5Y5KZn232ztPb1FkIGqo12vh3Lf+Vw5iTw==", - "peerDependencies": { - "@redis/client": "^1.0.0" - } - }, - "node_modules/@redis/time-series": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.0.5.tgz", - "integrity": "sha512-IFjIgTusQym2B5IZJG3XKr5llka7ey84fw/NOYqESP5WUfQs9zz1ww/9+qoz4ka/S6KcGBodzlCeZ5UImKbscg==", - "peerDependencies": { - "@redis/client": "^1.0.0" - } - }, "node_modules/@remix-run/router": { "version": "1.14.0", "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.14.0.tgz", @@ -7992,8 +7992,7 @@ "node_modules/@types/prop-types": { "version": "15.7.5", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", - "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==", - "devOptional": true + "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" }, "node_modules/@types/qs": { "version": "6.9.8", @@ -8011,7 +8010,6 @@ "version": "18.2.45", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.45.tgz", "integrity": "sha512-TtAxCNrlrBp8GoeEp1npd5g+d/OejJHFxS3OWmrPBMFaVQMSN0OFySozJio5BHxTuTeug00AVXVAjfDSfk+lUg==", - "devOptional": true, "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -8096,8 +8094,7 @@ "node_modules/@types/scheduler": { "version": "0.16.3", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz", - "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==", - "devOptional": true + "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==" }, "node_modules/@types/semver": { "version": "7.5.2", @@ -10321,14 +10318,6 @@ "node": ">=6" } }, - "node_modules/cluster-key-slot": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", - "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/cmd-shim": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/cmd-shim/-/cmd-shim-6.0.1.tgz", @@ -10568,17 +10557,6 @@ "typedarray": "^0.0.6" } }, - "node_modules/connect-redis": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/connect-redis/-/connect-redis-7.1.0.tgz", - "integrity": "sha512-UaqO1EirWjON2ENsyau7N5lbkrdYBpS6mYlXSeff/OYXsd6EGZ+SXSmNPoljL2PSua8fgjAEaldSA73PMZQ9Eg==", - "engines": { - "node": ">=16" - }, - "peerDependencies": { - "express-session": ">=1" - } - }, "node_modules/console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", @@ -10985,8 +10963,7 @@ "node_modules/csstype": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", - "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==", - "devOptional": true + "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" }, "node_modules/dargs": { "version": "7.0.0", @@ -11017,6 +10994,15 @@ "integrity": "sha512-8YnDaaf7N3k/q5HnTJVuzSyLETjoZjVmHc4AeKAzOvKHEFQKcn64OKBfzHYtE9zGjctNM7V9I0MfnUVLpi7M5g==", "dev": true }, + "node_modules/date-fns": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz", + "integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, "node_modules/dateformat": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", @@ -12660,64 +12646,6 @@ "node": ">= 0.10.0" } }, - "node_modules/express-session": { - "version": "1.17.3", - "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.17.3.tgz", - "integrity": "sha512-4+otWXlShYlG1Ma+2Jnn+xgKUZTMJ5QD3YvfilX3AcocOAbIkVylSWEklzALe/+Pu4qV6TYBj5GwOBFfdKqLBw==", - "dependencies": { - "cookie": "0.4.2", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "~2.0.0", - "on-headers": "~1.0.2", - "parseurl": "~1.3.3", - "safe-buffer": "5.2.1", - "uid-safe": "~2.1.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/express-session/node_modules/cookie": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", - "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/express-session/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/express-session/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "node_modules/express-session/node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, "node_modules/express-ws": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/express-ws/-/express-ws-5.0.2.tgz", @@ -13335,14 +13263,6 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/generic-pool": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz", - "integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==", - "engines": { - "node": ">= 4" - } - }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -20039,11 +19959,11 @@ } }, "node_modules/openid-client": { - "version": "5.6.1", - "resolved": "https://registry.npmjs.org/openid-client/-/openid-client-5.6.1.tgz", - "integrity": "sha512-PtrWsY+dXg6y8mtMPyL/namZSYVz8pjXz3yJiBNZsEdCnu9miHLB4ELVC85WvneMKo2Rg62Ay7NkuCpM0bgiLQ==", + "version": "5.6.5", + "resolved": "https://registry.npmjs.org/openid-client/-/openid-client-5.6.5.tgz", + "integrity": "sha512-5P4qO9nGJzB5PI0LFlhj4Dzg3m4odt0qsJTfyEtZyOlkgpILwEioOhVVJOrS1iVH494S4Ee5OCjjg6Bf5WOj3w==", "dependencies": { - "jose": "^4.15.1", + "jose": "^4.15.5", "lru-cache": "^6.0.0", "object-hash": "^2.2.0", "oidc-token-hash": "^5.0.3" @@ -21326,14 +21246,6 @@ "node": ">=8" } }, - "node_modules/random-bytes": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", - "integrity": "sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -21375,6 +21287,19 @@ "node": ">=0.10.0" } }, + "node_modules/react-day-picker": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/react-day-picker/-/react-day-picker-8.10.0.tgz", + "integrity": "sha512-mz+qeyrOM7++1NCb1ARXmkjMkzWVh2GL9YiPbRjKe0zHccvekk4HE+0MPOZOrosn8r8zTHIIeOUXTmXRqmkRmg==", + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/gpbl" + }, + "peerDependencies": { + "date-fns": "^2.28.0 || ^3.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/react-dom": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", @@ -21991,19 +21916,6 @@ "node": ">=8" } }, - "node_modules/redis": { - "version": "4.6.12", - "resolved": "https://registry.npmjs.org/redis/-/redis-4.6.12.tgz", - "integrity": "sha512-41Xuuko6P4uH4VPe5nE3BqXHB7a9lkFL0J29AlxKaIfD6eWO8VO/5PDF9ad2oS+mswMsfFxaM5DlE3tnXT+P8Q==", - "dependencies": { - "@redis/bloom": "1.2.0", - "@redis/client": "1.5.13", - "@redis/graph": "1.1.1", - "@redis/json": "1.0.6", - "@redis/search": "1.1.6", - "@redis/time-series": "1.0.5" - } - }, "node_modules/reflect.getprototypeof": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.4.tgz", @@ -24006,17 +23918,6 @@ "node": ">=0.8.0" } }, - "node_modules/uid-safe": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", - "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==", - "dependencies": { - "random-bytes": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/unbox-primitive": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", @@ -24934,19 +24835,16 @@ "version": "1.0.0", "license": "MIT", "dependencies": { + "@navikt/oasis": "^3.3.0", "babel-polyfill": "^6.26.0", "compression": "^1.7.4", - "connect-redis": "^7.1.0", "cookie-parser": "^1.4.6", "cross-env": "^7.0.3", "dotenv": "^16.3.1", "express": "^4.18.2", - "express-session": "^1.17.3", "http-proxy": "^1.18.1", "http-proxy-middleware": "^3.0.0", - "openid-client": "^5.6.1", "prom-client": "^15.1.0", - "redis": "^4.6.12", "uuid": "^9.0.1", "winston": "^3.11.0" }, @@ -25053,8 +24951,8 @@ "@apollo/client": "^3.8.8", "@grafana/faro-web-sdk": "^1.3.5", "@navikt/ds-css": "^6.8.0", - "@navikt/ds-css-internal": "^2.9.3", - "@navikt/ds-icons": "^2.9.3", + "@navikt/ds-css-internal": "^2.9.8", + "@navikt/ds-icons": "^2.9.8", "@navikt/ds-react": "^6.8.0", "@navikt/ds-tokens": "^6.8.0", "@tanstack/react-query": "^5.25.0", @@ -25120,60 +25018,6 @@ "npm": ">=6.14.0" } }, - "packages/frontend/node_modules/@floating-ui/react": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.25.4.tgz", - "integrity": "sha512-lWRQ/UiTvSIBxohn0/2HFHEmnmOVRjl7j6XcRJuLH0ls6f/9AyHMWVzkAJFuwx0n9gaEeCmg9VccCSCJzbEJig==", - "dependencies": { - "@floating-ui/react-dom": "^2.0.2", - "@floating-ui/utils": "^0.1.1", - "tabbable": "^6.0.1" - }, - "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" - } - }, - "packages/frontend/node_modules/@floating-ui/react-dom": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.0.tgz", - "integrity": "sha512-lNzj5EQmEKn5FFKc04+zasr09h/uX8RtJRNj5gUXsSQIXHVWTVh+hVAg1vOMCexkX8EgvemMvIFpQfkosnVNyA==", - "dependencies": { - "@floating-ui/dom": "^1.0.0" - }, - "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" - } - }, - "packages/frontend/node_modules/@navikt/aksel-icons": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/@navikt/aksel-icons/-/aksel-icons-6.8.0.tgz", - "integrity": "sha512-XiEr0Xb0BDaStrpGCuEPvNgvHalbL4dPh6HAA7jGV7cHnW6Zsb54Hsaq6dLMXIDYEpPQv2T27j25UvoRxVuk8g==" - }, - "packages/frontend/node_modules/@navikt/ds-react": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/@navikt/ds-react/-/ds-react-6.8.0.tgz", - "integrity": "sha512-FW2NndVzdVUTBselUzRa1vrkqpJDmHF6cG5A9bg5Y3Y4Aq2uQ07KvDUBzLP+rZz0i4bJ/gkrtoFF74nQRtmKkg==", - "dependencies": { - "@floating-ui/react": "0.25.4", - "@floating-ui/react-dom": "^2.0.9", - "@navikt/aksel-icons": "^6.8.0", - "@navikt/ds-tokens": "^6.8.0", - "clsx": "^2.1.0", - "date-fns": "^3.0.0", - "react-day-picker": "8.10.0" - }, - "peerDependencies": { - "@types/react": "^17.0.30 || ^18.0.0", - "react": "^17.0.0 || ^18.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, "packages/frontend/node_modules/brace-expansion": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", @@ -25183,23 +25027,6 @@ "balanced-match": "^1.0.0" } }, - "packages/frontend/node_modules/clsx": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", - "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", - "engines": { - "node": ">=6" - } - }, - "packages/frontend/node_modules/date-fns": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz", - "integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/kossnocorp" - } - }, "packages/frontend/node_modules/glob": { "version": "10.3.10", "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", @@ -25237,19 +25064,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "packages/frontend/node_modules/react-day-picker": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/react-day-picker/-/react-day-picker-8.10.0.tgz", - "integrity": "sha512-mz+qeyrOM7++1NCb1ARXmkjMkzWVh2GL9YiPbRjKe0zHccvekk4HE+0MPOZOrosn8r8zTHIIeOUXTmXRqmkRmg==", - "funding": { - "type": "individual", - "url": "https://github.com/sponsors/gpbl" - }, - "peerDependencies": { - "date-fns": "^2.28.0 || ^3.0.0", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - } - }, "packages/frontend/node_modules/rimraf": { "version": "5.0.5", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.5.tgz", diff --git a/packages/backend/auth/authSupport.test.ts b/packages/backend/auth/authSupport.test.ts deleted file mode 100644 index e5df07c82..000000000 --- a/packages/backend/auth/authSupport.test.ts +++ /dev/null @@ -1,58 +0,0 @@ -import auth from './authSupport'; - -type Claim = { [key: string]: string | string[] }; - -describe('isValidIn', () => { - const nowInSeconds = Math.floor(Date.now() / 1000); - const tokenThatExpiresIn = (seconds: number) => createToken({ exp: `${nowInSeconds + seconds}` }); - - test('time to check is before exp', () => { - expect(auth.isValidIn({ seconds: 28, token: tokenThatExpiresIn(30) })).toEqual(true); - }); - - test('time to check is at exp', () => { - expect(auth.isValidIn({ seconds: 30, token: tokenThatExpiresIn(30) })).toEqual(false); - }); - - test('time to check is after exp', () => { - expect(auth.isValidIn({ seconds: 31, token: tokenThatExpiresIn(30) })).toEqual(false); - }); - - test('the exp has already passed', () => { - expect(auth.isValidIn({ seconds: 1, token: tokenThatExpiresIn(-30) })).toEqual(false); - }); - - test('there is no token', () => { - expect(auth.isValidIn({ seconds: 1, token: undefined })).toEqual(false); - }); -}); - -test('user is member of required group', () => { - const token = createToken({ groups: ['group1', 'group2', 'group3'] }); - expect(auth.isMemberOf(token, 'group3')).toEqual(true); -}); - -test('user is not member of required group', () => { - const token = createToken({ groups: ['group1', 'group2', 'group3'] }); - expect(auth.isMemberOf(token, 'group4')).toEqual(false); -}); - -test('extraction from named jwt claim', () => { - const token = createToken({ name: 'John Doe' }); - expect(auth.valueFromClaim('name', token)).toEqual('John Doe'); -}); - -test('extraction from jwt claim, property missing', () => { - const token = createToken({}); - expect(auth.valueFromClaim('name', token)).toEqual('unknown value'); -}); - -test('extraction from jwt claim, malformed token', () => { - const token = 'invalid bogus'; - expect(auth.valueFromClaim('name', token)).toEqual('unknown value'); -}); - -const createToken = (claims: Claim) => { - const header = { alg: 'HS256', typ: 'JWT' }; - return `${btoa(JSON.stringify(header))}.${btoa(JSON.stringify(claims))}.bogussignature`; -}; diff --git a/packages/backend/auth/authSupport.ts b/packages/backend/auth/authSupport.ts deleted file mode 100644 index b48ddcd3d..000000000 --- a/packages/backend/auth/authSupport.ts +++ /dev/null @@ -1,129 +0,0 @@ -import { Request } from 'express'; -import { Client, TokenSet } from 'openid-client'; -import util from 'util'; - -import config from '../config'; -import logger from '../logging'; -import { AuthError, SpeilRequest, SpeilSession } from '../types'; - -interface IsValidInProps { - seconds: number; - token?: string; -} - -type ExpectedClaims = { - [key: string]: string | string[]; - exp: string; - groups: string[]; -}; -const isValidIn = ({ seconds, token }: IsValidInProps) => { - if (!token) return false; - const timeToCheck = Math.floor(Date.now() / 1000) + seconds; - const expirationTime = parseInt(claimsFrom(token).exp); - return timeToCheck < expirationTime; -}; - -const redirectUrl = (req: Request) => { - if (config.development) return 'http://localhost:3000/oauth2/callback'; - return 'https://' + req.get('Host') + '/oauth2/callback'; -}; - -const authError = (statusCode: number, reason: string, cause?: unknown): AuthError => { - return { - name: 'auth_error', - message: reason, - statusCode: statusCode, - cause: cause, - }; -}; - -const validateOidcCallback = (req: SpeilRequest, azureClient: Client) => { - if (req.body.code === undefined) { - return Promise.reject(authError(400, 'missing data in POST after login')); - } - const params = azureClient.callbackParams(req); - const nonce = req.session!.nonce; - const state = req.session!.state; - if (state == null) { - logger.sikker.error( - `'state' skulle ikke ha vært null.\nreq: ${util.inspect(req)}\nreq.session: ${util.inspect(req.session)}`, - ); - } - - return azureClient - .callback(redirectUrl(req), params, { nonce, state }) - .catch((err) => Promise.reject(authError(500, `Azure error: ${err.error_description}`, err))) - .then((tokenSet: TokenSet) => retrieveTokens(tokenSet, 'access_token', 'id_token', 'refresh_token')) - .then(([accessToken, idToken, refreshToken]) => { - return [accessToken, idToken, refreshToken]; - }); -}; - -const retrieveTokens = (tokenSet: TokenSet, ...tokenKeys: string[]): Promise => { - const tokens = tokenKeys.map((key) => tokenSet[key]); - for (const key of tokenKeys) { - if (tokenSet[key] === undefined) { - return Promise.reject(authError(500, `Missing ${key} in response from Azure AD.`)); - } - } - return Promise.resolve(tokens as string[]); -}; - -const isMemberOf = (token: string, group?: string) => { - const claims = claimsFrom(token); - const groups = claims.groups; - return groups.filter((element: string) => element === group).length === 1; -}; - -const valueFromClaim = (claim: string, token?: string): T => { - if (token === undefined) { - logger.info(`No token, cannot extract claim value '${claim}'`); - return 'unknown value' as T; - } - try { - return (claimsFrom(token)[claim] || 'unknown value') as T; - } catch (err) { - logger.error(`error while extracting value from claim '${claim}': ${err}`); - return 'unknown value' as T; - } -}; -const claimsFrom = (token: string): ExpectedClaims => { - return JSON.parse(Buffer.from(token.split('.')[1], 'base64').toString()); -}; - -const createTokenForTest = () => - `${Buffer.from(JSON.stringify({ alg: 'HS256', typ: 'JWT' })).toString('base64')}.${Buffer.from( - JSON.stringify({ - name: 'S. A. Ksbehandler', - email: 'dev@nav.no', - NAVident: 'dev-ident', - oid: '4577332e-801a-4c13-8a71-39f12b8abfa3', - }), - ).toString('base64')}.bogussignature`; - -const refreshAccessToken = async (azureClient: Client, session: SpeilSession): Promise => { - if (!session.refreshToken) return false; - return await azureClient - .refresh(session.refreshToken) - .then((tokenSet: TokenSet) => retrieveTokens(tokenSet, 'access_token', 'refresh_token')) - .then(([accessToken, refreshToken]) => { - logger.sikker.info(`Refresher access token for ${session.user}`); - session.speilToken = accessToken; - session.refreshToken = refreshToken; - return true; - }) - .catch((errorMessage) => { - logger.sikker.error(`Feilet refresh av access token for ${session.user}: ${errorMessage}`); - return false; - }); -}; - -export default { - isValidIn, - redirectUrl, - validateOidcCallback, - isMemberOf, - valueFromClaim, - createTokenForTest, - refreshAccessToken, -}; diff --git a/packages/backend/auth/azure.ts b/packages/backend/auth/azure.ts deleted file mode 100644 index c61ca5c71..000000000 --- a/packages/backend/auth/azure.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { Client, Issuer } from 'openid-client'; - -import config from '../config'; -import logger from '../logging'; -import { OidcConfig } from '../types'; - -('use strict'); - -let azureClient; - -const setup = (oidcConfig: OidcConfig) => { - return new Promise((resolve, reject) => { - if (config.development) { - resolve(); - } - - Issuer.discover(oidcConfig.wellKnownEndpoint) - .then((azure) => { - logger.info(`Discovered issuer ${azure.issuer}`); - azureClient = new azure.Client({ - client_id: oidcConfig.clientID, - client_secret: oidcConfig.clientSecret, - redirect_uris: [], - response_types: ['code'], - end_session_endpoint: azure.metadata.end_session_endpoint, - }); - - resolve(azureClient); - }) - .catch((err) => { - reject(err); - }); - }); -}; - -export default { setup }; diff --git a/packages/backend/auth/devOnBehalfOf.ts b/packages/backend/auth/devOnBehalfOf.ts deleted file mode 100644 index 1acb0dda9..000000000 --- a/packages/backend/auth/devOnBehalfOf.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { OnBehalfOf } from '../types'; - -const devOnBehalfOf: OnBehalfOf = { - hentFor: async () => 'en slags token-string', -}; - -export default devOnBehalfOf; diff --git a/packages/backend/auth/onBehalfOf.ts b/packages/backend/auth/onBehalfOf.ts deleted file mode 100644 index ff0fae0c1..000000000 --- a/packages/backend/auth/onBehalfOf.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { TokenSet } from 'openid-client'; - -import { Instrumentation } from '../instrumentation'; -import logger from '../logging'; -import { OidcConfig, OnBehalfOf, SpeilSession } from '../types'; -import { sleep } from '../utils'; -import authSupport from './authSupport'; - -export default (config: OidcConfig, instrumentation: Instrumentation): OnBehalfOf => { - const counter = instrumentation.onBehalfOfCounter(); - - const hentToken = async (init: RequestInit): Promise => { - const response = await fetch(config.tokenEndpoint, init); - const data = await response.json(); - if (!data || data.error) throw new Error(data.error); - return data; - }; - - return { - hentFor: async (targetClientId: string, session: SpeilSession, accessToken: string) => { - const oboToken = session.oboTokens?.[targetClientId]; - if (oboToken && authSupport.isValidIn({ seconds: 5, token: oboToken })) { - logger.info('Bruker cachet obo token i stedet for å hente nytt'); - return oboToken; - } - - logger.info(`Forsøker å hente nytt obo token for ${targetClientId}`); - - counter.inc(targetClientId); - - const options = { - method: 'post', - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - }, - body: new URLSearchParams({ - grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer', - client_id: config.clientID, // our own - client_secret: config.clientSecret, - assertion: accessToken, - scope: targetClientId, // the app we're reaching out to - requested_token_use: 'on_behalf_of', - }), - }; - let forsøk = 1; - let tokenSet: TokenSet | undefined; - while (!tokenSet) { - try { - tokenSet = await hentToken(options); - } catch (error) { - if (forsøk < 3) { - logger.info(`Prøver å hente token på nytt for ${targetClientId}, feil: ${error}`); - forsøk++; - await sleep(500 * forsøk); - } else { - logger.error( - `Feil etter ${forsøk} forsøk ved henting av token for ${targetClientId}: ${error}, gir opp.`, - ); - throw error; - } - } - } - - if (forsøk > 1) { - logger.info(`Brukte ${forsøk} forsøk på å hente token for ${targetClientId}`); - } - - session.oboTokens[targetClientId] = tokenSet.access_token!; - - return tokenSet.access_token!; - }, - }; -}; diff --git a/packages/backend/auth/testToken.ts b/packages/backend/auth/testToken.ts new file mode 100644 index 000000000..b3cd8e845 --- /dev/null +++ b/packages/backend/auth/testToken.ts @@ -0,0 +1,9 @@ +export const createTokenForTest = () => + `${Buffer.from(JSON.stringify({ alg: 'HS256', typ: 'JWT' })).toString('base64')}.${Buffer.from( + JSON.stringify({ + name: 'S. A. Ksbehandler', + email: 'dev@nav.no', + NAVident: 'dev-ident', + oid: '4577332e-801a-4c13-8a71-39f12b8abfa3', + }), + ).toString('base64')}.bogussignature`; diff --git a/packages/backend/auth/token.ts b/packages/backend/auth/token.ts new file mode 100644 index 000000000..002e0f2c2 --- /dev/null +++ b/packages/backend/auth/token.ts @@ -0,0 +1,27 @@ +import { Request } from 'express'; + +import { getToken, requestOboToken } from '@navikt/oasis'; + +import config from '../config'; + +export const requestAzureOboToken = async ( + token: string, + scope: string, +): Promise> => { + if (config.development) { + return { + ok: true, + token: 'et slags obo token', + }; + } + + return await requestOboToken(token, scope); +}; + +export const getAuthToken = (req: Request): string | null => { + if (config.development) { + return 'et slags token'; + } + + return getToken(req); +}; diff --git a/packages/backend/config.ts b/packages/backend/config.ts index 5907d53df..17422cdcb 100644 --- a/packages/backend/config.ts +++ b/packages/backend/config.ts @@ -1,16 +1,13 @@ +'use strict'; + import env from 'dotenv'; import * as process from 'process'; -import { OidcConfig, RedisConfig, ServerConfig } from './types'; - -('use strict'); +import { OidcConfig, ServerConfig } from './types'; env.config(); const oidc: OidcConfig = { - wellKnownEndpoint: process.env.AZURE_APP_WELL_KNOWN_URL || 'unknown', - tokenEndpoint: process.env.AZURE_OPENID_CONFIG_TOKEN_ENDPOINT || 'unknown', - clientID: process.env.AZURE_APP_CLIENT_ID || 'unknown', clientIDSpesialist: process.env.CLIENT_ID_SPESIALIST || 'unknown', clientIDFlexjar: process.env.CLIENT_ID_FLEXJAR || 'unknown', modiaApiScope: process.env.MODIA_API_SCOPE || 'unknown', @@ -29,17 +26,10 @@ const server: ServerConfig = { modiaBaseUrl: process.env.MODIA_BASE_URL || 'http://localhost', }; -const redis: RedisConfig = { - url: process.env.REDIS_URI_SESSIONS!, - username: process.env.REDIS_USERNAME_SESSIONS!, - password: process.env.REDIS_PASSWORD_SESSIONS!, -}; - const development = process.env.NODE_ENV === 'development'; export default { oidc, - redis, server, development, }; diff --git a/packages/backend/flexjar/flexjarClient.ts b/packages/backend/flexjar/flexjarClient.ts index 0e0e8df7b..e8e1f6152 100644 --- a/packages/backend/flexjar/flexjarClient.ts +++ b/packages/backend/flexjar/flexjarClient.ts @@ -1,35 +1,31 @@ import { v4 as uuidv4 } from 'uuid'; +import { requestAzureOboToken } from '../auth/token'; import config from '../config'; import logger from '../logging'; -import { OidcConfig, OnBehalfOf, SpeilSession } from '../types'; const baseUrl = config.server.flexjarBaseUrl; export interface FlexjarClient { - postFlexjarQuery: ( - speilToken: string, - session: SpeilSession, - data: string, - method?: string, - urlId?: string, - ) => Promise; + postFlexjarQuery: (wonderwallToken: string, data: string, method?: string, urlId?: string) => Promise; } -export default (oidcConfig: OidcConfig, onBehalfOf: OnBehalfOf): FlexjarClient => ({ +export default (): FlexjarClient => ({ postFlexjarQuery: async ( - speilToken: string, - session: SpeilSession, + wonderwallToken: string, data: string, method: string = 'POST', urlId: string = '', ): Promise => { const callId = uuidv4(); - const onBehalfOfToken = await onBehalfOf.hentFor(oidcConfig.clientIDFlexjar, session, speilToken); + const oboResult = await requestAzureOboToken(wonderwallToken, config.oidc.clientIDFlexjar); + if (!oboResult.ok) { + throw new Error(`Feil ved henting av OBO-token: ${oboResult.error.message}`); + } const options = { method, headers: { - Authorization: `Bearer ${onBehalfOfToken}`, + Authorization: `Bearer ${oboResult.token}`, 'X-Request-Id': callId, 'Content-Type': 'application/json', }, @@ -37,7 +33,7 @@ export default (oidcConfig: OidcConfig, onBehalfOf: OnBehalfOf): FlexjarClient = }; const erMethodPost = method === 'POST'; - const maskertToken = onBehalfOfToken.substring(0, 6); + const maskertToken = oboResult.token.substring(0, 6); logger.debug(`Kaller ${baseUrl} med X-Request-Id: ${callId} og token: ${maskertToken}...`); const start = Date.now(); const path = erMethodPost ? 'api/azure/v2/feedback' : `api/azure/v2/feedback/${urlId}`; diff --git a/packages/backend/flexjar/flexjarRoutes.ts b/packages/backend/flexjar/flexjarRoutes.ts index b3e09e25a..abd5a8f8d 100644 --- a/packages/backend/flexjar/flexjarRoutes.ts +++ b/packages/backend/flexjar/flexjarRoutes.ts @@ -1,7 +1,8 @@ -import { NextFunction, Response, Router } from 'express'; +import { NextFunction, Request, Response, Router } from 'express'; + +import { getToken } from '@navikt/oasis'; import logger from '../logging'; -import { SpeilRequest } from '../types'; import { FlexjarClient } from './flexjarClient'; interface SetupOptions { @@ -11,19 +12,25 @@ interface SetupOptions { export default ({ flexjarClient }: SetupOptions) => { const router = Router(); - router.post('/', (req: SpeilRequest, res: Response, next: NextFunction) => { + router.post('/', (req: Request, res: Response, next: NextFunction) => { postOpprett(flexjarClient, req, res).catch(next); }); - router.post(`/oppdater/:id`, (req: SpeilRequest, res: Response, next: NextFunction) => { + router.post(`/oppdater/:id`, (req: Request, res: Response, next: NextFunction) => { postOppdater(flexjarClient, req.params.id, req, res).catch(next); }); return router; }; -const postOpprett = async (flexjarClient: FlexjarClient, req: SpeilRequest, res: Response) => { +const postOpprett = async (flexjarClient: FlexjarClient, req: Request, res: Response) => { + const token = getToken(req); + if (!token) { + res.sendStatus(401); + return; + } + const response = await flexjarClient - .postFlexjarQuery(req.session!.speilToken, req.session, JSON.stringify(req.body)) + .postFlexjarQuery(token, JSON.stringify(req.body)) .then((response) => JSON.stringify(response)) .catch((error) => logger.info(`Sending av feedback til flexjar feilet: ${error}`)); logger.info(`Sending av feedback til flexjar, respons: ${JSON.stringify(response)}`); @@ -32,12 +39,16 @@ const postOpprett = async (flexjarClient: FlexjarClient, req: SpeilRequest, res: else res.sendStatus(500); }; -const postOppdater = async (flexjarClient: FlexjarClient, id: string, req: SpeilRequest, res: Response) => { - const response = await flexjarClient - .postFlexjarQuery(req.session!.speilToken, req.session, JSON.stringify(req.body), 'PUT', id) - .catch((error) => { - logger.info(`Oppdatering av feedback til flexjar feilet: ${error}`); - }); +const postOppdater = async (flexjarClient: FlexjarClient, id: string, req: Request, res: Response) => { + const token = getToken(req); + if (!token) { + res.sendStatus(401); + return; + } + + const response = await flexjarClient.postFlexjarQuery(token, JSON.stringify(req.body), 'PUT', id).catch((error) => { + logger.info(`Oppdatering av feedback til flexjar feilet: ${error}`); + }); if (response) res.status(204).send(JSON.stringify({})); else res.sendStatus(500); }; diff --git a/packages/backend/graphql/graphQLClient.ts b/packages/backend/graphql/graphQLClient.ts index 22a2f5785..13fb67ac1 100644 --- a/packages/backend/graphql/graphQLClient.ts +++ b/packages/backend/graphql/graphQLClient.ts @@ -1,23 +1,27 @@ import { v4 as uuidv4 } from 'uuid'; +import { requestAzureOboToken } from '../auth/token'; import config from '../config'; import logger from '../logging'; -import { OidcConfig, OnBehalfOf, SpeilSession } from '../types'; const baseUrl = config.server.spesialistBaseUrl; export interface GraphQLClient { - postGraphQLQuery: (speilToken: string, session: SpeilSession, data: string) => Promise; + postGraphQLQuery: (wonderwallToken: string, data: string) => Promise; } -export default (oidcConfig: OidcConfig, onBehalfOf: OnBehalfOf): GraphQLClient => ({ - postGraphQLQuery: async (speilToken: string, session: SpeilSession, data: string): Promise => { +export default (): GraphQLClient => ({ + postGraphQLQuery: async (wonderwallToken: string, data: string): Promise => { const callId = uuidv4(); - const onBehalfOfToken = await onBehalfOf.hentFor(oidcConfig.clientIDSpesialist, session, speilToken); + const oboResult = await requestAzureOboToken(wonderwallToken, config.oidc.clientIDSpesialist); + if (!oboResult.ok) { + throw new Error(`Feil ved henting av OBO-token: ${oboResult.error.message}`); + } + const options = { method: 'post', headers: { - Authorization: `Bearer ${onBehalfOfToken}`, + Authorization: `Bearer ${oboResult.token}`, 'X-Request-Id': callId, 'Content-Type': 'application/json', }, @@ -25,7 +29,7 @@ export default (oidcConfig: OidcConfig, onBehalfOf: OnBehalfOf): GraphQLClient = }; const operationName = JSON.parse(data)['operationName']; - const maskertToken = onBehalfOfToken.substring(0, 6); + const maskertToken = oboResult.token.substring(0, 6); logger.debug( `Kaller ${baseUrl} med X-Request-Id: ${callId}, operationName: ${operationName} og token: ${maskertToken}...`, ); diff --git a/packages/backend/graphql/graphQLRoutes.ts b/packages/backend/graphql/graphQLRoutes.ts index 1c422d116..8e6092baf 100644 --- a/packages/backend/graphql/graphQLRoutes.ts +++ b/packages/backend/graphql/graphQLRoutes.ts @@ -1,7 +1,7 @@ -import { NextFunction, Response, Router } from 'express'; +import { NextFunction, Request, Response, Router } from 'express'; +import { getAuthToken } from '../auth/token'; import logger from '../logging'; -import { SpeilRequest } from '../types'; import { sleep } from '../utils'; import { GraphQLClient } from './graphQLClient'; @@ -12,14 +12,14 @@ interface SetupOptions { export default ({ graphQLClient }: SetupOptions) => { const router = Router(); - router.post('/', (req: SpeilRequest, res: Response, next: NextFunction) => { + router.post('/', (req: Request, res: Response, next: NextFunction) => { retrySpørring(graphQLClient, req, res).catch(next); }); return router; }; -const retrySpørring = async (graphQLClient: GraphQLClient, req: SpeilRequest, res: Response) => { +const retrySpørring = async (graphQLClient: GraphQLClient, req: Request, res: Response) => { let forsøk = 0; let response: Response | undefined; let giOpp; @@ -42,9 +42,11 @@ const retrySpørring = async (graphQLClient: GraphQLClient, req: SpeilRequest, r else res.sendStatus(500); }; -const postSpørring = async (graphQLClient: GraphQLClient, req: SpeilRequest) => { +const postSpørring = async (graphQLClient: GraphQLClient, req: Request) => { const data = JSON.stringify(req.body); - const response = await graphQLClient.postGraphQLQuery(req.session!.speilToken, req.session, data); + const token = getAuthToken(req); + if (!token) throw new Error('Mangler token'); + const response = await graphQLClient.postGraphQLQuery(token, data); if (!response.ok) throw new Error(`Feil ved kall til spesialist, status: ${response.status}`); return await response.json(); }; diff --git a/packages/backend/logging.ts b/packages/backend/logging.ts index 6ad5e21da..717f0f6eb 100644 --- a/packages/backend/logging.ts +++ b/packages/backend/logging.ts @@ -1,11 +1,12 @@ +'use strict'; + +import { Request } from 'express'; import fs from 'fs'; import winston from 'winston'; -import authSupport from './auth/authSupport'; -import config from './config'; -import { SpeilRequest } from './types'; +import { getToken, parseAzureUserToken } from '@navikt/oasis'; -('use strict'); +import config from './config'; const sikkerLogPath = () => (fs.existsSync('/secure-logs/') ? '/secure-logs/secure.log' : './secure.log'); @@ -48,10 +49,11 @@ const sikkerError = (message: string, ...meta: unknown[]) => { sikkerLogger.error(message, ...meta); }; -const requestMeta = (req: SpeilRequest) => { +const requestMeta = (req: Request) => { + const user = userMeta(req); return { - speilUser: authSupport.valueFromClaim('name', req.session.speilToken), - navIdent: authSupport.valueFromClaim('NAVident', req.session.speilToken), + speilUser: user?.name ?? 'ukjent', + navIdent: user?.navIdent ?? 'ukjent', headers: req.headers, method: req.method, url: req.url, @@ -66,6 +68,16 @@ const requestMeta = (req: SpeilRequest) => { }; }; +const userMeta = (req: Request): { name: string; navIdent: string } | null => { + const token = getToken(req); + if (!token) return null; + + const parse = parseAzureUserToken(token); + if (!parse.ok) return null; + + return { name: parse.name, navIdent: parse.NAVident }; +}; + export default { debug, info, diff --git a/packages/backend/modia/modiaClient.ts b/packages/backend/modia/modiaClient.ts index 8aebba582..fb6eeb2c0 100644 --- a/packages/backend/modia/modiaClient.ts +++ b/packages/backend/modia/modiaClient.ts @@ -1,13 +1,13 @@ import { v4 as uuidv4 } from 'uuid'; +import { requestAzureOboToken } from '../auth/token'; import config from '../config'; import logger from '../logging'; -import { OidcConfig, OnBehalfOf, SpeilSession } from '../types'; const modiaBaseUrl = config.server.modiaBaseUrl; export interface ModiaClient { - kallModia: (handling: Handling, speilToken: string, session: SpeilSession, data?: string) => Promise; + kallModia: (handling: Handling, wonderwallToken: string, data?: string) => Promise; } export enum Handling { @@ -22,20 +22,18 @@ const handlinger: { [key in Handling]: Handlingdata } = { [Handling.nullstillBruker]: { path: '/api/context/aktivbruker', method: 'delete' }, }; -export default (oidcConfig: OidcConfig, onBehalfOf: OnBehalfOf): ModiaClient => ({ - kallModia: async ( - handling: Handling, - speilToken: string, - session: SpeilSession, - data: string, - ): Promise => { +export default (): ModiaClient => ({ + kallModia: async (handling: Handling, wonderwallToken: string, data: string): Promise => { const { method, path } = handlinger[handling]; const callId = uuidv4(); - const onBehalfOfToken = await onBehalfOf.hentFor(oidcConfig.modiaApiScope, session, speilToken); + const oboResult = await requestAzureOboToken(wonderwallToken, config.oidc.modiaApiScope); + if (!oboResult.ok) { + throw new Error(`Feil ved henting av OBO-token: ${oboResult.error.message}`); + } const options = { method: method, headers: { - Authorization: `Bearer ${onBehalfOfToken}`, + Authorization: `Bearer ${oboResult.token}`, 'X-Request-Id': callId, 'Content-Type': 'application/json', 'Nav-Consumer-Id': 'speil', @@ -43,7 +41,7 @@ export default (oidcConfig: OidcConfig, onBehalfOf: OnBehalfOf): ModiaClient => body: JSON.stringify(data), }; - const maskertToken = onBehalfOfToken.substring(0, 6); + const maskertToken = oboResult.token.substring(0, 6); const url = `${modiaBaseUrl}${path}`; logger.debug(`Kaller ${url} med X-Request-Id: ${callId} og token: ${maskertToken}...`); diff --git a/packages/backend/modia/modiaRoutes.ts b/packages/backend/modia/modiaRoutes.ts index bce0b5f21..ba42fd480 100644 --- a/packages/backend/modia/modiaRoutes.ts +++ b/packages/backend/modia/modiaRoutes.ts @@ -1,7 +1,8 @@ -import { Response, Router } from 'express'; +import { Request, Response, Router } from 'express'; + +import { getToken } from '@navikt/oasis'; import logger from '../logging'; -import { SpeilRequest } from '../types'; import { Handling, ModiaClient } from './modiaClient'; interface SetupOptions { @@ -10,9 +11,14 @@ interface SetupOptions { export default ({ modiaClient }: SetupOptions) => { const router = Router(); - router.post('/', async (req: SpeilRequest, res: Response) => { + router.post('/', async (req: Request, res: Response) => { + const token = getToken(req); + if (!token) { + res.sendStatus(401); + return; + } try { - await modiaClient.kallModia(Handling.velgBrukerIModia, req.session!.speilToken, req.session, req.body); + await modiaClient.kallModia(Handling.velgBrukerIModia, token, req.body); res.sendStatus(200); } catch (error) { logger.warn(`Setting av person i modiacontext feilet: ${error}`); @@ -20,9 +26,14 @@ export default ({ modiaClient }: SetupOptions) => { } }); - router.delete('/aktivbruker', async (req: SpeilRequest, res: Response) => { + router.delete('/aktivbruker', async (req: Request, res: Response) => { + const token = getToken(req); + if (!token) { + res.sendStatus(401); + return; + } try { - await modiaClient.kallModia(Handling.nullstillBruker, req.session!.speilToken, req.session); + await modiaClient.kallModia(Handling.nullstillBruker, token); res.sendStatus(200); } catch (error) { logger.warn(`Nullstilling av person i modiacontext feilet: ${error}`); diff --git a/packages/backend/package.json b/packages/backend/package.json index f6746b663..be1b7aced 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -25,21 +25,18 @@ "prettier": "prettier --write \"**/*.{js,ts}\"" }, "dependencies": { + "@navikt/oasis": "^3.3.0", "babel-polyfill": "^6.26.0", "compression": "^1.7.4", - "connect-redis": "^7.1.0", "cookie-parser": "^1.4.6", "cross-env": "^7.0.3", "dotenv": "^16.3.1", "express": "^4.18.2", - "express-session": "^1.17.3", "http-proxy": "^1.18.1", - "openid-client": "^5.6.1", + "http-proxy-middleware": "^3.0.0", "prom-client": "^15.1.0", - "redis": "^4.6.12", "uuid": "^9.0.1", - "winston": "^3.11.0", - "http-proxy-middleware": "^3.0.0" + "winston": "^3.11.0" }, "devDependencies": { "@babel/cli": "^7.23.4", diff --git a/packages/backend/redisClient.ts b/packages/backend/redisClient.ts deleted file mode 100644 index ee48611ec..000000000 --- a/packages/backend/redisClient.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { RedisClientType, createClient } from 'redis'; - -import logger from './logging'; -import { Helsesjekk, RedisConfig } from './types'; - -// Aiven Redis timer ut idle connections etter fem minutter, det gidder vi vel ikke. -const pingInterval = 1000 * 60 * 4; - -const init = (config: RedisConfig, helsesjekk: Helsesjekk) => { - const redisClient: RedisClientType = createClient({ - url: config.url, - username: config.username, - password: config.password, - pingInterval, - }); - redisClient.on('connect', () => { - logger.info('Redis client connected'); - }); - - redisClient.on('ready', () => { - helsesjekk.redis = true; - logger.info('Redis client ready'); - }); - - redisClient.on('error', (err) => { - helsesjekk.redis = false; - logger.error('Redis error: ', err); - }); - - redisClient.connect().catch((err) => logger.error(err)); - - return redisClient; -}; - -export default { init }; diff --git a/packages/backend/server.ts b/packages/backend/server.ts index 870ece68a..b26addcdf 100644 --- a/packages/backend/server.ts +++ b/packages/backend/server.ts @@ -4,11 +4,10 @@ import cookieParser from 'cookie-parser'; import express, { NextFunction, Request, Response } from 'express'; import { createProxyMiddleware } from 'http-proxy-middleware'; import * as http from 'node:http'; -import { Client, generators } from 'openid-client'; -import util from 'util'; -import auth from './auth/authSupport'; -import azure from './auth/azure'; +import { getToken, validateToken } from '@navikt/oasis'; + +import { createTokenForTest } from './auth/testToken'; import config from './config'; import flexjarRoutes from './flexjar/flexjarRoutes'; import graphQLRoutes from './graphql/graphQLRoutes'; @@ -16,154 +15,63 @@ import headers from './headers'; import logger from './logging'; import modiaRoutes from './modia/modiaRoutes'; import { ipAddressFromRequest } from './requestData'; -import { AuthError, SpeilRequest } from './types'; import wiring from './wiring'; const app = express(); const port = config.server.port; -const helsesjekk = { redis: false }; -const dependencies = wiring.getDependencies(app, helsesjekk); +const dependencies = wiring.getDependencies(app); app.use(bodyParser.json()); app.use(cookieParser()); -app.use(dependencies.sessionStore); app.use(compression()); headers.setup(app); -let azureClient: Client | null = null; -azure - .setup(config.oidc) - .then((client: Client) => { - azureClient = client; - }) - .catch((err) => { - logger.error(`Failed to discover OIDC provider properties: ${err}`); - process.exit(1); - }); - // Unprotected routes app.get('/isAlive', (_, res) => res.send('alive')); -app.get('/isReady', (_, res) => { - if (helsesjekk.redis) { - return res.send('ready'); - } else { - logger.warn('Svarer not ready på isReady'); - res.statusCode = 503; - return res.send('NOT READY'); - } -}); - -const setUpAuthentication = () => { - const authErrorCounter = dependencies.instrumentation.authError(); - app.get('/login', (req: SpeilRequest, res: Response) => { - const session = req.session; - session.nonce = generators.nonce(); - session.state = generators.state(); - const url = azureClient!.authorizationUrl({ - scope: config.oidc.scope, - redirect_uri: auth.redirectUrl(req), - response_type: config.oidc.responseType[0], - prompt: 'select_account', - response_mode: 'form_post', - nonce: session.nonce, - state: session.state, - }); - res.redirect(url); - }); - app.get('/logout', (req: SpeilRequest, res: Response) => { - azureClient! - .revoke(req.session.speilToken) - .catch(() => logger.warn('Kunne ikke invalidere token mot Azure AD')) - .finally(() => { - req.session.destroy(() => {}); - res.clearCookie('speil'); - res.redirect(302, config.oidc.logoutUrl); - }); - }); - - app.use(bodyParser.urlencoded({ extended: false })); - - app.post('/oauth2/callback', (req: SpeilRequest, res: Response) => { - const session = req.session; - auth.validateOidcCallback(req, azureClient!) - .then((tokens: string[]) => { - const [accessToken, idToken, refreshToken] = tokens; - res.cookie('speil', `${idToken}`, { - secure: true, - sameSite: true, - }); - session.speilToken = accessToken; - session.refreshToken = refreshToken; - session.oboTokens = {}; - session.user = auth.valueFromClaim('NAVident', idToken); - const tilbakeTilUrl = req.session.wantedPathBeforeAuth; - req.session.wantedPathBeforeAuth = undefined; - if (tilbakeTilUrl) logger.sikker.info(`sender bruker tilbake til ${tilbakeTilUrl}`); - res.redirect(303, tilbakeTilUrl ?? '/'); - }) - .catch((err: AuthError) => { - logger.warn(`Error caught during login: ${err.message} (se sikkerLog for detaljer)`); - logger.sikker.warn( - `Error caught during login: ${err.message}, cause ${err.cause}.` + - `The request received: ${util.inspect(req)}`, - err, - ); - authErrorCounter.inc(); - session.destroy((err) => { - if (err) { - return logger.sikker.warn(`Feil oppsto ifm sletting av sesjon: ${err}.`); - } - }); - res.clearCookie('speil'); - res.redirect('/login'); - }); - }); -}; - -setUpAuthentication(); +app.get('/isReady', (_, res) => res.send('ready')); // Protected routes -app.use('/*', async (req: SpeilRequest, res, next) => { +app.use('/*', async (req: Request, res, next) => { if (config.development) { - res.cookie('speil', auth.createTokenForTest(), { + res.cookie('speil', createTokenForTest(), { secure: false, sameSite: true, }); - req.session.user = 'dev-ident'; + next(); } else { - if ( - auth.isValidIn({ seconds: 5, token: req.session!.speilToken }) || - (await auth.refreshAccessToken(azureClient!, req.session!)) - ) { - next(); - } else { - if (req.session!.speilToken) { - const name: string = auth.valueFromClaim('name', req.session!.speilToken); - logger.info(`No valid session found for ${name}, connecting via ${ipAddressFromRequest(req)}`); - logger.sikker.info( - `No valid session found for ${name}, connecting via ${ipAddressFromRequest(req)}`, - logger.requestMeta(req), - ); - } - if (req.originalUrl === '/' || req.originalUrl.startsWith('/static')) { - const user = req.session.user; - req.session.destroy(() => logger.info(`Sesjonen for '${user}' er slettet ifm redirect til /login.`)); - res.redirect('/login'); + const token = getToken(req); + if (!token) { + logger.info(`No valid session found for user, connecting via ${ipAddressFromRequest(req)}`); + logger.sikker.info( + `No valid session found for user, connecting via ${ipAddressFromRequest(req)}`, + logger.requestMeta(req), + ); + + if (req.accepts('html')) { + const url = new URL(req.originalUrl); + res.redirect(`/oauth2/login?redirect=${url.pathname}`); + return; } else { - const url = req.originalUrl; - if (req.accepts('html') && url.includes('/person/')) { - req.session.wantedPathBeforeAuth = url; - logger.sikker.info(`Bruker vil til ${url}, tar vare på den URL-en til etter innlogging`); - res.redirect('/login'); - } else { - // these are not _that_ important, let the client decide how to handle - res.clearCookie('speil'); - res.sendStatus(401); - } + res.sendStatus(401); + return; } } + + const validation = await validateToken(token); + if (!validation.ok) { + if (validation.errorType === 'token expired') { + const url = new URL(req.originalUrl); + res.redirect(`/oauth2/login?redirect=${url.pathname}`); + return; + } + + logger.info(`Token validering feilet: ${validation.errorType}`); + res.sendStatus(401); + } + + next(); } }); diff --git a/packages/backend/sessionStore.ts b/packages/backend/sessionStore.ts deleted file mode 100644 index 78350f8cf..000000000 --- a/packages/backend/sessionStore.ts +++ /dev/null @@ -1,32 +0,0 @@ -import RedisStore from 'connect-redis'; -import expressSession from 'express-session'; -import { RedisClientType } from 'redis'; - -import logger from './logging'; -import { AppConfig } from './types'; - -const createMemoryStoreSession = (config: AppConfig) => { - logger.info('Setting up MemoryStore session store'); - - return expressSession({ - secret: config.server.sessionSecret!, - saveUninitialized: false, - resave: false, - }); -}; - -const createRedisSession = (config: AppConfig, redisClient: RedisClientType) => { - logger.info('Setting up Redis session store'); - - return expressSession({ - secret: config.server.sessionSecret!, - saveUninitialized: false, - resave: false, - store: new RedisStore({ - client: redisClient, - ttl: 43200, // 12 hours - }), - }); -}; - -export { createMemoryStoreSession, createRedisSession }; diff --git a/packages/backend/types.ts b/packages/backend/types.ts index 90d796419..f5de8c963 100644 --- a/packages/backend/types.ts +++ b/packages/backend/types.ts @@ -1,15 +1,6 @@ -import { Request } from 'express'; -import { Session } from 'express-session'; import { ResponseType } from 'openid-client'; -export interface Helsesjekk { - redis: boolean; -} - export interface OidcConfig { - wellKnownEndpoint: string; - tokenEndpoint: string; - clientID: string; clientIDSpesialist: string; clientIDFlexjar: string; modiaApiScope: string; @@ -27,36 +18,3 @@ export interface ServerConfig { flexjarBaseUrl: string; modiaBaseUrl: string; } - -export interface RedisConfig { - url: string; - username: string; - password: string; -} - -export interface AppConfig { - oidc: OidcConfig; - redis: object; - server: ServerConfig; -} - -export type OnBehalfOf = { hentFor: (tjenesteId: string, session: SpeilSession, token: string) => Promise }; - -export interface SpeilSession extends Session { - wantedPathBeforeAuth?: string; - speilToken: string; - refreshToken: string; - oboTokens: { [clientId: string]: string | undefined }; - nonce: string; - state: string; - user: string; -} - -export interface SpeilRequest extends Request { - session: SpeilSession; -} - -export interface AuthError extends Error { - statusCode: number; - cause?: unknown; -} diff --git a/packages/backend/wiring.ts b/packages/backend/wiring.ts index bdd09b985..198830e83 100644 --- a/packages/backend/wiring.ts +++ b/packages/backend/wiring.ts @@ -1,52 +1,39 @@ import { Express } from 'express'; -import { RedisClientType } from 'redis'; -import devOnBehalfOf from './auth/devOnBehalfOf'; -import onBehalfOf from './auth/onBehalfOf'; import config from './config'; import flexjarClient from './flexjar/flexjarClient'; import graphQLClient from './graphql/graphQLClient'; import instrumentationModule, { Instrumentation } from './instrumentation'; import modiaClient from './modia/modiaClient'; -import redisClient from './redisClient'; -import { createMemoryStoreSession, createRedisSession } from './sessionStore'; -import { Helsesjekk } from './types'; -const getDependencies = (app: Express, helsesjekk: Helsesjekk) => - config.development ? getDevDependencies(app) : getProdDependencies(app, helsesjekk); +const getDependencies = (app: Express) => (config.development ? getDevDependencies(app) : getProdDependencies(app)); const getDevDependencies = (app: Express) => { const instrumentation: Instrumentation = instrumentationModule.setup(app); - const _devGraphQLClient = graphQLClient(config.oidc, devOnBehalfOf); - const _devFlexjarClient = flexjarClient(config.oidc, devOnBehalfOf); - const _devModiaClient = modiaClient(config.oidc, devOnBehalfOf); + const _devGraphQLClient = graphQLClient(); + const _devFlexjarClient = flexjarClient(); + const _devModiaClient = modiaClient(); // Fredet 6; return { - sessionStore: createMemoryStoreSession(config), graphql: { graphQLClient: _devGraphQLClient }, flexjar: { flexjarClient: _devFlexjarClient }, modia: { modiaClient: _devModiaClient }, - onBehalfOf: devOnBehalfOf, instrumentation, }; }; -const getProdDependencies = (app: Express, helsesjekk: Helsesjekk) => { - const _redisClient: RedisClientType = redisClient.init(config.redis, helsesjekk); +const getProdDependencies = (app: Express) => { const instrumentation: Instrumentation = instrumentationModule.setup(app); - const _onBehalfOf = onBehalfOf(config.oidc, instrumentation); - const _graphQLClient = graphQLClient(config.oidc, _onBehalfOf); - const _flexjarClient = flexjarClient(config.oidc, _onBehalfOf); - const _ModiaClient = modiaClient(config.oidc, _onBehalfOf); + const _graphQLClient = graphQLClient(); + const _flexjarClient = flexjarClient(); + const _ModiaClient = modiaClient(); return { - sessionStore: createRedisSession(config, _redisClient), graphql: { graphQLClient: _graphQLClient }, flexjar: { flexjarClient: _flexjarClient }, modia: { modiaClient: _ModiaClient }, - onBehalfOf: _onBehalfOf, instrumentation, }; }; diff --git a/packages/frontend/package.json b/packages/frontend/package.json index ee55d227a..12c0f8713 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -26,8 +26,8 @@ "@apollo/client": "^3.8.8", "@grafana/faro-web-sdk": "^1.3.5", "@navikt/ds-css": "^6.8.0", - "@navikt/ds-css-internal": "^2.9.3", - "@navikt/ds-icons": "^2.9.3", + "@navikt/ds-css-internal": "^2.9.8", + "@navikt/ds-icons": "^2.9.8", "@navikt/ds-react": "^6.8.0", "@navikt/ds-tokens": "^6.8.0", "@tanstack/react-query": "^5.25.0",