@monocloud/auth-node-core 0.0.0-canary-20251223204113
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/LICENSE +21 -0
- package/README.md +143 -0
- package/dist/index.cjs +1105 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +676 -0
- package/dist/index.d.mts +676 -0
- package/dist/index.mjs +1040 -0
- package/dist/index.mjs.map +1 -0
- package/dist/utils/index.cjs +9 -0
- package/dist/utils/index.d.cts +1 -0
- package/dist/utils/index.d.mts +1 -0
- package/dist/utils/index.mjs +3 -0
- package/dist/utils/internal.cjs +9 -0
- package/dist/utils/internal.d.cts +1 -0
- package/dist/utils/internal.d.mts +1 -0
- package/dist/utils/internal.mjs +3 -0
- package/package.json +80 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,1040 @@
|
|
|
1
|
+
import { MonoCloudAuthBaseError, MonoCloudHttpError, MonoCloudOPError, MonoCloudOidcClient, MonoCloudOidcClient as MonoCloudOidcClient$1, MonoCloudTokenError, MonoCloudValidationError, MonoCloudValidationError as MonoCloudValidationError$1 } from "@monocloud/auth-core";
|
|
2
|
+
import { createRemoteJWKSet, jwtVerify } from "jose";
|
|
3
|
+
import { ensureLeadingSlash, findToken, getBoolean, getNumber, isAbsoluteUrl, isPresent, isSameHost, now, parseSpaceSeparated, parseSpaceSeparatedSet, removeTrailingSlash, setsEqual } from "@monocloud/auth-core/internal";
|
|
4
|
+
import { decrypt, decryptAuthState, encrypt, encryptAuthState, generateNonce, generatePKCE, generateState, isUserInGroup, mergeArrays, parseCallbackParams } from "@monocloud/auth-core/utils";
|
|
5
|
+
import { v4 } from "uuid";
|
|
6
|
+
import { serialize } from "cookie";
|
|
7
|
+
import Joi from "joi";
|
|
8
|
+
import dbug from "debug";
|
|
9
|
+
|
|
10
|
+
//#region src/monocloud-session-service.ts
|
|
11
|
+
const CHUNK_BYTE_SIZE = 4090;
|
|
12
|
+
var MonoCloudSessionService = class {
|
|
13
|
+
constructor(options) {
|
|
14
|
+
this.options = options;
|
|
15
|
+
}
|
|
16
|
+
async setSession(req, res, session) {
|
|
17
|
+
const key = v4();
|
|
18
|
+
const iat = now();
|
|
19
|
+
const uat = iat;
|
|
20
|
+
const cookieValue = {
|
|
21
|
+
key,
|
|
22
|
+
lifetime: {
|
|
23
|
+
c: iat,
|
|
24
|
+
u: uat,
|
|
25
|
+
e: this.getExpiry(iat, uat)
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
await this.saveSession(req, res, cookieValue, session);
|
|
29
|
+
return key;
|
|
30
|
+
}
|
|
31
|
+
async getSession(req, res, shouldResave = true) {
|
|
32
|
+
const cookieValue = await this.getCookieData(req);
|
|
33
|
+
if (!cookieValue) {
|
|
34
|
+
await this.deleteAllCookies(req, res);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
if (!await this.validateSession(req, res, cookieValue)) return;
|
|
38
|
+
const uat = now();
|
|
39
|
+
const exp = this.getExpiry(cookieValue.lifetime.c, uat);
|
|
40
|
+
if (!this.options.session.store) {
|
|
41
|
+
const session$1 = { user: {} };
|
|
42
|
+
if (!cookieValue.session) return;
|
|
43
|
+
Object.assign(session$1, JSON.parse(JSON.stringify(cookieValue.session)));
|
|
44
|
+
if (shouldResave && exp !== cookieValue.lifetime.e) await this.saveSession(req, res, {
|
|
45
|
+
...cookieValue,
|
|
46
|
+
lifetime: {
|
|
47
|
+
c: cookieValue.lifetime.c,
|
|
48
|
+
u: uat,
|
|
49
|
+
e: exp
|
|
50
|
+
}
|
|
51
|
+
}, session$1);
|
|
52
|
+
return session$1;
|
|
53
|
+
}
|
|
54
|
+
const sessionObj = await this.options.session.store.get(cookieValue.key);
|
|
55
|
+
if (!sessionObj) {
|
|
56
|
+
await this.deleteAllCookies(req, res);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
const session = { user: {} };
|
|
60
|
+
Object.assign(session, JSON.parse(JSON.stringify(sessionObj)));
|
|
61
|
+
if (shouldResave && exp !== cookieValue.lifetime.e) await this.saveSession(req, res, {
|
|
62
|
+
...cookieValue,
|
|
63
|
+
lifetime: {
|
|
64
|
+
c: cookieValue.lifetime.c,
|
|
65
|
+
u: uat,
|
|
66
|
+
e: exp
|
|
67
|
+
}
|
|
68
|
+
}, session);
|
|
69
|
+
return session;
|
|
70
|
+
}
|
|
71
|
+
async updateSession(req, res, session) {
|
|
72
|
+
const cookieValue = await this.getCookieData(req);
|
|
73
|
+
if (!cookieValue) {
|
|
74
|
+
await this.deleteAllCookies(req, res);
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
if (!await this.validateSession(req, res, cookieValue)) return false;
|
|
78
|
+
const uat = now();
|
|
79
|
+
const exp = this.getExpiry(cookieValue.lifetime.c, uat);
|
|
80
|
+
await this.saveSession(req, res, {
|
|
81
|
+
...cookieValue,
|
|
82
|
+
lifetime: {
|
|
83
|
+
c: cookieValue.lifetime.c,
|
|
84
|
+
u: uat,
|
|
85
|
+
e: exp
|
|
86
|
+
}
|
|
87
|
+
}, session);
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
async removeSession(req, res) {
|
|
91
|
+
const cookieValue = await this.getCookieData(req);
|
|
92
|
+
if (!cookieValue) {
|
|
93
|
+
await this.deleteAllCookies(req, res);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
if (this.options.session.store) {
|
|
97
|
+
/* v8 ignore else -- @preserve */
|
|
98
|
+
if (cookieValue.key) await this.options.session.store.delete(cookieValue.key);
|
|
99
|
+
}
|
|
100
|
+
await this.deleteAllCookies(req, res);
|
|
101
|
+
}
|
|
102
|
+
async validateSession(req, res, cookieValue) {
|
|
103
|
+
const nowTime = now();
|
|
104
|
+
let isValid = true;
|
|
105
|
+
if (cookieValue.lifetime.e && cookieValue.lifetime.e < nowTime) isValid = false;
|
|
106
|
+
if (this.options.session.sliding && cookieValue.lifetime.u + this.options.session.duration < nowTime) isValid = false;
|
|
107
|
+
if (cookieValue.lifetime.c + this.options.session.maximumDuration < nowTime) isValid = false;
|
|
108
|
+
if (isValid) return true;
|
|
109
|
+
if (this.options.session.store) await this.options.session.store.delete(cookieValue.key);
|
|
110
|
+
await this.deleteAllCookies(req, res);
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
async saveSession(req, res, cookieValue, session) {
|
|
114
|
+
var _await$this$getReques;
|
|
115
|
+
const cookies = new Set(((_await$this$getReques = await this.getRequestCookie(req)) === null || _await$this$getReques === void 0 ? void 0 : _await$this$getReques.keys) ?? []);
|
|
116
|
+
if (!this.options.session.store) cookieValue.session = session;
|
|
117
|
+
if (this.options.session.store) {
|
|
118
|
+
const cookieData = await this.getCookieData(req);
|
|
119
|
+
if (cookieData === null || cookieData === void 0 ? void 0 : cookieData.key) await this.options.session.store.delete(cookieData.key);
|
|
120
|
+
cookieValue.session = void 0;
|
|
121
|
+
await this.options.session.store.set(cookieValue.key, session, cookieValue.lifetime);
|
|
122
|
+
}
|
|
123
|
+
const encryptedData = await encrypt(JSON.stringify(cookieValue), this.options.cookieSecret);
|
|
124
|
+
const cookieExpiry = cookieValue.lifetime.e ? /* @__PURE__ */ new Date(cookieValue.lifetime.e * 1e3) : void 0;
|
|
125
|
+
const cookieOptions = this.getCookieOptions(cookieExpiry);
|
|
126
|
+
const chunkSize = CHUNK_BYTE_SIZE - serialize(`${this.options.session.cookie.name}.0`, "", cookieOptions).length;
|
|
127
|
+
const chunks = Math.ceil(encryptedData.length / chunkSize);
|
|
128
|
+
for (let i = 0; i < chunks; i += 1) {
|
|
129
|
+
const encryptedChunk = encryptedData.slice(i * chunkSize, (i + 1) * chunkSize);
|
|
130
|
+
const cookieName = chunks === 1 ? this.options.session.cookie.name : `${this.options.session.cookie.name}.${i}`;
|
|
131
|
+
await res.setCookie(cookieName, encryptedChunk, this.getCookieOptions(cookieExpiry));
|
|
132
|
+
cookies.delete(cookieName);
|
|
133
|
+
}
|
|
134
|
+
for (const cookie of cookies) await res.setCookie(cookie, "", this.getCookieOptions(/* @__PURE__ */ new Date(0)));
|
|
135
|
+
}
|
|
136
|
+
async getCookieData(req) {
|
|
137
|
+
const cookieData = await this.getRequestCookie(req);
|
|
138
|
+
if (!(cookieData === null || cookieData === void 0 ? void 0 : cookieData.value)) return;
|
|
139
|
+
const data = await decrypt(cookieData.value, this.options.cookieSecret);
|
|
140
|
+
if (!data) return;
|
|
141
|
+
return JSON.parse(data);
|
|
142
|
+
}
|
|
143
|
+
async getRequestCookie(req) {
|
|
144
|
+
const cookies = await req.getAllCookies();
|
|
145
|
+
if (!cookies.size) return;
|
|
146
|
+
const val = cookies.get(this.options.session.cookie.name);
|
|
147
|
+
if (val) return {
|
|
148
|
+
keys: [this.options.session.cookie.name],
|
|
149
|
+
value: val
|
|
150
|
+
};
|
|
151
|
+
const cookieValues = Array.from(cookies.entries()).filter(([cookie]) => cookie.startsWith(`${this.options.session.cookie.name}.`)).map(([cookie, value]) => ({
|
|
152
|
+
key: parseInt(cookie.split(".").pop() || "0", 10),
|
|
153
|
+
value
|
|
154
|
+
})).sort((a, b) => a.key - b.key);
|
|
155
|
+
const cookieValue = cookieValues.map(({ value }) => value).join("");
|
|
156
|
+
if (!cookieValue) return;
|
|
157
|
+
return {
|
|
158
|
+
keys: cookieValues.map(({ key }) => `${this.options.session.cookie.name}.${key}`),
|
|
159
|
+
value: cookieValue
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
getExpiry(iat, uat) {
|
|
163
|
+
if (!this.options.session.cookie.persistent) return;
|
|
164
|
+
if (!this.options.session.sliding) return Math.floor(iat + this.options.session.duration);
|
|
165
|
+
return Math.floor(Math.min(uat + this.options.session.duration, iat + this.options.session.maximumDuration));
|
|
166
|
+
}
|
|
167
|
+
getCookieOptions(exp) {
|
|
168
|
+
return {
|
|
169
|
+
domain: this.options.session.cookie.domain,
|
|
170
|
+
httpOnly: this.options.session.cookie.httpOnly,
|
|
171
|
+
sameSite: this.options.session.cookie.sameSite,
|
|
172
|
+
secure: this.options.session.cookie.secure,
|
|
173
|
+
path: this.options.session.cookie.path,
|
|
174
|
+
expires: exp
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
async deleteAllCookies(req, res) {
|
|
178
|
+
var _reqCookie$keys;
|
|
179
|
+
const reqCookie = await this.getRequestCookie(req);
|
|
180
|
+
const cookies = reqCookie === null || reqCookie === void 0 || (_reqCookie$keys = reqCookie.keys) === null || _reqCookie$keys === void 0 ? void 0 : _reqCookie$keys.filter((x) => x.startsWith(this.options.session.cookie.name));
|
|
181
|
+
for (const cookie of cookies ?? []) await res.setCookie(cookie, "", this.getCookieOptions(/* @__PURE__ */ new Date(0)));
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
//#endregion
|
|
186
|
+
//#region src/monocloud-state-service.ts
|
|
187
|
+
var MonoCloudStateService = class {
|
|
188
|
+
constructor(options) {
|
|
189
|
+
this.options = options;
|
|
190
|
+
}
|
|
191
|
+
async setState(res, state, overrideSameSite) {
|
|
192
|
+
await res.setCookie(this.options.state.cookie.name, await encryptAuthState(state, this.options.cookieSecret), this.getCookieOptions(overrideSameSite));
|
|
193
|
+
}
|
|
194
|
+
async getState(req, res) {
|
|
195
|
+
const cookie = await req.getCookie(this.options.state.cookie.name);
|
|
196
|
+
if (!cookie) return;
|
|
197
|
+
let decryptedResult;
|
|
198
|
+
try {
|
|
199
|
+
decryptedResult = await decryptAuthState(cookie, this.options.cookieSecret);
|
|
200
|
+
} catch {
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
await res.setCookie(this.options.state.cookie.name, "", {
|
|
204
|
+
...this.getCookieOptions(),
|
|
205
|
+
expires: /* @__PURE__ */ new Date(0)
|
|
206
|
+
});
|
|
207
|
+
return decryptedResult;
|
|
208
|
+
}
|
|
209
|
+
getCookieOptions(sameSite) {
|
|
210
|
+
return {
|
|
211
|
+
domain: this.options.state.cookie.domain,
|
|
212
|
+
httpOnly: this.options.state.cookie.httpOnly,
|
|
213
|
+
sameSite: sameSite ?? this.options.state.cookie.sameSite,
|
|
214
|
+
secure: this.options.state.cookie.secure,
|
|
215
|
+
path: this.options.state.cookie.path
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
//#endregion
|
|
221
|
+
//#region src/options/defaults.ts
|
|
222
|
+
const DEFAULT_OPTIONS = {
|
|
223
|
+
routes: {
|
|
224
|
+
callback: "/api/auth/callback",
|
|
225
|
+
backChannelLogout: "/api/auth/backchannel-logout",
|
|
226
|
+
signIn: "/api/auth/signin",
|
|
227
|
+
signOut: "/api/auth/signout",
|
|
228
|
+
userInfo: "/api/auth/userinfo"
|
|
229
|
+
},
|
|
230
|
+
clockSkew: 60,
|
|
231
|
+
responseTimeout: 1e4,
|
|
232
|
+
usePar: false,
|
|
233
|
+
userInfo: true,
|
|
234
|
+
refetchUserInfo: false,
|
|
235
|
+
federatedSignOut: true,
|
|
236
|
+
defaultAuthParams: {
|
|
237
|
+
scopes: "openid profile email",
|
|
238
|
+
responseType: "code"
|
|
239
|
+
},
|
|
240
|
+
session: {
|
|
241
|
+
cookie: {
|
|
242
|
+
httpOnly: true,
|
|
243
|
+
name: "session",
|
|
244
|
+
path: "/",
|
|
245
|
+
sameSite: "lax",
|
|
246
|
+
persistent: true
|
|
247
|
+
},
|
|
248
|
+
sliding: false,
|
|
249
|
+
duration: 1440 * 60,
|
|
250
|
+
maximumDuration: 10080 * 60
|
|
251
|
+
},
|
|
252
|
+
state: { cookie: {
|
|
253
|
+
httpOnly: true,
|
|
254
|
+
name: "state",
|
|
255
|
+
path: "/",
|
|
256
|
+
sameSite: "lax",
|
|
257
|
+
persistent: false
|
|
258
|
+
} },
|
|
259
|
+
idTokenSigningAlg: "RS256",
|
|
260
|
+
filteredIdTokenClaims: [
|
|
261
|
+
"iss",
|
|
262
|
+
"exp",
|
|
263
|
+
"nbf",
|
|
264
|
+
"aud",
|
|
265
|
+
"nonce",
|
|
266
|
+
"iat",
|
|
267
|
+
"auth_time",
|
|
268
|
+
"c_hash",
|
|
269
|
+
"at_hash",
|
|
270
|
+
"s_hash"
|
|
271
|
+
],
|
|
272
|
+
debugger: "node-auth-core",
|
|
273
|
+
userAgent: "node-auth-core"
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
//#endregion
|
|
277
|
+
//#region src/options/validation.ts
|
|
278
|
+
const stringRequired = Joi.string().required();
|
|
279
|
+
const stringOptional = Joi.string().optional();
|
|
280
|
+
const boolRequired = Joi.boolean().required();
|
|
281
|
+
const boolOptional = Joi.boolean().optional();
|
|
282
|
+
const numRequired = Joi.number().required();
|
|
283
|
+
const numOptional = Joi.number().optional();
|
|
284
|
+
const objectOptional = Joi.object().optional();
|
|
285
|
+
const funcOptional = Joi.function().optional();
|
|
286
|
+
const sessionCookieSchema = Joi.object({
|
|
287
|
+
name: stringRequired,
|
|
288
|
+
path: stringRequired.uri({ relativeOnly: true }),
|
|
289
|
+
domain: stringOptional,
|
|
290
|
+
httpOnly: boolRequired,
|
|
291
|
+
secure: boolRequired.when(Joi.ref("/appUrl"), {
|
|
292
|
+
is: Joi.string().pattern(/^https:/i),
|
|
293
|
+
then: Joi.valid(true).messages({ "any.only": "Cookie must be set to secure when app url protocol is https." }),
|
|
294
|
+
otherwise: Joi.valid(false)
|
|
295
|
+
}),
|
|
296
|
+
sameSite: stringRequired.valid("strict", "lax", "none"),
|
|
297
|
+
persistent: boolRequired
|
|
298
|
+
}).required();
|
|
299
|
+
const resourceSchema = stringRequired.custom((value, helpers) => {
|
|
300
|
+
let valid;
|
|
301
|
+
try {
|
|
302
|
+
const url = new URL(value);
|
|
303
|
+
valid = url.searchParams.size === 0 && url.hash.length === 0;
|
|
304
|
+
} catch {
|
|
305
|
+
valid = false;
|
|
306
|
+
}
|
|
307
|
+
if (!valid) return helpers.message({ custom: "Resource must be a valid URL without query or hash parameters" });
|
|
308
|
+
return value;
|
|
309
|
+
});
|
|
310
|
+
const resourceValidationSchema = Joi.string().custom((value, helpers) => {
|
|
311
|
+
const parts = value.split(/\s+/).map((x) => x.trim()).filter(Boolean);
|
|
312
|
+
if (parts.length === 0) return helpers.message({ custom: "Resource must not be empty" });
|
|
313
|
+
for (const part of parts) {
|
|
314
|
+
const { error } = resourceSchema.validate(part);
|
|
315
|
+
if (error) return helpers.message({ custom: `Invalid resource "${part}": ${error.message}` });
|
|
316
|
+
}
|
|
317
|
+
return parts.join(" ");
|
|
318
|
+
}).messages({ "string.base": "Resource must be a space-separated string of URLs" });
|
|
319
|
+
const sessionSchema = Joi.object({
|
|
320
|
+
cookie: sessionCookieSchema,
|
|
321
|
+
sliding: boolRequired,
|
|
322
|
+
duration: numRequired.min(1),
|
|
323
|
+
maximumDuration: numRequired.min(1).greater(Joi.ref("duration")),
|
|
324
|
+
store: objectOptional
|
|
325
|
+
}).required();
|
|
326
|
+
const stateSchema = Joi.object({ cookie: sessionCookieSchema }).required();
|
|
327
|
+
const scopesSchema = stringRequired.custom((value, helpers) => {
|
|
328
|
+
const scopes = value.split(/\s+/).map((x) => x.trim()).filter(Boolean);
|
|
329
|
+
if (scopes.length === 0) return helpers.message({ custom: "Scopes must be a space-separated string" });
|
|
330
|
+
if (!scopes.includes("openid")) return helpers.message({ custom: "Scope must contain openid" });
|
|
331
|
+
return scopes.join(" ");
|
|
332
|
+
}).messages({ "string.base": "Scopes must be a space-separated string" });
|
|
333
|
+
const authParamSchema = Joi.object({
|
|
334
|
+
scopes: scopesSchema,
|
|
335
|
+
responseType: stringOptional.valid("code").optional(),
|
|
336
|
+
responseMode: stringOptional.valid("query", "form_post"),
|
|
337
|
+
resource: resourceValidationSchema.optional()
|
|
338
|
+
}).unknown(true).required();
|
|
339
|
+
const optionalAuthParamSchema = Joi.object({
|
|
340
|
+
scopes: scopesSchema,
|
|
341
|
+
responseType: stringOptional.valid("code").optional(),
|
|
342
|
+
responseMode: stringOptional.valid("query", "form_post")
|
|
343
|
+
}).unknown(true).optional();
|
|
344
|
+
const routesSchema = Joi.object({
|
|
345
|
+
callback: stringRequired.uri({ relativeOnly: true }),
|
|
346
|
+
backChannelLogout: stringRequired.uri({ relativeOnly: true }),
|
|
347
|
+
signIn: stringRequired.uri({ relativeOnly: true }),
|
|
348
|
+
signOut: stringRequired.uri({ relativeOnly: true }),
|
|
349
|
+
userInfo: stringRequired.uri({ relativeOnly: true })
|
|
350
|
+
}).required();
|
|
351
|
+
const scopesValidationSchema = stringRequired.custom((value, helpers) => {
|
|
352
|
+
const scopes = value.split(/\s+/).map((x) => x.trim()).filter(Boolean);
|
|
353
|
+
if (scopes.length === 0) return helpers.message({ custom: "Scopes must be a space-separated string" });
|
|
354
|
+
return scopes.join(" ");
|
|
355
|
+
}).messages({ "string.base": "Scopes must be a space-separated string" });
|
|
356
|
+
const indicatorOptionsSchema = Joi.object({
|
|
357
|
+
resource: resourceValidationSchema,
|
|
358
|
+
scopes: scopesValidationSchema.optional()
|
|
359
|
+
});
|
|
360
|
+
const optionsSchema = Joi.object({
|
|
361
|
+
clientId: stringRequired,
|
|
362
|
+
clientSecret: stringRequired,
|
|
363
|
+
tenantDomain: stringRequired.uri(),
|
|
364
|
+
cookieSecret: stringRequired.min(8),
|
|
365
|
+
appUrl: stringRequired.uri(),
|
|
366
|
+
routes: routesSchema,
|
|
367
|
+
clockSkew: numRequired,
|
|
368
|
+
responseTimeout: numRequired.min(1e3),
|
|
369
|
+
usePar: boolRequired,
|
|
370
|
+
postLogoutRedirectUri: stringOptional.uri({ allowRelative: true }),
|
|
371
|
+
federatedSignOut: boolRequired,
|
|
372
|
+
userInfo: boolRequired,
|
|
373
|
+
refetchUserInfo: boolRequired,
|
|
374
|
+
defaultAuthParams: authParamSchema,
|
|
375
|
+
resources: Joi.array().items(indicatorOptionsSchema).optional(),
|
|
376
|
+
session: sessionSchema,
|
|
377
|
+
state: stateSchema,
|
|
378
|
+
idTokenSigningAlg: Joi.string().valid("RS256", "RS384", "RS512", "PS256", "PS384", "PS512", "ES256", "ES384", "ES512"),
|
|
379
|
+
filteredIdTokenClaims: Joi.array().items(stringRequired),
|
|
380
|
+
debugger: stringRequired,
|
|
381
|
+
userAgent: stringRequired,
|
|
382
|
+
jwksCacheDuration: numOptional,
|
|
383
|
+
metadataCacheDuration: numOptional,
|
|
384
|
+
onBackChannelLogout: funcOptional,
|
|
385
|
+
onSetApplicationState: funcOptional,
|
|
386
|
+
onSessionCreating: funcOptional
|
|
387
|
+
});
|
|
388
|
+
const signInOptionsSchema = Joi.object({
|
|
389
|
+
returnUrl: stringOptional.uri({ allowRelative: true }),
|
|
390
|
+
register: boolOptional,
|
|
391
|
+
authParams: optionalAuthParamSchema,
|
|
392
|
+
onError: funcOptional
|
|
393
|
+
});
|
|
394
|
+
const callbackOptionsSchema = Joi.object({
|
|
395
|
+
userInfo: boolOptional,
|
|
396
|
+
redirectUri: stringOptional.uri(),
|
|
397
|
+
onError: funcOptional
|
|
398
|
+
});
|
|
399
|
+
const userInfoOptionsSchema = Joi.object({
|
|
400
|
+
refresh: boolOptional,
|
|
401
|
+
onError: funcOptional
|
|
402
|
+
});
|
|
403
|
+
const signOutOptionsSchema = Joi.object({
|
|
404
|
+
postLogoutRedirectUri: stringOptional.uri({ allowRelative: true }),
|
|
405
|
+
idToken: stringOptional,
|
|
406
|
+
state: stringOptional,
|
|
407
|
+
federatedSignOut: boolOptional,
|
|
408
|
+
onError: funcOptional
|
|
409
|
+
});
|
|
410
|
+
const getTokensOptionsSchema = Joi.object({
|
|
411
|
+
forceRefresh: boolOptional,
|
|
412
|
+
refetchUserInfo: boolOptional,
|
|
413
|
+
resource: resourceValidationSchema.optional(),
|
|
414
|
+
scopes: scopesValidationSchema.optional()
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
//#endregion
|
|
418
|
+
//#region src/options/get-options.ts
|
|
419
|
+
const getOptions = (options, throwOnError = true) => {
|
|
420
|
+
var _options$defaultAuthP, _options$defaultAuthP2, _options$defaultAuthP3, _options$routes, _options$routes2, _options$routes3, _options$routes4, _options$routes5, _options$session, _options$session2, _options$session3, _options$session4, _options$session5, _options$session6, _options$session7, _options$session8, _options$session9, _options$session10, _options$session11, _options$state, _options$state2, _options$state3, _options$state4, _options$state5, _options$state6;
|
|
421
|
+
const MONOCLOUD_AUTH_CLIENT_ID = process.env.MONOCLOUD_AUTH_CLIENT_ID;
|
|
422
|
+
const MONOCLOUD_AUTH_CLIENT_SECRET = process.env.MONOCLOUD_AUTH_CLIENT_SECRET;
|
|
423
|
+
const MONOCLOUD_AUTH_TENANT_DOMAIN = process.env.MONOCLOUD_AUTH_TENANT_DOMAIN;
|
|
424
|
+
const MONOCLOUD_AUTH_SCOPES = process.env.MONOCLOUD_AUTH_SCOPES;
|
|
425
|
+
const MONOCLOUD_AUTH_COOKIE_SECRET = process.env.MONOCLOUD_AUTH_COOKIE_SECRET;
|
|
426
|
+
const MONOCLOUD_AUTH_APP_URL = process.env.MONOCLOUD_AUTH_APP_URL;
|
|
427
|
+
const MONOCLOUD_AUTH_CALLBACK_URL = process.env.MONOCLOUD_AUTH_CALLBACK_URL;
|
|
428
|
+
const MONOCLOUD_AUTH_BACK_CHANNEL_LOGOUT_URL = process.env.MONOCLOUD_AUTH_BACK_CHANNEL_LOGOUT_URL;
|
|
429
|
+
const MONOCLOUD_AUTH_SIGNIN_URL = process.env.MONOCLOUD_AUTH_SIGNIN_URL;
|
|
430
|
+
const MONOCLOUD_AUTH_SIGNOUT_URL = process.env.MONOCLOUD_AUTH_SIGNOUT_URL;
|
|
431
|
+
const MONOCLOUD_AUTH_USER_INFO_URL = process.env.MONOCLOUD_AUTH_USER_INFO_URL;
|
|
432
|
+
const MONOCLOUD_AUTH_RESOURCE = process.env.MONOCLOUD_AUTH_RESOURCE;
|
|
433
|
+
const MONOCLOUD_AUTH_CLOCK_SKEW = process.env.MONOCLOUD_AUTH_CLOCK_SKEW;
|
|
434
|
+
const MONOCLOUD_AUTH_RESPONSE_TIMEOUT = process.env.MONOCLOUD_AUTH_RESPONSE_TIMEOUT;
|
|
435
|
+
const MONOCLOUD_AUTH_USE_PAR = process.env.MONOCLOUD_AUTH_USE_PAR;
|
|
436
|
+
const MONOCLOUD_AUTH_POST_LOGOUT_REDIRECT_URI = process.env.MONOCLOUD_AUTH_POST_LOGOUT_REDIRECT_URI;
|
|
437
|
+
const MONOCLOUD_AUTH_FEDERATED_SIGNOUT = process.env.MONOCLOUD_AUTH_FEDERATED_SIGNOUT;
|
|
438
|
+
const MONOCLOUD_AUTH_USER_INFO = process.env.MONOCLOUD_AUTH_USER_INFO;
|
|
439
|
+
const MONOCLOUD_AUTH_REFETCH_USER_INFO = process.env.MONOCLOUD_AUTH_REFETCH_USER_INFO;
|
|
440
|
+
const MONOCLOUD_AUTH_SESSION_COOKIE_NAME = process.env.MONOCLOUD_AUTH_SESSION_COOKIE_NAME;
|
|
441
|
+
const MONOCLOUD_AUTH_SESSION_COOKIE_PATH = process.env.MONOCLOUD_AUTH_SESSION_COOKIE_PATH;
|
|
442
|
+
const MONOCLOUD_AUTH_SESSION_COOKIE_DOMAIN = process.env.MONOCLOUD_AUTH_SESSION_COOKIE_DOMAIN;
|
|
443
|
+
const MONOCLOUD_AUTH_SESSION_COOKIE_HTTP_ONLY = process.env.MONOCLOUD_AUTH_SESSION_COOKIE_HTTP_ONLY;
|
|
444
|
+
const MONOCLOUD_AUTH_SESSION_COOKIE_SECURE = process.env.MONOCLOUD_AUTH_SESSION_COOKIE_SECURE;
|
|
445
|
+
const MONOCLOUD_AUTH_SESSION_COOKIE_SAME_SITE = process.env.MONOCLOUD_AUTH_SESSION_COOKIE_SAME_SITE;
|
|
446
|
+
const MONOCLOUD_AUTH_SESSION_COOKIE_PERSISTENT = process.env.MONOCLOUD_AUTH_SESSION_COOKIE_PERSISTENT;
|
|
447
|
+
const MONOCLOUD_AUTH_SESSION_SLIDING = process.env.MONOCLOUD_AUTH_SESSION_SLIDING;
|
|
448
|
+
const MONOCLOUD_AUTH_SESSION_DURATION = process.env.MONOCLOUD_AUTH_SESSION_DURATION;
|
|
449
|
+
const MONOCLOUD_AUTH_SESSION_MAX_DURATION = process.env.MONOCLOUD_AUTH_SESSION_MAX_DURATION;
|
|
450
|
+
const MONOCLOUD_AUTH_STATE_COOKIE_NAME = process.env.MONOCLOUD_AUTH_STATE_COOKIE_NAME;
|
|
451
|
+
const MONOCLOUD_AUTH_STATE_COOKIE_PATH = process.env.MONOCLOUD_AUTH_STATE_COOKIE_PATH;
|
|
452
|
+
const MONOCLOUD_AUTH_STATE_COOKIE_DOMAIN = process.env.MONOCLOUD_AUTH_STATE_COOKIE_DOMAIN;
|
|
453
|
+
const MONOCLOUD_AUTH_STATE_COOKIE_SECURE = process.env.MONOCLOUD_AUTH_STATE_COOKIE_SECURE;
|
|
454
|
+
const MONOCLOUD_AUTH_STATE_COOKIE_SAME_SITE = process.env.MONOCLOUD_AUTH_STATE_COOKIE_SAME_SITE;
|
|
455
|
+
const MONOCLOUD_AUTH_STATE_COOKIE_PERSISTENT = process.env.MONOCLOUD_AUTH_STATE_COOKIE_PERSISTENT;
|
|
456
|
+
const MONOCLOUD_AUTH_ID_TOKEN_SIGNING_ALG = process.env.MONOCLOUD_AUTH_ID_TOKEN_SIGNING_ALG;
|
|
457
|
+
const MONOCLOUD_AUTH_FILTERED_ID_TOKEN_CLAIMS = process.env.MONOCLOUD_AUTH_FILTERED_ID_TOKEN_CLAIMS;
|
|
458
|
+
const MONOCLOUD_AUTH_JWKS_CACHE_DURATION = process.env.MONOCLOUD_AUTH_JWKS_CACHE_DURATION;
|
|
459
|
+
const MONOCLOUD_AUTH_METADATA_CACHE_DURATION = process.env.MONOCLOUD_AUTH_METADATA_CACHE_DURATION;
|
|
460
|
+
const appUrl = (options === null || options === void 0 ? void 0 : options.appUrl) ?? MONOCLOUD_AUTH_APP_URL;
|
|
461
|
+
const opt = {
|
|
462
|
+
clientId: (options === null || options === void 0 ? void 0 : options.clientId) ?? MONOCLOUD_AUTH_CLIENT_ID,
|
|
463
|
+
clientSecret: (options === null || options === void 0 ? void 0 : options.clientSecret) ?? MONOCLOUD_AUTH_CLIENT_SECRET,
|
|
464
|
+
tenantDomain: (options === null || options === void 0 ? void 0 : options.tenantDomain) ?? MONOCLOUD_AUTH_TENANT_DOMAIN,
|
|
465
|
+
defaultAuthParams: {
|
|
466
|
+
...(options === null || options === void 0 ? void 0 : options.defaultAuthParams) ?? {},
|
|
467
|
+
scopes: (options === null || options === void 0 || (_options$defaultAuthP = options.defaultAuthParams) === null || _options$defaultAuthP === void 0 ? void 0 : _options$defaultAuthP.scopes) ?? MONOCLOUD_AUTH_SCOPES ?? DEFAULT_OPTIONS.defaultAuthParams.scopes,
|
|
468
|
+
responseType: (options === null || options === void 0 || (_options$defaultAuthP2 = options.defaultAuthParams) === null || _options$defaultAuthP2 === void 0 ? void 0 : _options$defaultAuthP2.responseType) ?? DEFAULT_OPTIONS.defaultAuthParams.responseType,
|
|
469
|
+
resource: (options === null || options === void 0 || (_options$defaultAuthP3 = options.defaultAuthParams) === null || _options$defaultAuthP3 === void 0 ? void 0 : _options$defaultAuthP3.resource) ?? MONOCLOUD_AUTH_RESOURCE
|
|
470
|
+
},
|
|
471
|
+
resources: options === null || options === void 0 ? void 0 : options.resources,
|
|
472
|
+
cookieSecret: (options === null || options === void 0 ? void 0 : options.cookieSecret) ?? MONOCLOUD_AUTH_COOKIE_SECRET,
|
|
473
|
+
appUrl: removeTrailingSlash(appUrl),
|
|
474
|
+
routes: {
|
|
475
|
+
callback: removeTrailingSlash((options === null || options === void 0 || (_options$routes = options.routes) === null || _options$routes === void 0 ? void 0 : _options$routes.callback) ?? MONOCLOUD_AUTH_CALLBACK_URL ?? DEFAULT_OPTIONS.routes.callback),
|
|
476
|
+
backChannelLogout: removeTrailingSlash((options === null || options === void 0 || (_options$routes2 = options.routes) === null || _options$routes2 === void 0 ? void 0 : _options$routes2.backChannelLogout) ?? MONOCLOUD_AUTH_BACK_CHANNEL_LOGOUT_URL ?? DEFAULT_OPTIONS.routes.backChannelLogout),
|
|
477
|
+
signIn: removeTrailingSlash((options === null || options === void 0 || (_options$routes3 = options.routes) === null || _options$routes3 === void 0 ? void 0 : _options$routes3.signIn) ?? MONOCLOUD_AUTH_SIGNIN_URL ?? DEFAULT_OPTIONS.routes.signIn),
|
|
478
|
+
signOut: removeTrailingSlash((options === null || options === void 0 || (_options$routes4 = options.routes) === null || _options$routes4 === void 0 ? void 0 : _options$routes4.signOut) ?? MONOCLOUD_AUTH_SIGNOUT_URL ?? DEFAULT_OPTIONS.routes.signOut),
|
|
479
|
+
userInfo: removeTrailingSlash((options === null || options === void 0 || (_options$routes5 = options.routes) === null || _options$routes5 === void 0 ? void 0 : _options$routes5.userInfo) ?? MONOCLOUD_AUTH_USER_INFO_URL ?? DEFAULT_OPTIONS.routes.userInfo)
|
|
480
|
+
},
|
|
481
|
+
clockSkew: (options === null || options === void 0 ? void 0 : options.clockSkew) ?? getNumber(MONOCLOUD_AUTH_CLOCK_SKEW) ?? DEFAULT_OPTIONS.clockSkew,
|
|
482
|
+
responseTimeout: (options === null || options === void 0 ? void 0 : options.responseTimeout) ?? getNumber(MONOCLOUD_AUTH_RESPONSE_TIMEOUT) ?? DEFAULT_OPTIONS.responseTimeout,
|
|
483
|
+
usePar: (options === null || options === void 0 ? void 0 : options.usePar) ?? getBoolean(MONOCLOUD_AUTH_USE_PAR) ?? DEFAULT_OPTIONS.usePar,
|
|
484
|
+
postLogoutRedirectUri: (options === null || options === void 0 ? void 0 : options.postLogoutRedirectUri) ?? MONOCLOUD_AUTH_POST_LOGOUT_REDIRECT_URI,
|
|
485
|
+
federatedSignOut: (options === null || options === void 0 ? void 0 : options.federatedSignOut) ?? getBoolean(MONOCLOUD_AUTH_FEDERATED_SIGNOUT) ?? DEFAULT_OPTIONS.federatedSignOut,
|
|
486
|
+
userInfo: (options === null || options === void 0 ? void 0 : options.userInfo) ?? getBoolean(MONOCLOUD_AUTH_USER_INFO) ?? DEFAULT_OPTIONS.userInfo,
|
|
487
|
+
refetchUserInfo: (options === null || options === void 0 ? void 0 : options.refetchUserInfo) ?? getBoolean(MONOCLOUD_AUTH_REFETCH_USER_INFO) ?? DEFAULT_OPTIONS.refetchUserInfo,
|
|
488
|
+
session: {
|
|
489
|
+
cookie: {
|
|
490
|
+
name: (options === null || options === void 0 || (_options$session = options.session) === null || _options$session === void 0 || (_options$session = _options$session.cookie) === null || _options$session === void 0 ? void 0 : _options$session.name) ?? MONOCLOUD_AUTH_SESSION_COOKIE_NAME ?? DEFAULT_OPTIONS.session.cookie.name,
|
|
491
|
+
path: (options === null || options === void 0 || (_options$session2 = options.session) === null || _options$session2 === void 0 || (_options$session2 = _options$session2.cookie) === null || _options$session2 === void 0 ? void 0 : _options$session2.path) ?? MONOCLOUD_AUTH_SESSION_COOKIE_PATH ?? DEFAULT_OPTIONS.session.cookie.path,
|
|
492
|
+
domain: (options === null || options === void 0 || (_options$session3 = options.session) === null || _options$session3 === void 0 || (_options$session3 = _options$session3.cookie) === null || _options$session3 === void 0 ? void 0 : _options$session3.domain) ?? MONOCLOUD_AUTH_SESSION_COOKIE_DOMAIN,
|
|
493
|
+
httpOnly: (options === null || options === void 0 || (_options$session4 = options.session) === null || _options$session4 === void 0 || (_options$session4 = _options$session4.cookie) === null || _options$session4 === void 0 ? void 0 : _options$session4.httpOnly) ?? getBoolean(MONOCLOUD_AUTH_SESSION_COOKIE_HTTP_ONLY) ?? DEFAULT_OPTIONS.session.cookie.httpOnly,
|
|
494
|
+
secure: (options === null || options === void 0 || (_options$session5 = options.session) === null || _options$session5 === void 0 || (_options$session5 = _options$session5.cookie) === null || _options$session5 === void 0 ? void 0 : _options$session5.secure) ?? getBoolean(MONOCLOUD_AUTH_SESSION_COOKIE_SECURE) ?? (appUrl === null || appUrl === void 0 ? void 0 : appUrl.startsWith("https:")),
|
|
495
|
+
sameSite: (options === null || options === void 0 || (_options$session6 = options.session) === null || _options$session6 === void 0 || (_options$session6 = _options$session6.cookie) === null || _options$session6 === void 0 ? void 0 : _options$session6.sameSite) ?? MONOCLOUD_AUTH_SESSION_COOKIE_SAME_SITE ?? DEFAULT_OPTIONS.session.cookie.sameSite,
|
|
496
|
+
persistent: (options === null || options === void 0 || (_options$session7 = options.session) === null || _options$session7 === void 0 || (_options$session7 = _options$session7.cookie) === null || _options$session7 === void 0 ? void 0 : _options$session7.persistent) ?? getBoolean(MONOCLOUD_AUTH_SESSION_COOKIE_PERSISTENT) ?? DEFAULT_OPTIONS.session.cookie.persistent
|
|
497
|
+
},
|
|
498
|
+
sliding: (options === null || options === void 0 || (_options$session8 = options.session) === null || _options$session8 === void 0 ? void 0 : _options$session8.sliding) ?? getBoolean(MONOCLOUD_AUTH_SESSION_SLIDING) ?? DEFAULT_OPTIONS.session.sliding,
|
|
499
|
+
duration: (options === null || options === void 0 || (_options$session9 = options.session) === null || _options$session9 === void 0 ? void 0 : _options$session9.duration) ?? getNumber(MONOCLOUD_AUTH_SESSION_DURATION) ?? DEFAULT_OPTIONS.session.duration,
|
|
500
|
+
maximumDuration: (options === null || options === void 0 || (_options$session10 = options.session) === null || _options$session10 === void 0 ? void 0 : _options$session10.maximumDuration) ?? getNumber(MONOCLOUD_AUTH_SESSION_MAX_DURATION) ?? DEFAULT_OPTIONS.session.maximumDuration,
|
|
501
|
+
store: options === null || options === void 0 || (_options$session11 = options.session) === null || _options$session11 === void 0 ? void 0 : _options$session11.store
|
|
502
|
+
},
|
|
503
|
+
state: { cookie: {
|
|
504
|
+
name: (options === null || options === void 0 || (_options$state = options.state) === null || _options$state === void 0 || (_options$state = _options$state.cookie) === null || _options$state === void 0 ? void 0 : _options$state.name) ?? MONOCLOUD_AUTH_STATE_COOKIE_NAME ?? DEFAULT_OPTIONS.state.cookie.name,
|
|
505
|
+
path: (options === null || options === void 0 || (_options$state2 = options.state) === null || _options$state2 === void 0 || (_options$state2 = _options$state2.cookie) === null || _options$state2 === void 0 ? void 0 : _options$state2.path) ?? MONOCLOUD_AUTH_STATE_COOKIE_PATH ?? DEFAULT_OPTIONS.state.cookie.path,
|
|
506
|
+
domain: (options === null || options === void 0 || (_options$state3 = options.state) === null || _options$state3 === void 0 || (_options$state3 = _options$state3.cookie) === null || _options$state3 === void 0 ? void 0 : _options$state3.domain) ?? MONOCLOUD_AUTH_STATE_COOKIE_DOMAIN,
|
|
507
|
+
httpOnly: DEFAULT_OPTIONS.state.cookie.httpOnly,
|
|
508
|
+
secure: (options === null || options === void 0 || (_options$state4 = options.state) === null || _options$state4 === void 0 || (_options$state4 = _options$state4.cookie) === null || _options$state4 === void 0 ? void 0 : _options$state4.secure) ?? getBoolean(MONOCLOUD_AUTH_STATE_COOKIE_SECURE) ?? (appUrl === null || appUrl === void 0 ? void 0 : appUrl.startsWith("https:")),
|
|
509
|
+
sameSite: (options === null || options === void 0 || (_options$state5 = options.state) === null || _options$state5 === void 0 || (_options$state5 = _options$state5.cookie) === null || _options$state5 === void 0 ? void 0 : _options$state5.sameSite) ?? MONOCLOUD_AUTH_STATE_COOKIE_SAME_SITE ?? DEFAULT_OPTIONS.state.cookie.sameSite,
|
|
510
|
+
persistent: (options === null || options === void 0 || (_options$state6 = options.state) === null || _options$state6 === void 0 || (_options$state6 = _options$state6.cookie) === null || _options$state6 === void 0 ? void 0 : _options$state6.persistent) ?? getBoolean(MONOCLOUD_AUTH_STATE_COOKIE_PERSISTENT) ?? DEFAULT_OPTIONS.state.cookie.persistent
|
|
511
|
+
} },
|
|
512
|
+
idTokenSigningAlg: (options === null || options === void 0 ? void 0 : options.idTokenSigningAlg) ?? MONOCLOUD_AUTH_ID_TOKEN_SIGNING_ALG ?? DEFAULT_OPTIONS.idTokenSigningAlg,
|
|
513
|
+
filteredIdTokenClaims: (options === null || options === void 0 ? void 0 : options.filteredIdTokenClaims) ?? (MONOCLOUD_AUTH_FILTERED_ID_TOKEN_CLAIMS === null || MONOCLOUD_AUTH_FILTERED_ID_TOKEN_CLAIMS === void 0 ? void 0 : MONOCLOUD_AUTH_FILTERED_ID_TOKEN_CLAIMS.split(" ").map((x) => x.trim()).filter((x) => x.length)) ?? DEFAULT_OPTIONS.filteredIdTokenClaims,
|
|
514
|
+
debugger: (options === null || options === void 0 ? void 0 : options.debugger) ?? DEFAULT_OPTIONS.debugger,
|
|
515
|
+
userAgent: (options === null || options === void 0 ? void 0 : options.userAgent) ?? DEFAULT_OPTIONS.userAgent,
|
|
516
|
+
jwksCacheDuration: (options === null || options === void 0 ? void 0 : options.jwksCacheDuration) ?? getNumber(MONOCLOUD_AUTH_JWKS_CACHE_DURATION),
|
|
517
|
+
metadataCacheDuration: (options === null || options === void 0 ? void 0 : options.metadataCacheDuration) ?? getNumber(MONOCLOUD_AUTH_METADATA_CACHE_DURATION),
|
|
518
|
+
onBackChannelLogout: options === null || options === void 0 ? void 0 : options.onBackChannelLogout,
|
|
519
|
+
onSetApplicationState: options === null || options === void 0 ? void 0 : options.onSetApplicationState,
|
|
520
|
+
onSessionCreating: options === null || options === void 0 ? void 0 : options.onSessionCreating
|
|
521
|
+
};
|
|
522
|
+
const { value, error } = optionsSchema.validate(opt, { abortEarly: false });
|
|
523
|
+
const requiredEnv = {
|
|
524
|
+
tenantDomain: "MONOCLOUD_AUTH_TENANT_DOMAIN",
|
|
525
|
+
clientId: "MONOCLOUD_AUTH_CLIENT_ID",
|
|
526
|
+
clientSecret: "MONOCLOUD_AUTH_CLIENT_SECRET",
|
|
527
|
+
appUrl: "MONOCLOUD_AUTH_APP_URL",
|
|
528
|
+
cookieSecret: "MONOCLOUD_AUTH_COOKIE_SECRET"
|
|
529
|
+
};
|
|
530
|
+
if (error) {
|
|
531
|
+
if (throwOnError) throw new MonoCloudValidationError$1(error.details[0].message);
|
|
532
|
+
console.warn("WARNING: One or more configuration options were not provided for MonoCloudClient.");
|
|
533
|
+
error.details.forEach((detail) => {
|
|
534
|
+
var _detail$context;
|
|
535
|
+
if (((_detail$context = detail.context) === null || _detail$context === void 0 ? void 0 : _detail$context.key) && requiredEnv[detail.context.key]) console.warn(`Missing: ${detail.context.key} - Set ${requiredEnv[detail.context.key]} enviornment variable in your .env file.`);
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
return value;
|
|
539
|
+
};
|
|
540
|
+
|
|
541
|
+
//#endregion
|
|
542
|
+
//#region src/monocloud-node-core-client.ts
|
|
543
|
+
var MonoCloudCoreClient = class {
|
|
544
|
+
constructor(partialOptions) {
|
|
545
|
+
this.optionsValidated = false;
|
|
546
|
+
this.options = getOptions(partialOptions, false);
|
|
547
|
+
this.oidcClient = new MonoCloudOidcClient$1(this.options.tenantDomain, this.options.clientId, {
|
|
548
|
+
clientSecret: this.options.clientSecret,
|
|
549
|
+
idTokenSigningAlgorithm: this.options.idTokenSigningAlg
|
|
550
|
+
});
|
|
551
|
+
this.debug = dbug(this.options.debugger);
|
|
552
|
+
this.stateService = new MonoCloudStateService(this.options);
|
|
553
|
+
this.sessionService = new MonoCloudSessionService(this.options);
|
|
554
|
+
/* v8 ignore next -- @preserve */
|
|
555
|
+
if (process.env.DEBUG && !this.debug.enabled) dbug.enable(process.env.DEBUG);
|
|
556
|
+
this.debug("Debug logging enabled.");
|
|
557
|
+
}
|
|
558
|
+
/**
|
|
559
|
+
* Initiates the sign-in flow by redirecting the user to the MonoCloud authorization endpoint.
|
|
560
|
+
*
|
|
561
|
+
* This method handles scope and resource merging, state generation (nonce, state, PKCE),
|
|
562
|
+
* and Constructing the final authorization URL.
|
|
563
|
+
*
|
|
564
|
+
* @param request - MonoCloud request object.
|
|
565
|
+
* @param response - MonoCloud response object.
|
|
566
|
+
* @param signInOptions - Optional configuration to customize the sign-in behavior.
|
|
567
|
+
* @returns A promise that resolves when the callback processing and redirection are complete.
|
|
568
|
+
*
|
|
569
|
+
* @throws {@link MonoCloudValidationError} When validation of parameters or state fails.
|
|
570
|
+
*/
|
|
571
|
+
async signIn(request, response, signInOptions) {
|
|
572
|
+
this.debug("Starting sign-in handler");
|
|
573
|
+
try {
|
|
574
|
+
var _this$options$resourc, _this$options$resourc2, _signInOptions$authPa, _signInOptions$authPa2, _signInOptions$authPa3;
|
|
575
|
+
this.validateOptions();
|
|
576
|
+
const { method } = await request.getRawRequest();
|
|
577
|
+
if (method.toLowerCase() !== "get") {
|
|
578
|
+
response.methodNotAllowed();
|
|
579
|
+
return response.done();
|
|
580
|
+
}
|
|
581
|
+
const indicatorResource = (_this$options$resourc = this.options.resources) === null || _this$options$resourc === void 0 ? void 0 : _this$options$resourc.map((x) => x.resource).filter((x) => !!x).reduce((acc, x) => `${acc} ${x}`, "");
|
|
582
|
+
const indicatorScopes = (_this$options$resourc2 = this.options.resources) === null || _this$options$resourc2 === void 0 ? void 0 : _this$options$resourc2.map((x) => x.scopes).filter((x) => !!x).reduce((acc, x) => `${acc} ${x}`, "");
|
|
583
|
+
const mergedScopes = mergeArrays(parseSpaceSeparated(signInOptions === null || signInOptions === void 0 || (_signInOptions$authPa = signInOptions.authParams) === null || _signInOptions$authPa === void 0 ? void 0 : _signInOptions$authPa.scopes), parseSpaceSeparated(this.options.defaultAuthParams.scopes), parseSpaceSeparated(indicatorScopes)) ?? ["openid"];
|
|
584
|
+
const mergedResources = mergeArrays(parseSpaceSeparated(signInOptions === null || signInOptions === void 0 || (_signInOptions$authPa2 = signInOptions.authParams) === null || _signInOptions$authPa2 === void 0 ? void 0 : _signInOptions$authPa2.resource), parseSpaceSeparated(this.options.defaultAuthParams.resource), parseSpaceSeparated(indicatorResource));
|
|
585
|
+
const opt = {
|
|
586
|
+
...signInOptions ?? {},
|
|
587
|
+
authParams: {
|
|
588
|
+
...this.options.defaultAuthParams,
|
|
589
|
+
...signInOptions === null || signInOptions === void 0 ? void 0 : signInOptions.authParams,
|
|
590
|
+
scopes: mergedScopes.join(" "),
|
|
591
|
+
acrValues: mergeArrays(signInOptions === null || signInOptions === void 0 || (_signInOptions$authPa3 = signInOptions.authParams) === null || _signInOptions$authPa3 === void 0 ? void 0 : _signInOptions$authPa3.acrValues, this.options.defaultAuthParams.acrValues),
|
|
592
|
+
resource: mergedResources === null || mergedResources === void 0 ? void 0 : mergedResources.join(" ")
|
|
593
|
+
}
|
|
594
|
+
};
|
|
595
|
+
let appState = {};
|
|
596
|
+
if (this.options.onSetApplicationState) {
|
|
597
|
+
appState = await this.options.onSetApplicationState(request);
|
|
598
|
+
if (appState === null || appState === void 0 || typeof appState !== "object" || Array.isArray(appState)) throw new MonoCloudValidationError$1("Invalid Application State. Expected state to be an object");
|
|
599
|
+
}
|
|
600
|
+
const retUrl = request.getQuery("return_url") ?? opt.returnUrl;
|
|
601
|
+
if (typeof retUrl === "string" && retUrl && (!isAbsoluteUrl(retUrl) || isSameHost(this.options.appUrl, retUrl))) opt.returnUrl = retUrl;
|
|
602
|
+
const { error } = signInOptionsSchema.validate(opt, { abortEarly: true });
|
|
603
|
+
if (error) throw new MonoCloudValidationError$1(error.details[0].message);
|
|
604
|
+
const state = generateState();
|
|
605
|
+
const nonce = generateNonce();
|
|
606
|
+
const { codeChallenge, codeVerifier } = await generatePKCE();
|
|
607
|
+
const maxAgeQuery = request.getQuery("max_age");
|
|
608
|
+
if (typeof maxAgeQuery === "string" && maxAgeQuery) {
|
|
609
|
+
const parsedMaxAge = parseInt(maxAgeQuery, 10);
|
|
610
|
+
if (!isNaN(parsedMaxAge)) opt.authParams.maxAge = parsedMaxAge;
|
|
611
|
+
}
|
|
612
|
+
const returnUrl = encodeURIComponent(opt.returnUrl ?? this.options.appUrl);
|
|
613
|
+
let params = {
|
|
614
|
+
redirectUri: `${this.options.appUrl}${ensureLeadingSlash(this.options.routes.callback)}`,
|
|
615
|
+
...opt.authParams,
|
|
616
|
+
nonce,
|
|
617
|
+
state,
|
|
618
|
+
codeChallenge
|
|
619
|
+
};
|
|
620
|
+
const authenticatorHint = request.getQuery("authenticator_hint") ?? opt.authParams.authenticatorHint;
|
|
621
|
+
if (typeof authenticatorHint === "string" && authenticatorHint) params.authenticatorHint = authenticatorHint;
|
|
622
|
+
const reqScope = request.getQuery("scope");
|
|
623
|
+
const scopes = (typeof reqScope === "string" ? reqScope : void 0) ?? opt.authParams.scopes;
|
|
624
|
+
if (scopes) {
|
|
625
|
+
const { error: e } = scopesValidationSchema.validate(scopes, { abortEarly: true });
|
|
626
|
+
if (!e) params.scopes = scopes;
|
|
627
|
+
}
|
|
628
|
+
const reqResource = request.getQuery("resource");
|
|
629
|
+
const resource = (typeof reqResource === "string" ? reqResource : void 0) ?? opt.authParams.resource;
|
|
630
|
+
if (resource) {
|
|
631
|
+
const { error: e } = resourceValidationSchema.validate(resource, { abortEarly: true });
|
|
632
|
+
if (!e) params.resource = resource;
|
|
633
|
+
}
|
|
634
|
+
const display = request.getQuery("display") ?? opt.authParams.display;
|
|
635
|
+
if (typeof display === "string" && display) params.display = display;
|
|
636
|
+
const uiLocales = request.getQuery("ui_locales") ?? opt.authParams.uiLocales;
|
|
637
|
+
if (typeof uiLocales === "string" && uiLocales) params.uiLocales = uiLocales;
|
|
638
|
+
const acrValues = request.getQuery("acr_values") ?? opt.authParams.acrValues;
|
|
639
|
+
if (typeof acrValues === "string" && acrValues) params.acrValues = acrValues.split(" ").map((x) => x.trim()).filter((x) => x !== "");
|
|
640
|
+
const loginHint = request.getQuery("login_hint") ?? opt.authParams.loginHint;
|
|
641
|
+
if (typeof loginHint === "string" && loginHint) params.loginHint = loginHint;
|
|
642
|
+
let prompt;
|
|
643
|
+
if (typeof request.getQuery("prompt") === "string") prompt = request.getQuery("prompt");
|
|
644
|
+
else prompt = opt.register ? "create" : opt.authParams.prompt;
|
|
645
|
+
if (prompt) params.prompt = prompt;
|
|
646
|
+
/* v8 ignore next -- @preserve */
|
|
647
|
+
if (!params.scopes || params.scopes.length < 0) throw new MonoCloudValidationError$1("Scopes are required for signing in");
|
|
648
|
+
const monoCloudState = {
|
|
649
|
+
returnUrl,
|
|
650
|
+
state,
|
|
651
|
+
nonce,
|
|
652
|
+
codeVerifier,
|
|
653
|
+
maxAge: opt.authParams.maxAge,
|
|
654
|
+
appState: JSON.stringify(appState),
|
|
655
|
+
resource: this.options.defaultAuthParams.resource,
|
|
656
|
+
scopes: params.scopes
|
|
657
|
+
};
|
|
658
|
+
if (this.options.usePar) {
|
|
659
|
+
const { request_uri } = await this.oidcClient.pushedAuthorizationRequest(params);
|
|
660
|
+
params = { requestUri: request_uri };
|
|
661
|
+
}
|
|
662
|
+
const authUrl = await this.oidcClient.authorizationUrl(params);
|
|
663
|
+
await this.stateService.setState(response, monoCloudState, params.responseMode === "form_post" ? "none" : void 0);
|
|
664
|
+
response.redirect(authUrl, 302);
|
|
665
|
+
} catch (error) {
|
|
666
|
+
if (typeof (signInOptions === null || signInOptions === void 0 ? void 0 : signInOptions.onError) === "function") return signInOptions.onError(error);
|
|
667
|
+
else this.handleCatchAll(error, response);
|
|
668
|
+
}
|
|
669
|
+
return response.done();
|
|
670
|
+
}
|
|
671
|
+
/**
|
|
672
|
+
* Handles the OpenID callback after the user authenticates with MonoCloud.
|
|
673
|
+
*
|
|
674
|
+
* Processes the authorization code, validates the state and nonce, exchanges the code for tokens,
|
|
675
|
+
* initializes the user session, and performs the final redirect to the application's return URL.
|
|
676
|
+
*
|
|
677
|
+
* @param request - MonoCloud request object.
|
|
678
|
+
* @param response - MonoCloud response object.
|
|
679
|
+
* @param callbackOptions - Optional configuration for the callback handler.
|
|
680
|
+
* @returns A promise that resolves when the callback processing and redirection are complete.
|
|
681
|
+
*
|
|
682
|
+
* @throws {@link MonoCloudValidationError} If the state is mismatched or tokens are invalid.
|
|
683
|
+
*/
|
|
684
|
+
async callback(request, response, callbackOptions) {
|
|
685
|
+
this.debug("Starting callback handler");
|
|
686
|
+
try {
|
|
687
|
+
this.validateOptions();
|
|
688
|
+
const { method, url, body } = await request.getRawRequest();
|
|
689
|
+
if (method.toLowerCase() !== "get" && method.toLowerCase() !== "post") {
|
|
690
|
+
response.methodNotAllowed();
|
|
691
|
+
return response.done();
|
|
692
|
+
}
|
|
693
|
+
if (callbackOptions) {
|
|
694
|
+
const { error } = callbackOptionsSchema.validate(callbackOptions, { abortEarly: true });
|
|
695
|
+
if (error) throw new MonoCloudValidationError$1(error.details[0].message);
|
|
696
|
+
}
|
|
697
|
+
const monoCloudState = await this.stateService.getState(request, response);
|
|
698
|
+
if (!monoCloudState) throw new MonoCloudValidationError$1("Invalid Authentication State");
|
|
699
|
+
let fullUrl = url;
|
|
700
|
+
if (!isAbsoluteUrl(url)) fullUrl = `${this.options.appUrl}${ensureLeadingSlash(url)}`;
|
|
701
|
+
const callbackParams = parseCallbackParams(method.toLowerCase() === "post" ? new URLSearchParams(body) : new URL(fullUrl).searchParams);
|
|
702
|
+
if (callbackParams.state !== monoCloudState.state) throw new MonoCloudValidationError$1("Invalid state");
|
|
703
|
+
const redirectUri = (callbackOptions === null || callbackOptions === void 0 ? void 0 : callbackOptions.redirectUri) ?? `${this.options.appUrl}${ensureLeadingSlash(this.options.routes.callback)}`;
|
|
704
|
+
if (!callbackParams.code) throw new MonoCloudValidationError$1("Authorization code not found in callback params");
|
|
705
|
+
const appState = JSON.parse(monoCloudState.appState);
|
|
706
|
+
const session = await this.oidcClient.authenticate(callbackParams.code, redirectUri, monoCloudState.scopes, monoCloudState.resource, {
|
|
707
|
+
codeVerifier: monoCloudState.codeVerifier,
|
|
708
|
+
validateIdToken: true,
|
|
709
|
+
idTokenClockSkew: this.options.clockSkew,
|
|
710
|
+
idTokenNonce: monoCloudState.nonce,
|
|
711
|
+
idTokenMaxAge: monoCloudState.maxAge,
|
|
712
|
+
idTokenClockTolerance: 5,
|
|
713
|
+
fetchUserInfo: (callbackOptions === null || callbackOptions === void 0 ? void 0 : callbackOptions.userInfo) ?? this.options.userInfo,
|
|
714
|
+
filteredIdTokenClaims: this.options.filteredIdTokenClaims,
|
|
715
|
+
onSessionCreating: async (s, i, u) => {
|
|
716
|
+
var _this$options$onSessi, _this$options;
|
|
717
|
+
return await ((_this$options$onSessi = (_this$options = this.options).onSessionCreating) === null || _this$options$onSessi === void 0 ? void 0 : _this$options$onSessi.call(_this$options, s, i, u, appState));
|
|
718
|
+
}
|
|
719
|
+
});
|
|
720
|
+
await this.sessionService.setSession(request, response, session);
|
|
721
|
+
if (!monoCloudState.returnUrl) {
|
|
722
|
+
response.redirect(this.options.appUrl);
|
|
723
|
+
return response.done();
|
|
724
|
+
}
|
|
725
|
+
try {
|
|
726
|
+
const decodedUrl = decodeURIComponent(monoCloudState.returnUrl);
|
|
727
|
+
if (!isAbsoluteUrl(decodedUrl)) {
|
|
728
|
+
response.redirect(`${this.options.appUrl}${ensureLeadingSlash(decodedUrl)}`);
|
|
729
|
+
return response.done();
|
|
730
|
+
}
|
|
731
|
+
if (isSameHost(this.options.appUrl, decodedUrl)) {
|
|
732
|
+
response.redirect(decodedUrl);
|
|
733
|
+
return response.done();
|
|
734
|
+
}
|
|
735
|
+
} catch {}
|
|
736
|
+
/* c8 ignore stop */
|
|
737
|
+
response.redirect(this.options.appUrl);
|
|
738
|
+
} catch (error) {
|
|
739
|
+
if (typeof (callbackOptions === null || callbackOptions === void 0 ? void 0 : callbackOptions.onError) === "function") return callbackOptions.onError(error);
|
|
740
|
+
else this.handleCatchAll(error, response);
|
|
741
|
+
}
|
|
742
|
+
return response.done();
|
|
743
|
+
}
|
|
744
|
+
/**
|
|
745
|
+
* Retrieves user information, optionally refetching fresh data from the UserInfo endpoint.
|
|
746
|
+
*
|
|
747
|
+
* @param request - MonoCloud request object.
|
|
748
|
+
* @param response - MonoCloud response object.
|
|
749
|
+
* @param userinfoOptions - Configuration to control refetching and error handling.
|
|
750
|
+
* @returns A promise that resolves with the user information sent as a JSON response.
|
|
751
|
+
*
|
|
752
|
+
* @remarks
|
|
753
|
+
* If `refresh` is true, the session is updated with fresh claims from the identity provider.
|
|
754
|
+
*/
|
|
755
|
+
async userInfo(request, response, userinfoOptions) {
|
|
756
|
+
this.debug("Starting userinfo handler");
|
|
757
|
+
try {
|
|
758
|
+
var _this$options$onSessi2;
|
|
759
|
+
this.validateOptions();
|
|
760
|
+
const { method } = await request.getRawRequest();
|
|
761
|
+
if (method.toLowerCase() !== "get") {
|
|
762
|
+
response.methodNotAllowed();
|
|
763
|
+
return response.done();
|
|
764
|
+
}
|
|
765
|
+
if (userinfoOptions) {
|
|
766
|
+
const { error } = userInfoOptionsSchema.validate(userinfoOptions, { abortEarly: true });
|
|
767
|
+
if (error) throw new MonoCloudValidationError$1(error.details[0].message);
|
|
768
|
+
}
|
|
769
|
+
const refetchUserInfo = (userinfoOptions === null || userinfoOptions === void 0 ? void 0 : userinfoOptions.refresh) ?? this.options.refetchUserInfo;
|
|
770
|
+
const session = await this.sessionService.getSession(request, response, !refetchUserInfo);
|
|
771
|
+
if (!session) {
|
|
772
|
+
response.setNoCache();
|
|
773
|
+
response.noContent();
|
|
774
|
+
return response.done();
|
|
775
|
+
}
|
|
776
|
+
const defaultToken = findToken(session.accessTokens, this.options.defaultAuthParams.resource, session.authorizedScopes);
|
|
777
|
+
if (!refetchUserInfo || !defaultToken) {
|
|
778
|
+
response.sendJson(session.user);
|
|
779
|
+
return response.done();
|
|
780
|
+
}
|
|
781
|
+
const newSession = await this.oidcClient.refetchUserInfo(defaultToken, session, { onSessionCreating: (_this$options$onSessi2 = this.options.onSessionCreating) === null || _this$options$onSessi2 === void 0 ? void 0 : _this$options$onSessi2.bind(this) });
|
|
782
|
+
if (!await this.sessionService.updateSession(request, response, newSession)) {
|
|
783
|
+
response.setNoCache();
|
|
784
|
+
response.noContent();
|
|
785
|
+
return response.done();
|
|
786
|
+
}
|
|
787
|
+
response.sendJson(session.user);
|
|
788
|
+
} catch (error) {
|
|
789
|
+
if (typeof (userinfoOptions === null || userinfoOptions === void 0 ? void 0 : userinfoOptions.onError) === "function") return userinfoOptions.onError(error);
|
|
790
|
+
else this.handleCatchAll(error, response);
|
|
791
|
+
}
|
|
792
|
+
return response.done();
|
|
793
|
+
}
|
|
794
|
+
/**
|
|
795
|
+
* Initiates the sign-out flow, destroying the local session and optionally performing federated sign-out.
|
|
796
|
+
*
|
|
797
|
+
* @param request - MonoCloud request object.
|
|
798
|
+
* @param response - MonoCloud response object.
|
|
799
|
+
* @param signOutOptions - Configuration for post-logout behavior and federated sign-out.
|
|
800
|
+
*
|
|
801
|
+
* @returns A promise that resolves when the sign-out redirection is initiated.
|
|
802
|
+
*/
|
|
803
|
+
async signOut(request, response, signOutOptions) {
|
|
804
|
+
this.debug("Starting sign-out handler");
|
|
805
|
+
try {
|
|
806
|
+
this.validateOptions();
|
|
807
|
+
const { method } = await request.getRawRequest();
|
|
808
|
+
if (method.toLowerCase() !== "get") {
|
|
809
|
+
response.methodNotAllowed();
|
|
810
|
+
return response.done();
|
|
811
|
+
}
|
|
812
|
+
if (signOutOptions) {
|
|
813
|
+
const { error } = signOutOptionsSchema.validate(signOutOptions, { abortEarly: true });
|
|
814
|
+
if (error) throw new MonoCloudValidationError$1(error.details[0].message);
|
|
815
|
+
}
|
|
816
|
+
let returnUrl = this.options.postLogoutRedirectUri ?? (signOutOptions === null || signOutOptions === void 0 ? void 0 : signOutOptions.postLogoutRedirectUri) ?? this.options.appUrl;
|
|
817
|
+
const retUrl = request.getQuery("post_logout_url");
|
|
818
|
+
if (typeof retUrl === "string" && retUrl) {
|
|
819
|
+
const { error } = signOutOptionsSchema.validate({ postLogoutRedirectUri: retUrl });
|
|
820
|
+
if (!error) returnUrl = retUrl;
|
|
821
|
+
}
|
|
822
|
+
if (!isAbsoluteUrl(returnUrl)) returnUrl = `${this.options.appUrl}${ensureLeadingSlash(returnUrl)}`;
|
|
823
|
+
const session = await this.sessionService.getSession(request, response, false);
|
|
824
|
+
if (!session) {
|
|
825
|
+
response.redirect(returnUrl);
|
|
826
|
+
return response.done();
|
|
827
|
+
}
|
|
828
|
+
await this.sessionService.removeSession(request, response);
|
|
829
|
+
if (!((signOutOptions === null || signOutOptions === void 0 ? void 0 : signOutOptions.federatedSignOut) ?? this.options.federatedSignOut)) {
|
|
830
|
+
response.redirect(returnUrl);
|
|
831
|
+
return response.done();
|
|
832
|
+
}
|
|
833
|
+
const url = await this.oidcClient.endSessionUrl({
|
|
834
|
+
idToken: session.idToken,
|
|
835
|
+
postLogoutRedirectUri: returnUrl,
|
|
836
|
+
state: signOutOptions === null || signOutOptions === void 0 ? void 0 : signOutOptions.state
|
|
837
|
+
});
|
|
838
|
+
response.redirect(url);
|
|
839
|
+
} catch (error) {
|
|
840
|
+
if (typeof (signOutOptions === null || signOutOptions === void 0 ? void 0 : signOutOptions.onError) === "function") return signOutOptions.onError(error);
|
|
841
|
+
else this.handleCatchAll(error, response);
|
|
842
|
+
}
|
|
843
|
+
return response.done();
|
|
844
|
+
}
|
|
845
|
+
/**
|
|
846
|
+
* Handles Back-Channel Logout notifications from the identity provider.
|
|
847
|
+
*
|
|
848
|
+
* Validates the Logout Token and triggers the `onBackChannelLogout` callback defined in options.
|
|
849
|
+
*
|
|
850
|
+
* @param request - MonoCloud request object.
|
|
851
|
+
* @param response - MonoCloud response object.
|
|
852
|
+
*
|
|
853
|
+
* @returns A promise that resolves when the logout notification has been processed.
|
|
854
|
+
*
|
|
855
|
+
* @throws {@link MonoCloudValidationError} If the logout token is missing or invalid.
|
|
856
|
+
*/
|
|
857
|
+
async backChannelLogout(request, response) {
|
|
858
|
+
this.debug("Starting back-channel logout handler");
|
|
859
|
+
try {
|
|
860
|
+
this.validateOptions();
|
|
861
|
+
response.setNoCache();
|
|
862
|
+
if (!this.options.onBackChannelLogout) {
|
|
863
|
+
response.notFound();
|
|
864
|
+
return response.done();
|
|
865
|
+
}
|
|
866
|
+
const { method, body } = await request.getRawRequest();
|
|
867
|
+
if (method.toLowerCase() !== "post") {
|
|
868
|
+
response.methodNotAllowed();
|
|
869
|
+
return response.done();
|
|
870
|
+
}
|
|
871
|
+
const logoutToken = new URLSearchParams(body).get("logout_token");
|
|
872
|
+
if (!logoutToken) throw new MonoCloudValidationError$1("Missing Logout Token");
|
|
873
|
+
const metadata = await this.oidcClient.getMetadata();
|
|
874
|
+
const { sid, sub } = await this.verifyLogoutToken(logoutToken, metadata);
|
|
875
|
+
await this.options.onBackChannelLogout(sub, sid);
|
|
876
|
+
response.noContent();
|
|
877
|
+
} catch (error) {
|
|
878
|
+
this.handleCatchAll(error, response);
|
|
879
|
+
}
|
|
880
|
+
return response.done();
|
|
881
|
+
}
|
|
882
|
+
/**
|
|
883
|
+
* Checks if the current request has an active and authenticated session.
|
|
884
|
+
*
|
|
885
|
+
* @param request - MonoCloud cookie request object.
|
|
886
|
+
* @param response - MonoCloud cookie response object.
|
|
887
|
+
*
|
|
888
|
+
* @returns `true` if a valid session with user data exists, `false` otherwise.
|
|
889
|
+
*
|
|
890
|
+
*/
|
|
891
|
+
async isAuthenticated(request, response) {
|
|
892
|
+
const session = await this.sessionService.getSession(request, response);
|
|
893
|
+
return !!(session === null || session === void 0 ? void 0 : session.user);
|
|
894
|
+
}
|
|
895
|
+
/**
|
|
896
|
+
* Checks if the current session user belongs to the specified groups.
|
|
897
|
+
*
|
|
898
|
+
* @param request - MonoCloud cookie request object.
|
|
899
|
+
* @param response - MonoCloud cookie response object.
|
|
900
|
+
* @param groups - List of group names or IDs to check.
|
|
901
|
+
* @param groupsClaim - Optional claim name that holds groups. Defaults to "groups".
|
|
902
|
+
* @param matchAll - If `true`, requires membership in all groups; otherwise any one group is sufficient.
|
|
903
|
+
*
|
|
904
|
+
* @returns `true` if the user satisfies the group condition, `false` otherwise.
|
|
905
|
+
*/
|
|
906
|
+
async isUserInGroup(request, response, groups, groupsClaim, matchAll) {
|
|
907
|
+
const session = await this.sessionService.getSession(request, response);
|
|
908
|
+
if (!(session === null || session === void 0 ? void 0 : session.user)) return false;
|
|
909
|
+
return isUserInGroup(session.user, groups, groupsClaim, matchAll);
|
|
910
|
+
}
|
|
911
|
+
/**
|
|
912
|
+
* Retrieves the current user's session data.
|
|
913
|
+
*
|
|
914
|
+
* @param request - MonoCloud cookie request object.
|
|
915
|
+
* @param response - MonoCloud cookie response object.
|
|
916
|
+
*
|
|
917
|
+
* @returns Session or `undefined`.
|
|
918
|
+
*/
|
|
919
|
+
getSession(request, response) {
|
|
920
|
+
return this.sessionService.getSession(request, response);
|
|
921
|
+
}
|
|
922
|
+
/**
|
|
923
|
+
* Updates the current user's session with new data.
|
|
924
|
+
*
|
|
925
|
+
* @param request - MonoCloud cookie request object.
|
|
926
|
+
* @param response - MonoCloud cookie response object.
|
|
927
|
+
* @param session - The updated session object to persist.
|
|
928
|
+
*/
|
|
929
|
+
async updateSession(request, response, session) {
|
|
930
|
+
await this.sessionService.updateSession(request, response, session);
|
|
931
|
+
}
|
|
932
|
+
/**
|
|
933
|
+
* Returns a copy of the current client configuration options.
|
|
934
|
+
*
|
|
935
|
+
* @returns A copy of the initialized configuration.
|
|
936
|
+
*/
|
|
937
|
+
getOptions() {
|
|
938
|
+
return { ...this.options };
|
|
939
|
+
}
|
|
940
|
+
/**
|
|
941
|
+
* Destroys the local user session.
|
|
942
|
+
*
|
|
943
|
+
* @param request - MonoCloud cookie request object.
|
|
944
|
+
* @param response - MonoCloud cookie response object.
|
|
945
|
+
*
|
|
946
|
+
* @remarks
|
|
947
|
+
* This does not perform federated sign-out. For identity provider sign-out, use `signOut` handler.
|
|
948
|
+
*/
|
|
949
|
+
destroySession(request, response) {
|
|
950
|
+
return this.sessionService.removeSession(request, response);
|
|
951
|
+
}
|
|
952
|
+
/**
|
|
953
|
+
* Retrieves active tokens (Access, ID, Refresh), performing a refresh if they are expired or missing.
|
|
954
|
+
*
|
|
955
|
+
* @param request - MonoCloud cookie request object.
|
|
956
|
+
* @param response - MonoCloud cookie response object.
|
|
957
|
+
* @param options - Configuration for token retrieval (force refresh, specific scopes/resources).
|
|
958
|
+
*
|
|
959
|
+
* @returns Fetched tokens
|
|
960
|
+
*
|
|
961
|
+
* @throws {@link MonoCloudValidationError} If the session does not exist or tokens cannot be found/refreshed.
|
|
962
|
+
*/
|
|
963
|
+
async getTokens(request, response, options) {
|
|
964
|
+
if (options) {
|
|
965
|
+
const { error } = getTokensOptionsSchema.validate(options, { abortEarly: true });
|
|
966
|
+
if (error) throw new MonoCloudValidationError$1(error.details[0].message);
|
|
967
|
+
}
|
|
968
|
+
const session = await this.sessionService.getSession(request, response);
|
|
969
|
+
if (!session) throw new MonoCloudValidationError$1("Session does not exist");
|
|
970
|
+
let scopes = options === null || options === void 0 ? void 0 : options.scopes;
|
|
971
|
+
const resource = (options === null || options === void 0 ? void 0 : options.resource) ?? this.options.defaultAuthParams.resource;
|
|
972
|
+
if (isPresent(options === null || options === void 0 ? void 0 : options.resource)) {
|
|
973
|
+
if (!isPresent(scopes)) {
|
|
974
|
+
var _this$options$resourc3;
|
|
975
|
+
if (!((_this$options$resourc3 = this.options.resources) === null || _this$options$resourc3 === void 0 ? void 0 : _this$options$resourc3.find((x) => setsEqual(parseSpaceSeparatedSet(x.resource), parseSpaceSeparatedSet(resource)) && !x.scopes))) {
|
|
976
|
+
var _this$options$resourc4;
|
|
977
|
+
scopes = (_this$options$resourc4 = this.options.resources) === null || _this$options$resourc4 === void 0 || (_this$options$resourc4 = _this$options$resourc4.find((x) => setsEqual(parseSpaceSeparatedSet(x.resource), parseSpaceSeparatedSet(resource)))) === null || _this$options$resourc4 === void 0 ? void 0 : _this$options$resourc4.scopes;
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
const findTokenScopes = !isPresent(options === null || options === void 0 ? void 0 : options.resource) && !isPresent(scopes) ? session.authorizedScopes : scopes;
|
|
982
|
+
let token = findToken(session.accessTokens, resource, findTokenScopes);
|
|
983
|
+
const tokenExpired = !!token && token.accessTokenExpiration - 30 < now();
|
|
984
|
+
let { idToken } = session;
|
|
985
|
+
let { refreshToken } = session;
|
|
986
|
+
if ((options === null || options === void 0 ? void 0 : options.forceRefresh) || !token || tokenExpired) {
|
|
987
|
+
var _this$options$onSessi3;
|
|
988
|
+
const updatedSession = await this.oidcClient.refreshSession(session, {
|
|
989
|
+
fetchUserInfo: (options === null || options === void 0 ? void 0 : options.refetchUserInfo) ?? this.options.refetchUserInfo,
|
|
990
|
+
validateIdToken: true,
|
|
991
|
+
idTokenClockSkew: this.options.clockSkew,
|
|
992
|
+
idTokenClockTolerance: 5,
|
|
993
|
+
refreshGrantOptions: {
|
|
994
|
+
resource,
|
|
995
|
+
scopes
|
|
996
|
+
},
|
|
997
|
+
filteredIdTokenClaims: this.options.filteredIdTokenClaims,
|
|
998
|
+
onSessionCreating: (_this$options$onSessi3 = this.options.onSessionCreating) === null || _this$options$onSessi3 === void 0 ? void 0 : _this$options$onSessi3.bind(this)
|
|
999
|
+
});
|
|
1000
|
+
await this.sessionService.updateSession(request, response, updatedSession);
|
|
1001
|
+
token = findToken(updatedSession === null || updatedSession === void 0 ? void 0 : updatedSession.accessTokens, resource, findTokenScopes);
|
|
1002
|
+
idToken = updatedSession.idToken;
|
|
1003
|
+
refreshToken = updatedSession.refreshToken;
|
|
1004
|
+
}
|
|
1005
|
+
/* v8 ignore next -- @preserve */
|
|
1006
|
+
if (!token) throw new MonoCloudValidationError$1("Access token not found");
|
|
1007
|
+
return {
|
|
1008
|
+
...token,
|
|
1009
|
+
idToken,
|
|
1010
|
+
refreshToken,
|
|
1011
|
+
isExpired: token.accessTokenExpiration - 30 < now()
|
|
1012
|
+
};
|
|
1013
|
+
}
|
|
1014
|
+
async verifyLogoutToken(token, metadata) {
|
|
1015
|
+
const { payload } = await jwtVerify(token, createRemoteJWKSet(new URL(metadata.jwks_uri)), {
|
|
1016
|
+
issuer: metadata.issuer,
|
|
1017
|
+
audience: this.options.clientId,
|
|
1018
|
+
algorithms: [this.options.idTokenSigningAlg],
|
|
1019
|
+
requiredClaims: ["iat"]
|
|
1020
|
+
});
|
|
1021
|
+
if (!payload.sid && !payload.sub || payload.nonce || !payload.events || typeof payload.events !== "object") throw new MonoCloudValidationError$1("Invalid logout token");
|
|
1022
|
+
const event = payload.events["http://schemas.openid.net/event/backchannel-logout"];
|
|
1023
|
+
if (!event || typeof event !== "object") throw new MonoCloudValidationError$1("Invalid logout token");
|
|
1024
|
+
return payload;
|
|
1025
|
+
}
|
|
1026
|
+
handleCatchAll(error, res) {
|
|
1027
|
+
console.error(error);
|
|
1028
|
+
res.internalServerError();
|
|
1029
|
+
}
|
|
1030
|
+
validateOptions() {
|
|
1031
|
+
if (!this.optionsValidated) {
|
|
1032
|
+
this.optionsValidated = true;
|
|
1033
|
+
getOptions(this.options);
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
};
|
|
1037
|
+
|
|
1038
|
+
//#endregion
|
|
1039
|
+
export { MonoCloudAuthBaseError, MonoCloudCoreClient, MonoCloudHttpError, MonoCloudOPError, MonoCloudOidcClient, MonoCloudTokenError, MonoCloudValidationError };
|
|
1040
|
+
//# sourceMappingURL=index.mjs.map
|