@oslokommune/auth-bff 1.0.0-beta19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client.d.mts +7 -0
- package/dist/client.d.mts.map +1 -0
- package/dist/client.mjs +92 -0
- package/dist/config-utils.d.mts +2 -0
- package/dist/config-utils.d.mts.map +1 -0
- package/dist/config-utils.mjs +1 -0
- package/dist/config.d.mts +4 -0
- package/dist/config.d.mts.map +1 -0
- package/dist/config.mjs +65 -0
- package/dist/middleware/oidc-routes.d.mts +2 -0
- package/dist/middleware/oidc-routes.d.mts.map +1 -0
- package/dist/middleware/oidc-routes.mjs +9 -0
- package/dist/middleware/oidc.d.mts +16 -0
- package/dist/middleware/oidc.d.mts.map +1 -0
- package/dist/middleware/oidc.mjs +132 -0
- package/dist/middleware/proxy-routes.d.mts +2 -0
- package/dist/middleware/proxy-routes.d.mts.map +1 -0
- package/dist/middleware/proxy-routes.mjs +27 -0
- package/dist/middleware/security-headers.d.mts +2 -0
- package/dist/middleware/security-headers.d.mts.map +1 -0
- package/dist/middleware/security-headers.mjs +30 -0
- package/dist/middleware/sessions.d.mts +2 -0
- package/dist/middleware/sessions.d.mts.map +1 -0
- package/dist/middleware/sessions.mjs +34 -0
- package/dist/middleware/static-routes.d.mts +2 -0
- package/dist/middleware/static-routes.d.mts.map +1 -0
- package/dist/middleware/static-routes.mjs +19 -0
- package/dist/react/AuthContext.d.ts +8 -0
- package/dist/react/AuthContext.d.ts.map +1 -0
- package/dist/react/AuthContext.jsx +2 -0
- package/dist/react/AuthContextProvider.d.ts +9 -0
- package/dist/react/AuthContextProvider.d.ts.map +1 -0
- package/dist/react/AuthContextProvider.jsx +29 -0
- package/dist/react/UseAuthContext.d.ts +2 -0
- package/dist/react/UseAuthContext.d.ts.map +1 -0
- package/dist/react/UseAuthContext.jsx +10 -0
- package/dist/react/index.d.ts +4 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +3 -0
- package/dist/server.d.mts +3 -0
- package/dist/server.d.mts.map +1 -0
- package/dist/server.mjs +40 -0
- package/dist/vite-plugin.d.mts +20 -0
- package/dist/vite-plugin.d.mts.map +1 -0
- package/dist/vite-plugin.mjs +45 -0
- package/package.json +45 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.mts","sourceRoot":"","sources":["../src/client.mjs"],"names":[],"mappings":"AAKA;IAME,yBAEC;IAED,sBASC;IAyDD,kBAEC;;CAEF"}
|
package/dist/client.mjs
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
11
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
12
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
13
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
14
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
15
|
+
};
|
|
16
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
17
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
18
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
19
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
20
|
+
};
|
|
21
|
+
var _OidcClientManager_instances, _OidcClientManager_issuer, _OidcClientManager_config, _OidcClientManager_client, _OidcClientManager_p12ToJwks, _OidcClientManager_createKeyStoreFromOkData, _OidcClientManager_createClient;
|
|
22
|
+
import forge from "node-forge";
|
|
23
|
+
import * as jose from 'jose';
|
|
24
|
+
import { Issuer } from "openid-client";
|
|
25
|
+
import { getSsmParameter } from "./config.mjs";
|
|
26
|
+
export class OidcClientManager {
|
|
27
|
+
constructor(config) {
|
|
28
|
+
_OidcClientManager_instances.add(this);
|
|
29
|
+
_OidcClientManager_issuer.set(this, void 0);
|
|
30
|
+
_OidcClientManager_config.set(this, void 0);
|
|
31
|
+
_OidcClientManager_client.set(this, void 0);
|
|
32
|
+
__classPrivateFieldSet(this, _OidcClientManager_config, config, "f");
|
|
33
|
+
}
|
|
34
|
+
init() {
|
|
35
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
36
|
+
__classPrivateFieldSet(this, _OidcClientManager_issuer, yield Issuer.discover(__classPrivateFieldGet(this, _OidcClientManager_config, "f").oidcDiscoveryUri), "f");
|
|
37
|
+
__classPrivateFieldSet(this, _OidcClientManager_client, yield __classPrivateFieldGet(this, _OidcClientManager_instances, "m", _OidcClientManager_createClient).call(this), "f");
|
|
38
|
+
if (__classPrivateFieldGet(this, _OidcClientManager_config, "f").okDataIdPortenKeyName) {
|
|
39
|
+
setInterval(() => __awaiter(this, void 0, void 0, function* () {
|
|
40
|
+
__classPrivateFieldSet(this, _OidcClientManager_client, yield __classPrivateFieldGet(this, _OidcClientManager_instances, "m", _OidcClientManager_createClient).call(this), "f");
|
|
41
|
+
}), 5 * 60 * 1000);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
get client() {
|
|
46
|
+
return __classPrivateFieldGet(this, _OidcClientManager_client, "f");
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
_OidcClientManager_issuer = new WeakMap(), _OidcClientManager_config = new WeakMap(), _OidcClientManager_client = new WeakMap(), _OidcClientManager_instances = new WeakSet(), _OidcClientManager_p12ToJwks = function _OidcClientManager_p12ToJwks(okdataP12) {
|
|
50
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
51
|
+
const p12Der = forge.util.decode64(okdataP12.keystore);
|
|
52
|
+
const p12Asn1 = forge.asn1.fromDer(p12Der);
|
|
53
|
+
const p12 = forge.pkcs12.pkcs12FromAsn1(p12Asn1, okdataP12.key_password);
|
|
54
|
+
const privateKey = p12.getBagsByFriendlyName(okdataP12.key_alias)[0].key;
|
|
55
|
+
const privateKeyAsn1 = forge.pki.privateKeyToAsn1(privateKey);
|
|
56
|
+
const privateKeyInfo = forge.pki.wrapRsaPrivateKey(privateKeyAsn1);
|
|
57
|
+
const pem = forge.pki.privateKeyInfoToPem(privateKeyInfo);
|
|
58
|
+
const k = yield jose.importPKCS8(pem, 'RS256', { extractable: true });
|
|
59
|
+
const jwk = yield jose.exportJWK(k);
|
|
60
|
+
jwk.kid = okdataP12.key_id;
|
|
61
|
+
jwk.use = 'sig';
|
|
62
|
+
jwk.alg = 'RS256';
|
|
63
|
+
return {
|
|
64
|
+
keys: [jwk]
|
|
65
|
+
};
|
|
66
|
+
});
|
|
67
|
+
}, _OidcClientManager_createKeyStoreFromOkData = function _OidcClientManager_createKeyStoreFromOkData(ssmName) {
|
|
68
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
69
|
+
const keyString = yield getSsmParameter(ssmName);
|
|
70
|
+
const okdataP12 = JSON.parse(keyString);
|
|
71
|
+
return yield __classPrivateFieldGet(this, _OidcClientManager_instances, "m", _OidcClientManager_p12ToJwks).call(this, okdataP12);
|
|
72
|
+
});
|
|
73
|
+
}, _OidcClientManager_createClient = function _OidcClientManager_createClient() {
|
|
74
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
75
|
+
let keyStore;
|
|
76
|
+
if (__classPrivateFieldGet(this, _OidcClientManager_config, "f").okDataIdPortenKeyName) {
|
|
77
|
+
keyStore = yield __classPrivateFieldGet(this, _OidcClientManager_instances, "m", _OidcClientManager_createKeyStoreFromOkData).call(this, __classPrivateFieldGet(this, _OidcClientManager_config, "f").okDataIdPortenKeyName);
|
|
78
|
+
}
|
|
79
|
+
else if (__classPrivateFieldGet(this, _OidcClientManager_config, "f").keyStore) {
|
|
80
|
+
keyStore = __classPrivateFieldGet(this, _OidcClientManager_config, "f").keyStore;
|
|
81
|
+
}
|
|
82
|
+
return new (__classPrivateFieldGet(this, _OidcClientManager_issuer, "f").Client)({
|
|
83
|
+
client_id: __classPrivateFieldGet(this, _OidcClientManager_config, "f").clientId,
|
|
84
|
+
client_secret: __classPrivateFieldGet(this, _OidcClientManager_config, "f").clientSecret,
|
|
85
|
+
redirect_uris: [__classPrivateFieldGet(this, _OidcClientManager_config, "f").redirectUri],
|
|
86
|
+
response_types: ["code"],
|
|
87
|
+
token_endpoint_auth_method: __classPrivateFieldGet(this, _OidcClientManager_config, "f").clientSecret ? "client_secret_post" : "private_key_jwt",
|
|
88
|
+
token_endpoint_auth_signing_alg: "RS256",
|
|
89
|
+
post_logout_redirect_uris: __classPrivateFieldGet(this, _OidcClientManager_config, "f").postLogoutRedirectUris
|
|
90
|
+
}, keyStore);
|
|
91
|
+
});
|
|
92
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-utils.d.mts","sourceRoot":"","sources":["../src/config-utils.mjs"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.mts","sourceRoot":"","sources":["../src/config.mjs"],"names":[],"mappings":"AAGA,qEAQC;AAGD,mFAMC;AAUD,2CAqBC"}
|
package/dist/config.mjs
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import findup from 'findup-sync';
|
|
11
|
+
import { GetParameterCommand, SSMClient } from "@aws-sdk/client-ssm";
|
|
12
|
+
export function getEnv(env, defaultVal, parseFn) {
|
|
13
|
+
if (process.env[env]) {
|
|
14
|
+
return parseFn ? parseFn(process.env[env]) : process.env[env];
|
|
15
|
+
}
|
|
16
|
+
else if (defaultVal !== undefined) {
|
|
17
|
+
return defaultVal;
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
throw Error(`Missing env var: ${env}`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
let ssmClient;
|
|
24
|
+
export function getSsmParameter(name_1) {
|
|
25
|
+
return __awaiter(this, arguments, void 0, function* (name, withDecryption = true) {
|
|
26
|
+
ssmClient !== null && ssmClient !== void 0 ? ssmClient : (ssmClient = new SSMClient({}));
|
|
27
|
+
return ssmClient.send(new GetParameterCommand({
|
|
28
|
+
Name: name,
|
|
29
|
+
WithDecryption: withDecryption
|
|
30
|
+
})).then(p => p.Parameter.Value);
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
const defaultConfig = {
|
|
34
|
+
basePath: "",
|
|
35
|
+
cookieSecure: true,
|
|
36
|
+
cookieSameSite: 'lax',
|
|
37
|
+
staticRootPath: './dist'
|
|
38
|
+
};
|
|
39
|
+
let config;
|
|
40
|
+
export function loadConfig() {
|
|
41
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
42
|
+
var _a;
|
|
43
|
+
if (config)
|
|
44
|
+
return config;
|
|
45
|
+
const userConfigPath = findup('bff.config.json');
|
|
46
|
+
console.log('Loading config at', userConfigPath);
|
|
47
|
+
const { default: loadedConfig } = yield import(userConfigPath, { with: { type: 'json' } });
|
|
48
|
+
for (const [key, value] of Object.entries(loadedConfig)) {
|
|
49
|
+
if (typeof value === "string") {
|
|
50
|
+
const [, varType, varName] = (_a = value.match(/\{(\w+):(.*)}/)) !== null && _a !== void 0 ? _a : [];
|
|
51
|
+
if (varType === 'env') {
|
|
52
|
+
loadedConfig[key] = getEnv(varName);
|
|
53
|
+
}
|
|
54
|
+
else if (varType === 'ssm') {
|
|
55
|
+
loadedConfig[key] = yield getSsmParameter(varName);
|
|
56
|
+
}
|
|
57
|
+
else if (varType) {
|
|
58
|
+
throw Error(`unknown varType: ${varType}`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
config = Object.assign(Object.assign({}, defaultConfig), loadedConfig);
|
|
63
|
+
return config;
|
|
64
|
+
});
|
|
65
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oidc-routes.d.mts","sourceRoot":"","sources":["../../src/middleware/oidc-routes.mjs"],"names":[],"mappings":"AAEA,qDASC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import express from "express";
|
|
2
|
+
export function oidcRoutes(oidcMiddleware) {
|
|
3
|
+
const router = new express.Router();
|
|
4
|
+
router.get('/auth/login', oidcMiddleware.login);
|
|
5
|
+
router.get('/auth/callback', oidcMiddleware.callback);
|
|
6
|
+
router.get('/auth/logout', oidcMiddleware.logout);
|
|
7
|
+
router.get('/auth/user', oidcMiddleware.user);
|
|
8
|
+
return router;
|
|
9
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export class OidcMiddleware {
|
|
2
|
+
static create(config: any): Promise<OidcMiddleware>;
|
|
3
|
+
/**
|
|
4
|
+
* @private
|
|
5
|
+
* @param config
|
|
6
|
+
* @param clientManager
|
|
7
|
+
*/
|
|
8
|
+
private constructor();
|
|
9
|
+
get ensureFreshToken(): (req: any, _: any, next: any) => void;
|
|
10
|
+
get login(): (req: any, res: any) => void;
|
|
11
|
+
get callback(): (req: any, res: any) => Promise<void>;
|
|
12
|
+
get user(): (req: any, res: any) => Promise<any>;
|
|
13
|
+
get logout(): (req: any, res: any) => void;
|
|
14
|
+
#private;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=oidc.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oidc.d.mts","sourceRoot":"","sources":["../../src/middleware/oidc.mjs"],"names":[],"mappings":"AAGA;IAcE,oDAIC;IAdD;;;;OAIG;IACH,sBAGC;IA4BD,yBACU,QAAG,EAAE,MAAC,EAAE,SAAI,UAMrB;IAED,cACU,QAAG,EAAE,QAAG,UAiBjB;IAED,iBACgB,QAAG,EAAE,QAAG,mBAqBvB;IAED,aACgB,QAAG,EAAE,QAAG,kBAQvB;IAED,eACU,QAAG,EAAE,QAAG,UAajB;;CACF"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
11
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
12
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
13
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
14
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
15
|
+
};
|
|
16
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
17
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
18
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
19
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
20
|
+
};
|
|
21
|
+
var _OidcMiddleware_instances, _OidcMiddleware_clientManager, _OidcMiddleware_config, _OidcMiddleware_getFreshTokenSet;
|
|
22
|
+
import { generators, TokenSet } from "openid-client";
|
|
23
|
+
import { OidcClientManager } from "../client.mjs";
|
|
24
|
+
export class OidcMiddleware {
|
|
25
|
+
/**
|
|
26
|
+
* @private
|
|
27
|
+
* @param config
|
|
28
|
+
* @param clientManager
|
|
29
|
+
*/
|
|
30
|
+
constructor(config, clientManager) {
|
|
31
|
+
_OidcMiddleware_instances.add(this);
|
|
32
|
+
_OidcMiddleware_clientManager.set(this, void 0);
|
|
33
|
+
_OidcMiddleware_config.set(this, void 0);
|
|
34
|
+
__classPrivateFieldSet(this, _OidcMiddleware_clientManager, clientManager, "f");
|
|
35
|
+
__classPrivateFieldSet(this, _OidcMiddleware_config, config, "f");
|
|
36
|
+
}
|
|
37
|
+
static create(config) {
|
|
38
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
39
|
+
const clientManager = new OidcClientManager(config);
|
|
40
|
+
yield clientManager.init();
|
|
41
|
+
return new OidcMiddleware(config, clientManager);
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
get ensureFreshToken() {
|
|
45
|
+
return (req, _, next) => {
|
|
46
|
+
__classPrivateFieldGet(this, _OidcMiddleware_instances, "m", _OidcMiddleware_getFreshTokenSet).call(this, req).then(tokenSet => {
|
|
47
|
+
req.tokenSet = tokenSet;
|
|
48
|
+
next();
|
|
49
|
+
});
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
get login() {
|
|
53
|
+
return (req, res) => {
|
|
54
|
+
const codeVerifier = generators.codeVerifier();
|
|
55
|
+
const codeChallenge = generators.codeChallenge(codeVerifier);
|
|
56
|
+
const authorizationUrl = __classPrivateFieldGet(this, _OidcMiddleware_clientManager, "f").client.authorizationUrl({
|
|
57
|
+
scope: "openid profile",
|
|
58
|
+
code_challenge: codeChallenge,
|
|
59
|
+
code_challenge_method: "S256",
|
|
60
|
+
resource: __classPrivateFieldGet(this, _OidcMiddleware_config, "f").resources,
|
|
61
|
+
});
|
|
62
|
+
req.session.codeVerifier = codeVerifier;
|
|
63
|
+
req.session.save(() => {
|
|
64
|
+
res.redirect(authorizationUrl);
|
|
65
|
+
});
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
get callback() {
|
|
69
|
+
return (req, res) => __awaiter(this, void 0, void 0, function* () {
|
|
70
|
+
const params = __classPrivateFieldGet(this, _OidcMiddleware_clientManager, "f").client.callbackParams(req);
|
|
71
|
+
const codeVerifier = req.session.codeVerifier;
|
|
72
|
+
const redirectUri = `${req.protocol}://${req.headers.host}${__classPrivateFieldGet(this, _OidcMiddleware_config, "f").basePath}/auth/callback`;
|
|
73
|
+
try {
|
|
74
|
+
const tokenSet = yield __classPrivateFieldGet(this, _OidcMiddleware_clientManager, "f").client.callback(redirectUri, params, {
|
|
75
|
+
code_verifier: codeVerifier
|
|
76
|
+
});
|
|
77
|
+
delete req.session.codeVerifier;
|
|
78
|
+
req.session.tokenSet = new TokenSet(tokenSet);
|
|
79
|
+
req.session.save(() => {
|
|
80
|
+
res.redirect(__classPrivateFieldGet(this, _OidcMiddleware_config, "f").basePath || "/"); //TODO: skal denne kunne redirecte et annet sted?
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
catch (err) {
|
|
84
|
+
console.error(err);
|
|
85
|
+
res.status(500).send("Error during callback");
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
get user() {
|
|
90
|
+
return (req, res) => __awaiter(this, void 0, void 0, function* () {
|
|
91
|
+
const tokenSet = yield __classPrivateFieldGet(this, _OidcMiddleware_instances, "m", _OidcMiddleware_getFreshTokenSet).call(this, req);
|
|
92
|
+
if (!tokenSet) {
|
|
93
|
+
return res.sendStatus(401);
|
|
94
|
+
}
|
|
95
|
+
return res.send(tokenSet.claims());
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
get logout() {
|
|
99
|
+
return (req, res) => {
|
|
100
|
+
const tokenSet = req.session.tokenSet && new TokenSet(req.session.tokenSet);
|
|
101
|
+
//TODO: støtt frontchannel SLO
|
|
102
|
+
req.session.destroy(() => {
|
|
103
|
+
res.redirect(__classPrivateFieldGet(this, _OidcMiddleware_clientManager, "f").client.endSessionUrl({
|
|
104
|
+
id_token_hint: tokenSet === null || tokenSet === void 0 ? void 0 : tokenSet.id_token,
|
|
105
|
+
}));
|
|
106
|
+
});
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
_OidcMiddleware_clientManager = new WeakMap(), _OidcMiddleware_config = new WeakMap(), _OidcMiddleware_instances = new WeakSet(), _OidcMiddleware_getFreshTokenSet = function _OidcMiddleware_getFreshTokenSet(req) {
|
|
111
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
112
|
+
const tokenSet = req.session.tokenSet && new TokenSet(req.session.tokenSet);
|
|
113
|
+
if (!tokenSet) {
|
|
114
|
+
console.log("No tokenSet found in session");
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
if (tokenSet.expired()) {
|
|
118
|
+
try {
|
|
119
|
+
const refreshedTokenSet = yield __classPrivateFieldGet(this, _OidcMiddleware_clientManager, "f").client.refresh(tokenSet.refresh_token);
|
|
120
|
+
Object.assign(req.session.tokenSet, refreshedTokenSet);
|
|
121
|
+
return new TokenSet(req.session.tokenSet);
|
|
122
|
+
}
|
|
123
|
+
catch (err) {
|
|
124
|
+
console.log("Token refresh failed", err);
|
|
125
|
+
req.session.tokenSet = null;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
return tokenSet;
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy-routes.d.mts","sourceRoot":"","sources":["../../src/middleware/proxy-routes.mjs"],"names":[],"mappings":"AAGA,mEA4BC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import express from "express";
|
|
2
|
+
import { createProxyMiddleware } from "http-proxy-middleware";
|
|
3
|
+
export function proxyRoutes(config, oidcMiddleware) {
|
|
4
|
+
const router = new express.Router();
|
|
5
|
+
for (const [path, target] of Object.entries(config.proxyTargets)) {
|
|
6
|
+
console.log(`Setting up auth proxy: ${path} -> ${target}`);
|
|
7
|
+
router.use(path, oidcMiddleware.ensureFreshToken, createProxyMiddleware({
|
|
8
|
+
target: target,
|
|
9
|
+
changeOrigin: true,
|
|
10
|
+
on: {
|
|
11
|
+
proxyReq: (proxyReq, req, res) => {
|
|
12
|
+
const tokenSet = req.tokenSet;
|
|
13
|
+
if (!tokenSet) {
|
|
14
|
+
console.error("proxy: missing tokenSet");
|
|
15
|
+
return res.status(401);
|
|
16
|
+
}
|
|
17
|
+
proxyReq.setHeader("Authorization", `Bearer ${tokenSet.access_token}`);
|
|
18
|
+
proxyReq.removeHeader("Cookie");
|
|
19
|
+
},
|
|
20
|
+
proxyRes: (proxyRes, req, res) => {
|
|
21
|
+
console.log(`proxyied ${req.originalUrl}: ${proxyRes.statusCode}`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}));
|
|
25
|
+
}
|
|
26
|
+
return router;
|
|
27
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"security-headers.d.mts","sourceRoot":"","sources":["../../src/middleware/security-headers.mjs"],"names":[],"mappings":"AAGA,0FA+BC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import crypto from "crypto";
|
|
2
|
+
import helmet from "helmet";
|
|
3
|
+
export function securityHeaders(config) {
|
|
4
|
+
const contentSecurityPolicy = config.contentSecurityPolicy;
|
|
5
|
+
if (contentSecurityPolicy === null || contentSecurityPolicy === void 0 ? void 0 : contentSecurityPolicy.directives) {
|
|
6
|
+
for (const [_, values] of Object.entries(contentSecurityPolicy.directives)) {
|
|
7
|
+
for (const [i, value] of values.entries()) {
|
|
8
|
+
if (value === '{nonce}') {
|
|
9
|
+
values[i] = (req, res) => `'nonce-${res.locals.cspNonce}'`;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
const generateCspNonceMiddleware = (req, res, next) => {
|
|
15
|
+
res.locals.cspNonce = crypto.randomBytes(16).toString("hex");
|
|
16
|
+
next();
|
|
17
|
+
};
|
|
18
|
+
const helmetMiddleware = helmet({
|
|
19
|
+
strictTransportSecurity: {
|
|
20
|
+
maxAge: 31536000,
|
|
21
|
+
includeSubDomains: false,
|
|
22
|
+
preload: false,
|
|
23
|
+
},
|
|
24
|
+
contentSecurityPolicy: contentSecurityPolicy !== null && contentSecurityPolicy !== void 0 ? contentSecurityPolicy : false,
|
|
25
|
+
});
|
|
26
|
+
return [
|
|
27
|
+
generateCspNonceMiddleware,
|
|
28
|
+
helmetMiddleware
|
|
29
|
+
];
|
|
30
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sessions.d.mts","sourceRoot":"","sources":["../../src/middleware/sessions.mjs"],"names":[],"mappings":"AAQA,2CAwBC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import session from "express-session";
|
|
2
|
+
import dynamoDbStore from "connect-dynamodb";
|
|
3
|
+
function dynamoDbSessionStore(config = {}) {
|
|
4
|
+
const DynamoDbStore = dynamoDbStore({ session });
|
|
5
|
+
return new DynamoDbStore(config);
|
|
6
|
+
}
|
|
7
|
+
export function sessions(config) {
|
|
8
|
+
var _a;
|
|
9
|
+
let sessionStore;
|
|
10
|
+
if (config.sessionStoreType === 'memory') {
|
|
11
|
+
sessionStore = undefined;
|
|
12
|
+
}
|
|
13
|
+
else if (config.sessionStoreType === 'dynamodb') {
|
|
14
|
+
const sessionStoreOptions = (_a = config.sessionStoreOptions) !== null && _a !== void 0 ? _a : {};
|
|
15
|
+
sessionStore = dynamoDbSessionStore(sessionStoreOptions);
|
|
16
|
+
}
|
|
17
|
+
else if (config.sessionStoreType) {
|
|
18
|
+
throw Error(`unknown sessionStoreType ${config.sessionStoreType}`);
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
throw Error('missing sessionStoreType');
|
|
22
|
+
}
|
|
23
|
+
return session({
|
|
24
|
+
secret: config.sessionSecret,
|
|
25
|
+
store: sessionStore,
|
|
26
|
+
resave: false,
|
|
27
|
+
saveUninitialized: false,
|
|
28
|
+
cookie: {
|
|
29
|
+
httpOnly: true,
|
|
30
|
+
secure: config.cookieSecure,
|
|
31
|
+
sameSite: config.cookieSameSite
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"static-routes.d.mts","sourceRoot":"","sources":["../../src/middleware/static-routes.mjs"],"names":[],"mappings":"AAIA,+CAiBC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import express from "express";
|
|
2
|
+
import { stringReplace } from "string-replace-middleware";
|
|
3
|
+
import path from "path";
|
|
4
|
+
export function staticRoutes(config) {
|
|
5
|
+
const router = new express.Router();
|
|
6
|
+
router.use(stringReplace({
|
|
7
|
+
'__CSP_NONCE__': (req, res) => res.locals.cspNonce
|
|
8
|
+
}, {
|
|
9
|
+
contentTypeFilterRegexp: /^text\/html/
|
|
10
|
+
}));
|
|
11
|
+
const staticPath = path.resolve(process.cwd(), config.staticRootPath);
|
|
12
|
+
console.log(`Serving static content from '${staticPath}'`);
|
|
13
|
+
router.use(express.static(staticPath, { index: false }));
|
|
14
|
+
router.get('*', function (req, res) {
|
|
15
|
+
res.set('Cache-Control', 'no-store');
|
|
16
|
+
res.sendFile(path.resolve(staticPath, 'index.html'));
|
|
17
|
+
});
|
|
18
|
+
return router;
|
|
19
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AuthContext.d.ts","sourceRoot":"","sources":["../../src/react/AuthContext.tsx"],"names":[],"mappings":"AAEA,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,SAAS,GAAG,eAAe,GAAG,iBAAiB,CAAC;IACvD,IAAI,CAAC,EAAE;QAAC,GAAG,EAAE,MAAM,CAAA;KAAC,CAAA;CAAC,CAAA;AAEvB,eAAO,MAAM,WAAW,KAAyD,CAAA"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
type AuthContextProviderProps = {
|
|
3
|
+
children: ReactNode;
|
|
4
|
+
authRequired?: boolean;
|
|
5
|
+
loaderComponent: ReactNode;
|
|
6
|
+
};
|
|
7
|
+
export declare function AuthContextProvider({ children, authRequired, loaderComponent }: AuthContextProviderProps): any;
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=AuthContextProvider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AuthContextProvider.d.ts","sourceRoot":"","sources":["../../src/react/AuthContextProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAQ,SAAS,EAA8B,MAAM,OAAO,CAAC;AAGpE,KAAK,wBAAwB,GAAG;IAC9B,QAAQ,EAAE,SAAS,CAAC;IACpB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,eAAe,EAAE,SAAS,CAAA;CAC3B,CAAA;AAED,wBAAgB,mBAAmB,CAAC,EAAC,QAAQ,EAAE,YAAoB,EAAE,eAAsB,EAAC,EAAE,wBAAwB,OA6BrH"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { React, useEffect, useRef, useState } from "react";
|
|
2
|
+
import { AuthContext } from "./AuthContext";
|
|
3
|
+
export function AuthContextProvider({ children, authRequired = false, loaderComponent = null }) {
|
|
4
|
+
const [user, setUser] = useState(undefined);
|
|
5
|
+
const [state, setState] = useState('pending');
|
|
6
|
+
const userPromise = useRef(undefined);
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
var _a;
|
|
9
|
+
((_a = userPromise.current) !== null && _a !== void 0 ? _a : (userPromise.current = fetch('/auth/user').then(res => res.ok && res.json())))
|
|
10
|
+
.then(json => {
|
|
11
|
+
if (json) {
|
|
12
|
+
setUser(json);
|
|
13
|
+
setState('authenticated');
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
setState('unauthenticated');
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
}, []);
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
if (authRequired && state === 'unauthenticated') {
|
|
22
|
+
window.location.assign('/auth/login');
|
|
23
|
+
}
|
|
24
|
+
}, [authRequired, state]);
|
|
25
|
+
return (<AuthContext.Provider value={{ user, state }}>
|
|
26
|
+
{(authRequired && state !== 'authenticated' || !authRequired && state === 'pending') && loaderComponent}
|
|
27
|
+
{(authRequired && state === 'authenticated' || !authRequired && state !== 'pending') && children}
|
|
28
|
+
</AuthContext.Provider>);
|
|
29
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UseAuthContext.d.ts","sourceRoot":"","sources":["../../src/react/UseAuthContext.tsx"],"names":[],"mappings":"AAGA,wBAAgB,cAAc,CAAC,QAAQ,GAAE,OAAe,OAOvD"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { useContext } from "react";
|
|
2
|
+
import { AuthContext } from "./AuthContext";
|
|
3
|
+
export function useAuthContext(required = false) {
|
|
4
|
+
const authContext = useContext(AuthContext);
|
|
5
|
+
if (required && (authContext === null || authContext === void 0 ? void 0 : authContext.state) === 'unauthenticated') {
|
|
6
|
+
window.location.assign('/auth/login');
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
return authContext;
|
|
10
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAA;AAC7B,cAAc,uBAAuB,CAAA;AACrC,cAAc,kBAAkB,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.mts","sourceRoot":"","sources":["../src/server.mjs"],"names":[],"mappings":""}
|
package/dist/server.mjs
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import express from "express";
|
|
3
|
+
import compression from "compression";
|
|
4
|
+
import { loadConfig } from './config.mjs';
|
|
5
|
+
import { proxyRoutes } from "./middleware/proxy-routes.mjs";
|
|
6
|
+
import { staticRoutes } from "./middleware/static-routes.mjs";
|
|
7
|
+
import { securityHeaders } from "./middleware/security-headers.mjs";
|
|
8
|
+
import { sessions } from "./middleware/sessions.mjs";
|
|
9
|
+
import { oidcRoutes } from "./middleware/oidc-routes.mjs";
|
|
10
|
+
import { OidcMiddleware } from "./middleware/oidc.mjs";
|
|
11
|
+
const config = await loadConfig();
|
|
12
|
+
const port = process.env.port || config.port || 8080;
|
|
13
|
+
const oidcMiddleware = await OidcMiddleware.create(config);
|
|
14
|
+
const app = express();
|
|
15
|
+
app.set('trust proxy', true); // TODO: sjekk om denne kan/bør være strengere: https://expressjs.com/en/api.html#trust.proxy.options.table
|
|
16
|
+
app.disable("x-powered-by");
|
|
17
|
+
app.use((req, res, next) => {
|
|
18
|
+
//request logging
|
|
19
|
+
next();
|
|
20
|
+
console.log(`${req.method} ${req.originalUrl}`);
|
|
21
|
+
});
|
|
22
|
+
app.use(compression());
|
|
23
|
+
app.use(sessions(config));
|
|
24
|
+
app.use(securityHeaders(config));
|
|
25
|
+
app.get("/health", (req, res) => {
|
|
26
|
+
res.send("OK");
|
|
27
|
+
});
|
|
28
|
+
const basePath = config.basePath || "/";
|
|
29
|
+
app.use(basePath, oidcRoutes(oidcMiddleware));
|
|
30
|
+
app.use(basePath, proxyRoutes(config, oidcMiddleware));
|
|
31
|
+
app.use(basePath, staticRoutes(config));
|
|
32
|
+
const server = app.listen(port, () => {
|
|
33
|
+
console.log(`Server started on port ${port}`);
|
|
34
|
+
});
|
|
35
|
+
process.on('SIGTERM', () => {
|
|
36
|
+
console.log('SIGTERM received. Closing...');
|
|
37
|
+
server.close(() => {
|
|
38
|
+
console.log('Server closed');
|
|
39
|
+
});
|
|
40
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* @returns {{
|
|
4
|
+
* name: string,
|
|
5
|
+
* apply: 'serve',
|
|
6
|
+
* configureServer: ((function({middlewares: *}): Promise<void>)|*),
|
|
7
|
+
* configurePreviewServer: ((function({middlewares: *}): Promise<void>)|*)
|
|
8
|
+
* }}
|
|
9
|
+
*/
|
|
10
|
+
export default function bff(): {
|
|
11
|
+
name: string;
|
|
12
|
+
apply: "serve";
|
|
13
|
+
configureServer: (((arg0: {
|
|
14
|
+
middlewares: any;
|
|
15
|
+
}) => Promise<void>) | any);
|
|
16
|
+
configurePreviewServer: (((arg0: {
|
|
17
|
+
middlewares: any;
|
|
18
|
+
}) => Promise<void>) | any);
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=vite-plugin.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vite-plugin.d.mts","sourceRoot":"","sources":["../src/vite-plugin.mjs"],"names":[],"mappings":"AAuBA;;;;;;;;GAQG;AACH,+BAPa;IACT,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;IACf,eAAe,EAAE,CAAC,CAAC,CAAS,IAAgB,EAAhB;QAAC,WAAW,EAAE,GAAC,CAAA;KAAC,KAAG,OAAO,CAAC,IAAI,CAAC,CAAC,GAAC,GAAC,CAAC,CAAC;IACjE,sBAAsB,EAAE,CAAC,CAAC,CAAS,IAAgB,EAAhB;QAAC,WAAW,EAAE,GAAC,CAAA;KAAC,KAAG,OAAO,CAAC,IAAI,CAAC,CAAC,GAAC,GAAC,CAAC,CAAA;CACvE,CASH"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import express from "express";
|
|
11
|
+
import { loadConfig } from "./config.mjs";
|
|
12
|
+
import { OidcMiddleware } from "./middleware/oidc.mjs";
|
|
13
|
+
import { securityHeaders } from "./middleware/security-headers.mjs";
|
|
14
|
+
function configureServer(_a) {
|
|
15
|
+
return __awaiter(this, arguments, void 0, function* ({ middlewares }) {
|
|
16
|
+
const { oidcRoutes } = yield import("./middleware/oidc-routes.mjs");
|
|
17
|
+
const { proxyRoutes } = yield import("./middleware/proxy-routes.mjs");
|
|
18
|
+
const { sessions } = yield import("./middleware/sessions.mjs");
|
|
19
|
+
const config = yield loadConfig();
|
|
20
|
+
const oidcMiddleware = yield OidcMiddleware.create(config);
|
|
21
|
+
const basePath = "" || "/";
|
|
22
|
+
const app = express();
|
|
23
|
+
app.use(sessions(config));
|
|
24
|
+
app.use(basePath, oidcRoutes(oidcMiddleware));
|
|
25
|
+
app.use(basePath, proxyRoutes(config, oidcMiddleware));
|
|
26
|
+
middlewares.use(app);
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
*
|
|
31
|
+
* @returns {{
|
|
32
|
+
* name: string,
|
|
33
|
+
* apply: 'serve',
|
|
34
|
+
* configureServer: ((function({middlewares: *}): Promise<void>)|*),
|
|
35
|
+
* configurePreviewServer: ((function({middlewares: *}): Promise<void>)|*)
|
|
36
|
+
* }}
|
|
37
|
+
*/
|
|
38
|
+
export default function bff() {
|
|
39
|
+
return {
|
|
40
|
+
name: 'bff',
|
|
41
|
+
apply: 'serve',
|
|
42
|
+
configureServer: configureServer,
|
|
43
|
+
configurePreviewServer: configureServer
|
|
44
|
+
};
|
|
45
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@oslokommune/auth-bff",
|
|
3
|
+
"version": "1.0.0-beta19",
|
|
4
|
+
"repository": "https://github.com/oslokommune/auth-bff.git",
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"access": "public"
|
|
7
|
+
},
|
|
8
|
+
"scripts": {
|
|
9
|
+
"build": "tsc",
|
|
10
|
+
"run": "node ./dist/server.mjs",
|
|
11
|
+
"build-and-publish": "tsc && npm publish"
|
|
12
|
+
},
|
|
13
|
+
"exports": {
|
|
14
|
+
"./vite-plugin": "./dist/vite-plugin.mjs",
|
|
15
|
+
"./react": "./dist/react/index.js"
|
|
16
|
+
},
|
|
17
|
+
"bin": {
|
|
18
|
+
"auth-bff": "dist/server.mjs"
|
|
19
|
+
},
|
|
20
|
+
"files": ["/dist"],
|
|
21
|
+
"type": "module",
|
|
22
|
+
"author": "",
|
|
23
|
+
"license": "",
|
|
24
|
+
"description": "",
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@types/express": "^4.17.22",
|
|
27
|
+
"react": "17.0.2",
|
|
28
|
+
"typescript": "^5.8.3"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@aws-sdk/client-dynamodb": "^3.817.0",
|
|
32
|
+
"@aws-sdk/client-ssm": "^3.817.0",
|
|
33
|
+
"compression": "^1.8.0",
|
|
34
|
+
"connect-dynamodb": "^3.0.5",
|
|
35
|
+
"express": "^4.21.2",
|
|
36
|
+
"express-session": "^1.18.1",
|
|
37
|
+
"findup-sync": "^5.0.0",
|
|
38
|
+
"helmet": "^8.1.0",
|
|
39
|
+
"http-proxy-middleware": "^3.0.5",
|
|
40
|
+
"jose": "^6.0.11",
|
|
41
|
+
"node-forge": "^1.3.1",
|
|
42
|
+
"openid-client": "^5.7.1",
|
|
43
|
+
"string-replace-middleware": "^1.1.0"
|
|
44
|
+
}
|
|
45
|
+
}
|