@go-mondo/nextjs-auth 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +462 -0
- package/dist/access-token-UIlXwi3X.d.cts +27 -0
- package/dist/access-token-UIlXwi3X.d.ts +27 -0
- package/dist/client.cjs +1324 -0
- package/dist/client.cjs.map +1 -0
- package/dist/client.d.cts +201 -0
- package/dist/client.d.ts +201 -0
- package/dist/client.js +1301 -0
- package/dist/client.js.map +1 -0
- package/dist/config.cjs +4 -0
- package/dist/config.cjs.map +1 -0
- package/dist/config.d.cts +90 -0
- package/dist/config.d.ts +90 -0
- package/dist/config.js +3 -0
- package/dist/config.js.map +1 -0
- package/dist/errors.cjs +189 -0
- package/dist/errors.cjs.map +1 -0
- package/dist/errors.d.cts +178 -0
- package/dist/errors.d.ts +178 -0
- package/dist/errors.js +178 -0
- package/dist/errors.js.map +1 -0
- package/dist/hooks.cjs +236 -0
- package/dist/hooks.cjs.map +1 -0
- package/dist/hooks.d.cts +146 -0
- package/dist/hooks.d.ts +146 -0
- package/dist/hooks.js +230 -0
- package/dist/hooks.js.map +1 -0
- package/dist/oauth.cjs +10 -0
- package/dist/oauth.cjs.map +1 -0
- package/dist/oauth.d.cts +55 -0
- package/dist/oauth.d.ts +55 -0
- package/dist/oauth.js +8 -0
- package/dist/oauth.js.map +1 -0
- package/dist/session.cjs +45 -0
- package/dist/session.cjs.map +1 -0
- package/dist/session.d.cts +71 -0
- package/dist/session.d.ts +71 -0
- package/dist/session.js +43 -0
- package/dist/session.js.map +1 -0
- package/dist/types-CbrOw4QQ.d.cts +108 -0
- package/dist/types-CbrOw4QQ.d.ts +108 -0
- package/package.json +146 -0
package/dist/client.cjs
ADDED
|
@@ -0,0 +1,1324 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var server_js = require('next/server.js');
|
|
4
|
+
var ironSession = require('iron-session');
|
|
5
|
+
var cookie = require('cookie');
|
|
6
|
+
var headers_js = require('next/headers.js');
|
|
7
|
+
var oidc = require('openid-client');
|
|
8
|
+
var zod = require('zod');
|
|
9
|
+
|
|
10
|
+
function _interopNamespace(e) {
|
|
11
|
+
if (e && e.__esModule) return e;
|
|
12
|
+
var n = Object.create(null);
|
|
13
|
+
if (e) {
|
|
14
|
+
Object.keys(e).forEach(function (k) {
|
|
15
|
+
if (k !== 'default') {
|
|
16
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
17
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
18
|
+
enumerable: true,
|
|
19
|
+
get: function () { return e[k]; }
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
n.default = e;
|
|
25
|
+
return Object.freeze(n);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
var oidc__namespace = /*#__PURE__*/_interopNamespace(oidc);
|
|
29
|
+
|
|
30
|
+
// src/client.ts
|
|
31
|
+
|
|
32
|
+
// src/errors/auth.ts
|
|
33
|
+
function appendCause(errorMessage, cause) {
|
|
34
|
+
if (!cause) return errorMessage;
|
|
35
|
+
const separator = errorMessage.endsWith(".") ? "" : ".";
|
|
36
|
+
return `${errorMessage}${separator} CAUSE: ${cause.message}`;
|
|
37
|
+
}
|
|
38
|
+
var AuthError = class extends Error {
|
|
39
|
+
/**
|
|
40
|
+
* A machine-readable error code that remains stable within a major version of the SDK. You
|
|
41
|
+
* should rely on this error code to handle errors. In contrast, the error message is not part of
|
|
42
|
+
* the API and can change anytime. Do **not** parse or otherwise rely on the error message to
|
|
43
|
+
* handle errors.
|
|
44
|
+
*/
|
|
45
|
+
code;
|
|
46
|
+
/**
|
|
47
|
+
* The error class name.
|
|
48
|
+
*/
|
|
49
|
+
name;
|
|
50
|
+
/**
|
|
51
|
+
* The underlying error, if any.
|
|
52
|
+
*
|
|
53
|
+
* **IMPORTANT** When this error is from the Identity Provider ({@link IdentityProviderError}) it can contain user
|
|
54
|
+
* input and is only escaped using basic escaping for putting untrusted data directly into the HTML body.
|
|
55
|
+
*
|
|
56
|
+
* You should **not** render this error without using a templating engine that will properly escape it for other
|
|
57
|
+
* HTML contexts first.
|
|
58
|
+
*/
|
|
59
|
+
cause;
|
|
60
|
+
/**
|
|
61
|
+
* The HTTP status code, if any.
|
|
62
|
+
*/
|
|
63
|
+
status;
|
|
64
|
+
/**
|
|
65
|
+
* @param options - Error metadata used by SDK-specific subclasses.
|
|
66
|
+
*/
|
|
67
|
+
constructor(options) {
|
|
68
|
+
super(appendCause(options.message, options.cause));
|
|
69
|
+
this.code = options.code;
|
|
70
|
+
this.name = options.name;
|
|
71
|
+
this.cause = options.cause;
|
|
72
|
+
this.status = options.status;
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
// src/errors/access-token.ts
|
|
77
|
+
var AccessTokenError = class _AccessTokenError extends AuthError {
|
|
78
|
+
/**
|
|
79
|
+
* @param code - Stable machine-readable error code.
|
|
80
|
+
* @param message - Human-readable diagnostic message.
|
|
81
|
+
* @param cause - Optional lower-level error.
|
|
82
|
+
*/
|
|
83
|
+
constructor(code, message, cause) {
|
|
84
|
+
super({ code, message, name: "AccessTokenError", cause });
|
|
85
|
+
Error.captureStackTrace(this, this.constructor);
|
|
86
|
+
Object.setPrototypeOf(this, _AccessTokenError.prototype);
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
// src/crypto/secrets.ts
|
|
91
|
+
function getSecrets(config) {
|
|
92
|
+
const secretsArray = Array.isArray(config.secret) ? config.secret : [config.secret];
|
|
93
|
+
const secrets = {};
|
|
94
|
+
secretsArray.forEach((secret, index) => {
|
|
95
|
+
secrets[secretsArray.length - index] = secret;
|
|
96
|
+
});
|
|
97
|
+
return secrets;
|
|
98
|
+
}
|
|
99
|
+
async function cookieFactory(req, res) {
|
|
100
|
+
if (req) {
|
|
101
|
+
return new HttpCookieStore(req, res);
|
|
102
|
+
}
|
|
103
|
+
return headers_js.cookies();
|
|
104
|
+
}
|
|
105
|
+
var HttpCookieStore = class {
|
|
106
|
+
constructor(req, res) {
|
|
107
|
+
this.req = req;
|
|
108
|
+
this.res = res;
|
|
109
|
+
}
|
|
110
|
+
req;
|
|
111
|
+
res;
|
|
112
|
+
get(cookieName) {
|
|
113
|
+
const value = cookie.parse(this.req.headers.get("cookie") ?? "")[cookieName];
|
|
114
|
+
return value === void 0 ? void 0 : { name: cookieName, value };
|
|
115
|
+
}
|
|
116
|
+
set(nameOrOptions, value, cookie) {
|
|
117
|
+
if (typeof nameOrOptions === "string") {
|
|
118
|
+
return this.setCookie(nameOrOptions, value, cookie);
|
|
119
|
+
}
|
|
120
|
+
return this.setCookie(
|
|
121
|
+
nameOrOptions.name,
|
|
122
|
+
nameOrOptions.value,
|
|
123
|
+
nameOrOptions
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
setCookie(name, value, cookie$1) {
|
|
127
|
+
if (!this.res) {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
const cookieValue = cookie.serialize(name, value, cookie$1);
|
|
131
|
+
this.res.headers.append("set-cookie", cookieValue);
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
// src/session/model.ts
|
|
136
|
+
var Session = class {
|
|
137
|
+
/**
|
|
138
|
+
* The authenticated user (claims from the `id_token`)
|
|
139
|
+
*/
|
|
140
|
+
user;
|
|
141
|
+
/**
|
|
142
|
+
* A timestamp when authentication / session occurred
|
|
143
|
+
*/
|
|
144
|
+
issuedAt;
|
|
145
|
+
/**
|
|
146
|
+
* A timestamp when authentication / session was last updated (touched)
|
|
147
|
+
*/
|
|
148
|
+
updatedAt;
|
|
149
|
+
/**
|
|
150
|
+
* A timestamp when the authentication / session is set to expire
|
|
151
|
+
*/
|
|
152
|
+
expiresAt;
|
|
153
|
+
/**
|
|
154
|
+
* OAuth access-token state stored separately from the base session payload.
|
|
155
|
+
*/
|
|
156
|
+
authorization;
|
|
157
|
+
/**
|
|
158
|
+
* OIDC authentication token state stored separately from the base session
|
|
159
|
+
* payload.
|
|
160
|
+
*/
|
|
161
|
+
authentication;
|
|
162
|
+
/**
|
|
163
|
+
* Creates a normalized session object from sealed cookie payloads.
|
|
164
|
+
*/
|
|
165
|
+
constructor(props) {
|
|
166
|
+
this.user = props.user;
|
|
167
|
+
this.issuedAt = props.issuedAt;
|
|
168
|
+
this.updatedAt = props.updatedAt;
|
|
169
|
+
this.expiresAt = props.expiresAt;
|
|
170
|
+
this.authentication = props.authentication;
|
|
171
|
+
this.authorization = props.authorization;
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
function fromTokenEndpointResponse(tokenEndpointResponse) {
|
|
175
|
+
const { iat, exp, aud, iss, nonce, ...user } = decodeJwt(
|
|
176
|
+
tokenEndpointResponse.id_token
|
|
177
|
+
);
|
|
178
|
+
const {
|
|
179
|
+
id_token,
|
|
180
|
+
access_token,
|
|
181
|
+
scope,
|
|
182
|
+
expires_in,
|
|
183
|
+
expires_at,
|
|
184
|
+
refresh_token,
|
|
185
|
+
token_type,
|
|
186
|
+
...remainder
|
|
187
|
+
} = tokenEndpointResponse;
|
|
188
|
+
const authorization = access_token ? {
|
|
189
|
+
accessToken: access_token,
|
|
190
|
+
scope,
|
|
191
|
+
expiresAt: Math.floor(Date.now() / 1e3) + Number(expires_in),
|
|
192
|
+
refreshToken: refresh_token,
|
|
193
|
+
type: token_type
|
|
194
|
+
} : void 0;
|
|
195
|
+
const authentication = id_token ? {
|
|
196
|
+
idToken: id_token
|
|
197
|
+
} : void 0;
|
|
198
|
+
return Object.assign(
|
|
199
|
+
new Session({
|
|
200
|
+
user,
|
|
201
|
+
issuedAt: iat,
|
|
202
|
+
updatedAt: iat,
|
|
203
|
+
expiresAt: exp,
|
|
204
|
+
authorization,
|
|
205
|
+
authentication
|
|
206
|
+
}),
|
|
207
|
+
remainder
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
function decodeJwt(jwt) {
|
|
211
|
+
const [, payload] = jwt.split(".");
|
|
212
|
+
if (!payload) {
|
|
213
|
+
throw new TypeError("Invalid JWT payload.");
|
|
214
|
+
}
|
|
215
|
+
const normalized = payload.replace(/-/g, "+").replace(/_/g, "/");
|
|
216
|
+
const padded = normalized.padEnd(
|
|
217
|
+
normalized.length + (4 - normalized.length % 4) % 4,
|
|
218
|
+
"="
|
|
219
|
+
);
|
|
220
|
+
const decoded = typeof atob === "function" ? atob(padded) : Buffer.from(padded, "base64").toString("binary");
|
|
221
|
+
const json = decodeURIComponent(
|
|
222
|
+
Array.from(
|
|
223
|
+
decoded,
|
|
224
|
+
(char) => `%${char.charCodeAt(0).toString(16).padStart(2, "0")}`
|
|
225
|
+
).join("")
|
|
226
|
+
);
|
|
227
|
+
return JSON.parse(json);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// src/session/assert.ts
|
|
231
|
+
var assertBoolean = (bool2, msg) => {
|
|
232
|
+
if (!bool2) {
|
|
233
|
+
throw new Error(msg);
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
// src/session/utils.ts
|
|
238
|
+
var epoch = () => Date.now() / 1e3 | 0;
|
|
239
|
+
|
|
240
|
+
// src/session/stores/abstract-store.ts
|
|
241
|
+
var AbstractSessionStore = class {
|
|
242
|
+
constructor(config) {
|
|
243
|
+
this.config = config;
|
|
244
|
+
}
|
|
245
|
+
config;
|
|
246
|
+
/**
|
|
247
|
+
* Reads and validates the current session.
|
|
248
|
+
*
|
|
249
|
+
* @returns The session, or `undefined` when missing, expired, or malformed.
|
|
250
|
+
*/
|
|
251
|
+
async get() {
|
|
252
|
+
const { absoluteDuration, idleDuration } = this.config.session;
|
|
253
|
+
const now = epoch();
|
|
254
|
+
try {
|
|
255
|
+
const session = await this._get();
|
|
256
|
+
if (session) {
|
|
257
|
+
assertBoolean(
|
|
258
|
+
session.expiresAt > now,
|
|
259
|
+
"it is expired based on the effective session expiry"
|
|
260
|
+
);
|
|
261
|
+
if (idleDuration !== false) {
|
|
262
|
+
assertBoolean(
|
|
263
|
+
session.updatedAt + idleDuration > now,
|
|
264
|
+
"it is expired based on current idleDuration rules"
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
if (absoluteDuration !== false) {
|
|
268
|
+
assertBoolean(
|
|
269
|
+
session.issuedAt + absoluteDuration > now,
|
|
270
|
+
"it is expired based on current absoluteDuration rules"
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
return session;
|
|
274
|
+
}
|
|
275
|
+
} catch {
|
|
276
|
+
return void 0;
|
|
277
|
+
}
|
|
278
|
+
return void 0;
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Persists a complete session.
|
|
282
|
+
*/
|
|
283
|
+
async set(session) {
|
|
284
|
+
session.expiresAt = calculateExp(session.updatedAt, this.config, {
|
|
285
|
+
issuedAt: session.issuedAt
|
|
286
|
+
});
|
|
287
|
+
await this._set(session);
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Clears the session from the backing store.
|
|
291
|
+
*/
|
|
292
|
+
async delete() {
|
|
293
|
+
await this._delete();
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Updates idle expiry timestamps and persists the session.
|
|
297
|
+
*
|
|
298
|
+
* When idle sessions are disabled, this returns the current session
|
|
299
|
+
* without modifying cookies.
|
|
300
|
+
*/
|
|
301
|
+
async touch() {
|
|
302
|
+
const session = await this.get();
|
|
303
|
+
if (!session) {
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
if (this.config.session.idleDuration === false) {
|
|
307
|
+
return session;
|
|
308
|
+
}
|
|
309
|
+
const updatedAt = epoch();
|
|
310
|
+
const expiresAt = calculateExp(updatedAt, this.config, {
|
|
311
|
+
issuedAt: session.issuedAt
|
|
312
|
+
});
|
|
313
|
+
session.updatedAt = updatedAt;
|
|
314
|
+
session.expiresAt = expiresAt;
|
|
315
|
+
await this.set(session);
|
|
316
|
+
return session;
|
|
317
|
+
}
|
|
318
|
+
};
|
|
319
|
+
function calculateExp(updatedAt, config, session) {
|
|
320
|
+
const { absoluteDuration, idleDuration } = config.session;
|
|
321
|
+
const candidates = [];
|
|
322
|
+
if (idleDuration !== false) {
|
|
323
|
+
candidates.push(updatedAt + idleDuration);
|
|
324
|
+
}
|
|
325
|
+
if (absoluteDuration !== false) {
|
|
326
|
+
candidates.push(session.issuedAt + absoluteDuration);
|
|
327
|
+
}
|
|
328
|
+
return Math.min(...candidates);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// src/session/stores/stateless-store.ts
|
|
332
|
+
function sessionStoreFactory(config, request, response) {
|
|
333
|
+
return new NewStatelessSessionStore(config, request, response);
|
|
334
|
+
}
|
|
335
|
+
var NewStatelessSessionStore = class extends AbstractSessionStore {
|
|
336
|
+
constructor(config, request = void 0, response = void 0, cookieStore = () => cookieFactory(request, response)) {
|
|
337
|
+
super(config);
|
|
338
|
+
this.cookieStore = cookieStore;
|
|
339
|
+
this.cookieName = config.session.name;
|
|
340
|
+
this.cookieOptions = {
|
|
341
|
+
...config.session.cookie,
|
|
342
|
+
httpOnly: true
|
|
343
|
+
};
|
|
344
|
+
this.secrets = getSecrets(config);
|
|
345
|
+
}
|
|
346
|
+
cookieStore;
|
|
347
|
+
secrets;
|
|
348
|
+
cookieName;
|
|
349
|
+
cookieOptions;
|
|
350
|
+
async _get() {
|
|
351
|
+
const [session, authorization, authentication] = await this.getAllCookies();
|
|
352
|
+
if (!session.data) {
|
|
353
|
+
return void 0;
|
|
354
|
+
}
|
|
355
|
+
return new Session({
|
|
356
|
+
...session.data,
|
|
357
|
+
authorization: authorization.data || void 0,
|
|
358
|
+
authentication: authentication.data || void 0
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
async _set(payload) {
|
|
362
|
+
const [session, authorization, authentication] = await this.getAllCookies();
|
|
363
|
+
const {
|
|
364
|
+
user,
|
|
365
|
+
issuedAt,
|
|
366
|
+
updatedAt,
|
|
367
|
+
expiresAt,
|
|
368
|
+
authorization: authz,
|
|
369
|
+
authentication: authn
|
|
370
|
+
} = payload;
|
|
371
|
+
session.data = { user, issuedAt, updatedAt, expiresAt };
|
|
372
|
+
authentication.data = authn;
|
|
373
|
+
authorization.data = authz;
|
|
374
|
+
await Promise.all([
|
|
375
|
+
session.save(),
|
|
376
|
+
authorization.save(),
|
|
377
|
+
authentication.save()
|
|
378
|
+
]);
|
|
379
|
+
}
|
|
380
|
+
async _delete() {
|
|
381
|
+
const [session, authorization, authentication] = await this.getAllCookies();
|
|
382
|
+
await Promise.all([
|
|
383
|
+
session.destroy(),
|
|
384
|
+
authorization.destroy(),
|
|
385
|
+
authentication.destroy()
|
|
386
|
+
]);
|
|
387
|
+
}
|
|
388
|
+
async getAllCookies() {
|
|
389
|
+
return await Promise.all([
|
|
390
|
+
this.getCookie("Session"),
|
|
391
|
+
this.getCookie("Authorization"),
|
|
392
|
+
this.getCookie("Authentication")
|
|
393
|
+
]);
|
|
394
|
+
}
|
|
395
|
+
async getCookie(type) {
|
|
396
|
+
const ironSession$1 = await ironSession.getIronSession(await this.cookieStore(this.config), {
|
|
397
|
+
cookieName: `${this.cookieName}.${type}`,
|
|
398
|
+
password: this.secrets,
|
|
399
|
+
cookieOptions: this.cookieOptions
|
|
400
|
+
});
|
|
401
|
+
return ironSession$1;
|
|
402
|
+
}
|
|
403
|
+
};
|
|
404
|
+
async function discoverOIDC(config) {
|
|
405
|
+
const isLocalDevelopment = config.issuerBaseURL.includes("localhost") || config.issuerBaseURL.includes("127.0.0.1");
|
|
406
|
+
return await oidc__namespace.discovery(
|
|
407
|
+
new URL(config.issuerBaseURL),
|
|
408
|
+
config.clientId,
|
|
409
|
+
config.clientSecret,
|
|
410
|
+
void 0,
|
|
411
|
+
isLocalDevelopment ? {
|
|
412
|
+
execute: [oidc__namespace.allowInsecureRequests]
|
|
413
|
+
} : void 0
|
|
414
|
+
);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
// src/oauth/access-token.ts
|
|
418
|
+
function getAccessTokenFactory(instance) {
|
|
419
|
+
return async (options = {}) => {
|
|
420
|
+
const sessionStore = sessionStoreFactory(instance.config);
|
|
421
|
+
const session = await sessionStore.get();
|
|
422
|
+
if (!session?.user) {
|
|
423
|
+
throw new AccessTokenError(
|
|
424
|
+
"ERR_MISSING_SESSION" /* MISSING_SESSION */,
|
|
425
|
+
"A session is required to get an access token."
|
|
426
|
+
);
|
|
427
|
+
}
|
|
428
|
+
const authorization = session.authorization;
|
|
429
|
+
if (!authorization?.accessToken) {
|
|
430
|
+
throw new AccessTokenError(
|
|
431
|
+
"ERR_MISSING_ACCESS_TOKEN" /* MISSING_ACCESS_TOKEN */,
|
|
432
|
+
"The session does not contain an access token."
|
|
433
|
+
);
|
|
434
|
+
}
|
|
435
|
+
if (canUseAccessToken(authorization, options)) {
|
|
436
|
+
return toAccessTokenResult(authorization);
|
|
437
|
+
}
|
|
438
|
+
if (!authorization.refreshToken) {
|
|
439
|
+
throw new AccessTokenError(
|
|
440
|
+
isExpired(authorization, options) ? "ERR_EXPIRED_ACCESS_TOKEN" /* EXPIRED_ACCESS_TOKEN */ : "ERR_INSUFFICIENT_SCOPE" /* INSUFFICIENT_SCOPE */,
|
|
441
|
+
"The access token cannot be refreshed because the session does not contain a refresh token."
|
|
442
|
+
);
|
|
443
|
+
}
|
|
444
|
+
return refreshAccessToken(instance, session, options);
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
async function refreshAccessToken(instance, session, options) {
|
|
448
|
+
const oidc2 = await import('openid-client');
|
|
449
|
+
const authorization = session.authorization;
|
|
450
|
+
if (!authorization?.refreshToken) {
|
|
451
|
+
throw new AccessTokenError(
|
|
452
|
+
"ERR_MISSING_REFRESH_TOKEN" /* MISSING_REFRESH_TOKEN */,
|
|
453
|
+
"The session does not contain a refresh token."
|
|
454
|
+
);
|
|
455
|
+
}
|
|
456
|
+
try {
|
|
457
|
+
const params = getRefreshParameters(options);
|
|
458
|
+
const tokens = await oidc2.refreshTokenGrant(
|
|
459
|
+
await discoverOIDC(instance.config),
|
|
460
|
+
authorization.refreshToken,
|
|
461
|
+
params
|
|
462
|
+
);
|
|
463
|
+
if (!tokens.access_token) {
|
|
464
|
+
throw new AccessTokenError(
|
|
465
|
+
"ERR_FAILED_REFRESH_GRANT" /* FAILED_REFRESH_GRANT */,
|
|
466
|
+
"The refresh grant did not return an access token."
|
|
467
|
+
);
|
|
468
|
+
}
|
|
469
|
+
const refreshedAuthorization = {
|
|
470
|
+
accessToken: tokens.access_token,
|
|
471
|
+
expiresAt: epoch() + Number(tokens.expires_in ?? authorization.expiresAt - epoch()),
|
|
472
|
+
scope: tokens.scope ?? normalizeScopes(options.scopes) ?? authorization.scope,
|
|
473
|
+
refreshToken: tokens.refresh_token ?? authorization.refreshToken,
|
|
474
|
+
type: tokens.token_type ?? authorization.type
|
|
475
|
+
};
|
|
476
|
+
session.authorization = refreshedAuthorization;
|
|
477
|
+
await sessionStoreFactory(instance.config).set(session);
|
|
478
|
+
return toAccessTokenResult(refreshedAuthorization);
|
|
479
|
+
} catch (error) {
|
|
480
|
+
if (error instanceof AccessTokenError) {
|
|
481
|
+
throw error;
|
|
482
|
+
}
|
|
483
|
+
throw new AccessTokenError(
|
|
484
|
+
"ERR_FAILED_REFRESH_GRANT" /* FAILED_REFRESH_GRANT */,
|
|
485
|
+
"The refresh grant failed.",
|
|
486
|
+
error instanceof Error ? error : void 0
|
|
487
|
+
);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
function canUseAccessToken(authorization, options) {
|
|
491
|
+
return options.refresh !== true && !isExpired(authorization, options) && hasScopes(authorization.scope, options.scopes);
|
|
492
|
+
}
|
|
493
|
+
function isExpired(authorization, options) {
|
|
494
|
+
const skew = options.refreshBeforeExpiresIn ?? 60;
|
|
495
|
+
return authorization.expiresAt <= epoch() + skew;
|
|
496
|
+
}
|
|
497
|
+
function hasScopes(grantedScope, requiredScopes) {
|
|
498
|
+
const required = normalizeScopes(requiredScopes);
|
|
499
|
+
if (!required) {
|
|
500
|
+
return true;
|
|
501
|
+
}
|
|
502
|
+
const granted = new Set((grantedScope ?? "").split(/\s+/).filter(Boolean));
|
|
503
|
+
return required.split(/\s+/).every((scope) => granted.has(scope));
|
|
504
|
+
}
|
|
505
|
+
function getRefreshParameters(options) {
|
|
506
|
+
const scope = normalizeScopes(options.scopes);
|
|
507
|
+
if (!scope) {
|
|
508
|
+
return void 0;
|
|
509
|
+
}
|
|
510
|
+
const params = new URLSearchParams();
|
|
511
|
+
params.set("scope", scope);
|
|
512
|
+
return params;
|
|
513
|
+
}
|
|
514
|
+
function normalizeScopes(scopes) {
|
|
515
|
+
if (Array.isArray(scopes)) {
|
|
516
|
+
return scopes.join(" ");
|
|
517
|
+
}
|
|
518
|
+
return scopes;
|
|
519
|
+
}
|
|
520
|
+
function toAccessTokenResult(authorization) {
|
|
521
|
+
return {
|
|
522
|
+
accessToken: authorization.accessToken,
|
|
523
|
+
expiresAt: authorization.expiresAt,
|
|
524
|
+
scope: authorization.scope,
|
|
525
|
+
type: authorization.type
|
|
526
|
+
};
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
// src/errors/config.ts
|
|
530
|
+
var ConfigError = class _ConfigError extends AuthError {
|
|
531
|
+
static code = "ERR_CONFIG_VALIDATION";
|
|
532
|
+
/**
|
|
533
|
+
* Standard Schema validation issues for the invalid configuration.
|
|
534
|
+
*/
|
|
535
|
+
issues;
|
|
536
|
+
/**
|
|
537
|
+
* @param issues - Standard Schema validation issues.
|
|
538
|
+
*/
|
|
539
|
+
constructor(issues) {
|
|
540
|
+
super({
|
|
541
|
+
code: _ConfigError.code,
|
|
542
|
+
message: `Invalid @go-mondo/nextjs-auth configuration:
|
|
543
|
+
${formatIssues(
|
|
544
|
+
issues
|
|
545
|
+
)}`,
|
|
546
|
+
name: "ConfigError"
|
|
547
|
+
});
|
|
548
|
+
this.issues = issues;
|
|
549
|
+
Error.captureStackTrace(this, this.constructor);
|
|
550
|
+
Object.setPrototypeOf(this, _ConfigError.prototype);
|
|
551
|
+
}
|
|
552
|
+
};
|
|
553
|
+
function formatIssues(issues) {
|
|
554
|
+
return issues.map((issue) => {
|
|
555
|
+
const path = issue.path?.length ? issue.path.map(formatPathSegment).join(".") : "config";
|
|
556
|
+
return `- ${path}: ${issue.message}`;
|
|
557
|
+
}).join("\n");
|
|
558
|
+
}
|
|
559
|
+
function formatPathSegment(segment) {
|
|
560
|
+
return typeof segment === "object" && segment !== null && "key" in segment ? String(segment.key) : String(segment);
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
// src/config/routes.ts
|
|
564
|
+
var DEFAULT_ROUTES = {
|
|
565
|
+
login: "/auth/login",
|
|
566
|
+
callback: "/auth/callback",
|
|
567
|
+
logout: "/auth/logout",
|
|
568
|
+
session: "/auth/session",
|
|
569
|
+
accessToken: "/auth/access-token",
|
|
570
|
+
postLogoutRedirect: "/"
|
|
571
|
+
};
|
|
572
|
+
var RelativePathSchema = zod.z.string().startsWith("/", 'Must start with "/".').refine((value) => !value.includes("//"), 'Must not contain "//".').describe(
|
|
573
|
+
'An application-relative path, such as "/auth/login". Double slashes are not allowed.'
|
|
574
|
+
);
|
|
575
|
+
var StringUrlSchema = zod.z.string().url().transform((value) => value.replace(/\/+$/, "")).describe("An absolute URL. Trailing slashes are removed after parsing.");
|
|
576
|
+
var AuthorizationParamValueSchema = zod.z.union([
|
|
577
|
+
zod.z.string(),
|
|
578
|
+
zod.z.number(),
|
|
579
|
+
zod.z.boolean()
|
|
580
|
+
]);
|
|
581
|
+
var SessionSchema = zod.z.object({
|
|
582
|
+
name: zod.z.string().optional().default("Mondo").describe("Cookie name prefix used for the session cookie set."),
|
|
583
|
+
idleDuration: zod.z.union([zod.z.number().positive(), zod.z.literal(false)]).default(24 * 60 * 60).describe(
|
|
584
|
+
"Idle session duration in seconds. Set to false to disable activity-based session extension."
|
|
585
|
+
),
|
|
586
|
+
absoluteDuration: zod.z.union([zod.z.number().positive(), zod.z.literal(false)]).default(false).describe(
|
|
587
|
+
"Absolute session duration in seconds from login. Set to false to disable a hard maximum lifetime."
|
|
588
|
+
),
|
|
589
|
+
cookie: zod.z.object({
|
|
590
|
+
domain: zod.z.string().optional().describe("Optional domain shared by session cookies."),
|
|
591
|
+
path: RelativePathSchema.optional().default("/").describe("Path scope for session cookies."),
|
|
592
|
+
httpOnly: zod.z.boolean().optional().default(true).describe("Always true for server-managed authentication cookies."),
|
|
593
|
+
sameSite: zod.z.enum(["lax", "strict", "none"]).optional().default("lax").describe("SameSite policy used for session cookies."),
|
|
594
|
+
secure: zod.z.boolean().default(true).describe("Whether session cookies require HTTPS.")
|
|
595
|
+
}).describe("Cookie options for the tamper-proof iron-session cookies.")
|
|
596
|
+
}).refine(
|
|
597
|
+
(session) => session.idleDuration !== false || session.absoluteDuration !== false,
|
|
598
|
+
"At least one of idleDuration or absoluteDuration must be enabled."
|
|
599
|
+
).describe("Application session storage and expiration settings.");
|
|
600
|
+
var Schema = zod.z.object({
|
|
601
|
+
authorization: zod.z.object({
|
|
602
|
+
response_type: zod.z.enum(["code"]).default("code").describe(
|
|
603
|
+
"OAuth response type. This SDK uses authorization code flow."
|
|
604
|
+
),
|
|
605
|
+
scope: zod.z.string().default("openid profile email").describe("Default scopes requested during login."),
|
|
606
|
+
response_mode: zod.z.enum(["query", "form_post"]).default("query").describe(
|
|
607
|
+
"How the authorization response is returned to the callback."
|
|
608
|
+
),
|
|
609
|
+
audience: zod.z.string().optional().describe("Optional API audience for access token issuance."),
|
|
610
|
+
display: zod.z.enum(["page", "popup", "touch", "wap"]).optional().describe(
|
|
611
|
+
"OIDC display preference forwarded to the authorization URL."
|
|
612
|
+
),
|
|
613
|
+
prompt: zod.z.enum(["none", "login", "consent", "select_account"]).optional().describe("OIDC prompt behavior forwarded to the authorization URL."),
|
|
614
|
+
max_age: zod.z.number().optional().describe("Maximum authentication age, in seconds."),
|
|
615
|
+
ui_locales: zod.z.string().optional().describe("Preferred UI locales sent to the identity provider."),
|
|
616
|
+
id_token_hint: zod.z.string().optional().describe("Optional ID token hint sent to the identity provider."),
|
|
617
|
+
login_hint: zod.z.string().optional().describe("Optional login hint sent to the identity provider."),
|
|
618
|
+
acr_values: zod.z.string().optional().describe("Optional authentication context values.")
|
|
619
|
+
}).catchall(AuthorizationParamValueSchema).describe(
|
|
620
|
+
"Authorization URL parameters. Unknown string, number, and boolean values are preserved for provider-specific options."
|
|
621
|
+
),
|
|
622
|
+
baseURL: StringUrlSchema.describe(
|
|
623
|
+
"Public application origin used to construct default redirect URLs."
|
|
624
|
+
),
|
|
625
|
+
clientId: zod.z.string().min(1).describe("OIDC client identifier for this Next.js application."),
|
|
626
|
+
clientSecret: zod.z.string().min(1).describe("OIDC client secret used for token endpoint authentication."),
|
|
627
|
+
issuerBaseURL: StringUrlSchema.describe(
|
|
628
|
+
"Issuer origin used for OIDC discovery and logout redirects."
|
|
629
|
+
),
|
|
630
|
+
secret: zod.z.union([zod.z.string().min(32), zod.z.array(zod.z.string().min(32)).min(1)]).describe(
|
|
631
|
+
"Secret or rotated secrets used by iron-session to seal transaction and session cookies."
|
|
632
|
+
),
|
|
633
|
+
session: SessionSchema,
|
|
634
|
+
routes: zod.z.object({
|
|
635
|
+
login: RelativePathSchema.default("/auth/login").describe(
|
|
636
|
+
"Route that starts the login transaction."
|
|
637
|
+
),
|
|
638
|
+
callback: RelativePathSchema.default("/auth/callback").describe(
|
|
639
|
+
"Route that completes the authorization code exchange."
|
|
640
|
+
),
|
|
641
|
+
logout: RelativePathSchema.default("/auth/logout").describe(
|
|
642
|
+
"Route that clears the application session."
|
|
643
|
+
),
|
|
644
|
+
session: RelativePathSchema.default("/auth/session").describe(
|
|
645
|
+
"Route that returns the current session as JSON."
|
|
646
|
+
),
|
|
647
|
+
accessToken: RelativePathSchema.default("/auth/access-token").describe(
|
|
648
|
+
"Route that returns or refreshes the current access token."
|
|
649
|
+
),
|
|
650
|
+
postLogoutRedirect: RelativePathSchema.default("/").describe(
|
|
651
|
+
"Application path to redirect to after logout."
|
|
652
|
+
)
|
|
653
|
+
}).describe("Application routes mounted by the auth client."),
|
|
654
|
+
transaction: zod.z.object({
|
|
655
|
+
name: zod.z.string().default("Mondo.Verification").describe(
|
|
656
|
+
"Cookie name used to store login transaction verification."
|
|
657
|
+
),
|
|
658
|
+
cookie: zod.z.object({
|
|
659
|
+
domain: zod.z.string().optional().describe("Optional domain shared by transaction cookies."),
|
|
660
|
+
secure: zod.z.boolean().optional().describe("Whether transaction cookies require HTTPS."),
|
|
661
|
+
sameSite: zod.z.enum(["lax", "strict", "none"]).default("lax").describe("SameSite policy used for transaction cookies."),
|
|
662
|
+
path: RelativePathSchema.optional().default("/").describe("Path scope for transaction cookies.")
|
|
663
|
+
}).describe("Cookie options for temporary login transaction state.")
|
|
664
|
+
}).describe("Short-lived state used to verify authorization callbacks.")
|
|
665
|
+
}).describe("Validated configuration for @go-mondo/nextjs-auth.");
|
|
666
|
+
var schema_default = Schema;
|
|
667
|
+
|
|
668
|
+
// src/config/utils.ts
|
|
669
|
+
var FALSEY = ["n", "no", "false", "0", "off"];
|
|
670
|
+
var bool = (param, defaultValue) => {
|
|
671
|
+
if (param === void 0 || param === "") return defaultValue;
|
|
672
|
+
if (param && typeof param === "string")
|
|
673
|
+
return !FALSEY.includes(param.toLowerCase().trim());
|
|
674
|
+
return !!param;
|
|
675
|
+
};
|
|
676
|
+
var num = (param) => param === void 0 || param === "" ? void 0 : +param;
|
|
677
|
+
|
|
678
|
+
// src/config/config.ts
|
|
679
|
+
var getConfig = (params = {}) => {
|
|
680
|
+
const MONDO_SECRET = process.env.MONDO_SECRET;
|
|
681
|
+
const MONDO_ISSUER_BASE_URL = process.env.MONDO_ISSUER_BASE_URL;
|
|
682
|
+
const APP_BASE_URL = process.env.APP_BASE_URL || process.env.NEXT_PUBLIC_APP_BASE_URL;
|
|
683
|
+
const MONDO_CLIENT_ID = process.env.MONDO_CLIENT_ID;
|
|
684
|
+
const MONDO_CLIENT_SECRET = process.env.MONDO_CLIENT_SECRET;
|
|
685
|
+
const MONDO_AUDIENCE = process.env.MONDO_AUDIENCE;
|
|
686
|
+
const MONDO_SCOPE = process.env.MONDO_SCOPE;
|
|
687
|
+
const CALLBACK_ROUTE = process.env.CALLBACK_ROUTE;
|
|
688
|
+
const LOGOUT_ROUTE = process.env.LOGOUT_ROUTE;
|
|
689
|
+
const SESSION_ROUTE = process.env.SESSION_ROUTE;
|
|
690
|
+
const NEXT_PUBLIC_SESSION_ROUTE = process.env.NEXT_PUBLIC_SESSION_ROUTE;
|
|
691
|
+
const ACCESS_TOKEN_ROUTE = process.env.ACCESS_TOKEN_ROUTE;
|
|
692
|
+
const NEXT_PUBLIC_ACCESS_TOKEN_ROUTE = process.env.NEXT_PUBLIC_ACCESS_TOKEN_ROUTE;
|
|
693
|
+
const POST_LOGOUT_REDIRECT_ROUTE = process.env.POST_LOGOUT_REDIRECT_ROUTE;
|
|
694
|
+
const MONDO_SESSION_NAME = process.env.MONDO_SESSION_NAME;
|
|
695
|
+
const MONDO_SESSION_IDLE_DURATION = process.env.MONDO_SESSION_IDLE_DURATION;
|
|
696
|
+
const MONDO_SESSION_ABSOLUTE_DURATION = process.env.MONDO_SESSION_ABSOLUTE_DURATION;
|
|
697
|
+
const MONDO_SESSION_COOKIE_DOMAIN = process.env.MONDO_COOKIE_DOMAIN;
|
|
698
|
+
const MONDO_SESSION_COOKIE_PATH = process.env.MONDO_COOKIE_PATH;
|
|
699
|
+
const MONDO_SESSION_COOKIE_SECURE = process.env.MONDO_COOKIE_SECURE;
|
|
700
|
+
const MONDO_SESSION_COOKIE_SAME_SITE = process.env.MONDO_COOKIE_SAME_SITE;
|
|
701
|
+
const MONDO_TRANSACTION_NAME = process.env.MONDO_TRANSACTION_COOKIE_NAME;
|
|
702
|
+
const MONDO_TRANSACTION_COOKIE_DOMAIN = process.env.MONDO_TRANSACTION_COOKIE_DOMAIN;
|
|
703
|
+
const MONDO_TRANSACTION_COOKIE_PATH = process.env.MONDO_TRANSACTION_COOKIE_PATH;
|
|
704
|
+
const MONDO_TRANSACTION_COOKIE_SAME_SITE = process.env.MONDO_TRANSACTION_COOKIE_SAME_SITE;
|
|
705
|
+
const MONDO_TRANSACTION_COOKIE_SECURE = process.env.MONDO_TRANSACTION_COOKIE_SECURE;
|
|
706
|
+
const baseURL = APP_BASE_URL && !/^https?:\/\//.test(APP_BASE_URL) ? `https://${APP_BASE_URL}` : APP_BASE_URL;
|
|
707
|
+
const result = schema_default.safeParse({
|
|
708
|
+
secret: MONDO_SECRET,
|
|
709
|
+
issuerBaseURL: MONDO_ISSUER_BASE_URL,
|
|
710
|
+
baseURL,
|
|
711
|
+
clientId: MONDO_CLIENT_ID,
|
|
712
|
+
clientSecret: MONDO_CLIENT_SECRET,
|
|
713
|
+
...params,
|
|
714
|
+
authorization: {
|
|
715
|
+
response_type: "code",
|
|
716
|
+
audience: MONDO_AUDIENCE,
|
|
717
|
+
scope: MONDO_SCOPE,
|
|
718
|
+
...params.authorization
|
|
719
|
+
},
|
|
720
|
+
session: {
|
|
721
|
+
name: MONDO_SESSION_NAME,
|
|
722
|
+
idleDuration: duration(MONDO_SESSION_IDLE_DURATION),
|
|
723
|
+
absoluteDuration: duration(MONDO_SESSION_ABSOLUTE_DURATION),
|
|
724
|
+
...params.session,
|
|
725
|
+
cookie: {
|
|
726
|
+
domain: MONDO_SESSION_COOKIE_DOMAIN,
|
|
727
|
+
path: MONDO_SESSION_COOKIE_PATH || "/",
|
|
728
|
+
secure: bool(MONDO_SESSION_COOKIE_SECURE),
|
|
729
|
+
sameSite: MONDO_SESSION_COOKIE_SAME_SITE,
|
|
730
|
+
...params.session?.cookie
|
|
731
|
+
}
|
|
732
|
+
},
|
|
733
|
+
routes: {
|
|
734
|
+
callback: params.routes?.callback || CALLBACK_ROUTE || DEFAULT_ROUTES.callback,
|
|
735
|
+
login: params.routes?.login || process.env.NEXT_PUBLIC_LOGIN_ROUTE || DEFAULT_ROUTES.login,
|
|
736
|
+
logout: params.routes?.logout || LOGOUT_ROUTE || DEFAULT_ROUTES.logout,
|
|
737
|
+
session: params.routes?.session || SESSION_ROUTE || NEXT_PUBLIC_SESSION_ROUTE || DEFAULT_ROUTES.session,
|
|
738
|
+
accessToken: params.routes?.accessToken || ACCESS_TOKEN_ROUTE || NEXT_PUBLIC_ACCESS_TOKEN_ROUTE || DEFAULT_ROUTES.accessToken,
|
|
739
|
+
postLogoutRedirect: params.routes?.postLogoutRedirect || POST_LOGOUT_REDIRECT_ROUTE || DEFAULT_ROUTES.postLogoutRedirect
|
|
740
|
+
},
|
|
741
|
+
transaction: {
|
|
742
|
+
name: MONDO_TRANSACTION_NAME,
|
|
743
|
+
...params.transaction,
|
|
744
|
+
cookie: {
|
|
745
|
+
domain: MONDO_TRANSACTION_COOKIE_DOMAIN,
|
|
746
|
+
path: MONDO_TRANSACTION_COOKIE_PATH || "/",
|
|
747
|
+
secure: bool(MONDO_TRANSACTION_COOKIE_SECURE),
|
|
748
|
+
sameSite: MONDO_TRANSACTION_COOKIE_SAME_SITE,
|
|
749
|
+
...params.transaction?.cookie
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
});
|
|
753
|
+
if (!result.success) {
|
|
754
|
+
throw new ConfigError(result.error.issues);
|
|
755
|
+
}
|
|
756
|
+
return result.data;
|
|
757
|
+
};
|
|
758
|
+
function duration(value) {
|
|
759
|
+
if (!value) {
|
|
760
|
+
return void 0;
|
|
761
|
+
}
|
|
762
|
+
return Number.isNaN(Number(value)) ? bool(value) : num(value);
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
// src/core/instance.ts
|
|
766
|
+
var initInstance = (params) => {
|
|
767
|
+
const config = getConfig(params);
|
|
768
|
+
return {
|
|
769
|
+
config
|
|
770
|
+
};
|
|
771
|
+
};
|
|
772
|
+
|
|
773
|
+
// src/errors/handlers.ts
|
|
774
|
+
var HandlerError = class extends AuthError {
|
|
775
|
+
constructor(options) {
|
|
776
|
+
let status;
|
|
777
|
+
if ("status" in options.cause) status = options.cause.status;
|
|
778
|
+
super({ ...options, status });
|
|
779
|
+
}
|
|
780
|
+
};
|
|
781
|
+
var CallbackHandlerError = class _CallbackHandlerError extends HandlerError {
|
|
782
|
+
static code = "ERR_CALLBACK_HANDLER_FAILURE";
|
|
783
|
+
constructor(cause) {
|
|
784
|
+
super({
|
|
785
|
+
code: _CallbackHandlerError.code,
|
|
786
|
+
message: "Callback handler failed.",
|
|
787
|
+
name: "CallbackHandlerError",
|
|
788
|
+
cause
|
|
789
|
+
});
|
|
790
|
+
Object.setPrototypeOf(this, _CallbackHandlerError.prototype);
|
|
791
|
+
}
|
|
792
|
+
};
|
|
793
|
+
var LoginHandlerError = class _LoginHandlerError extends HandlerError {
|
|
794
|
+
static code = "ERR_LOGIN_HANDLER_FAILURE";
|
|
795
|
+
constructor(cause) {
|
|
796
|
+
super({
|
|
797
|
+
code: _LoginHandlerError.code,
|
|
798
|
+
message: "Login handler failed.",
|
|
799
|
+
name: "LoginHandlerError",
|
|
800
|
+
cause
|
|
801
|
+
});
|
|
802
|
+
Object.setPrototypeOf(this, _LoginHandlerError.prototype);
|
|
803
|
+
}
|
|
804
|
+
};
|
|
805
|
+
var LogoutHandlerError = class _LogoutHandlerError extends HandlerError {
|
|
806
|
+
static code = "ERR_LOGOUT_HANDLER_FAILURE";
|
|
807
|
+
constructor(cause) {
|
|
808
|
+
super({
|
|
809
|
+
code: _LogoutHandlerError.code,
|
|
810
|
+
message: "Logout handler failed.",
|
|
811
|
+
name: "LogoutHandlerError",
|
|
812
|
+
cause
|
|
813
|
+
});
|
|
814
|
+
Object.setPrototypeOf(this, _LogoutHandlerError.prototype);
|
|
815
|
+
}
|
|
816
|
+
};
|
|
817
|
+
|
|
818
|
+
// src/errors/state.ts
|
|
819
|
+
var MissingStateCookieError = class _MissingStateCookieError extends Error {
|
|
820
|
+
static message = "Missing state cookie from login request (check login URL, callback URL and cookie config).";
|
|
821
|
+
status = 400;
|
|
822
|
+
statusCode = 400;
|
|
823
|
+
constructor() {
|
|
824
|
+
super(_MissingStateCookieError.message);
|
|
825
|
+
Object.setPrototypeOf(this, _MissingStateCookieError.prototype);
|
|
826
|
+
}
|
|
827
|
+
};
|
|
828
|
+
function transactionStoreFactory(config, cookieStore) {
|
|
829
|
+
return new TransactionStore(
|
|
830
|
+
getSecrets(config),
|
|
831
|
+
cookieStore,
|
|
832
|
+
config.transaction.name,
|
|
833
|
+
{
|
|
834
|
+
...config.transaction.cookie,
|
|
835
|
+
httpOnly: true
|
|
836
|
+
}
|
|
837
|
+
);
|
|
838
|
+
}
|
|
839
|
+
var TransactionStore = class {
|
|
840
|
+
constructor(secrets, cookieStore, cookieName, cookieOptions) {
|
|
841
|
+
this.secrets = secrets;
|
|
842
|
+
this.cookieStore = cookieStore;
|
|
843
|
+
this.cookieName = cookieName;
|
|
844
|
+
this.cookieOptions = cookieOptions;
|
|
845
|
+
}
|
|
846
|
+
secrets;
|
|
847
|
+
cookieStore;
|
|
848
|
+
cookieName;
|
|
849
|
+
cookieOptions;
|
|
850
|
+
/**
|
|
851
|
+
* Saves transaction verification data in a sealed cookie.
|
|
852
|
+
*/
|
|
853
|
+
async save(value) {
|
|
854
|
+
const cookie = await this.getCookie();
|
|
855
|
+
cookie.code_verifier = value.code_verifier;
|
|
856
|
+
cookie.nonce = value.nonce;
|
|
857
|
+
cookie.state = value.state;
|
|
858
|
+
cookie.max_age = value.max_age;
|
|
859
|
+
cookie.return_to = value.return_to;
|
|
860
|
+
return await cookie.save();
|
|
861
|
+
}
|
|
862
|
+
async getCookie() {
|
|
863
|
+
const ironSession$1 = await ironSession.getIronSession(
|
|
864
|
+
this.cookieStore,
|
|
865
|
+
{
|
|
866
|
+
cookieName: this.cookieName,
|
|
867
|
+
password: this.secrets,
|
|
868
|
+
cookieOptions: this.cookieOptions
|
|
869
|
+
}
|
|
870
|
+
);
|
|
871
|
+
return ironSession$1;
|
|
872
|
+
}
|
|
873
|
+
/**
|
|
874
|
+
* Reads and destroys the transaction cookie.
|
|
875
|
+
*
|
|
876
|
+
* @returns Verification data, or `undefined` when the cookie is missing or
|
|
877
|
+
* malformed.
|
|
878
|
+
*/
|
|
879
|
+
async read() {
|
|
880
|
+
const cookie = await this.getCookie();
|
|
881
|
+
if (!cookie.code_verifier || !cookie.nonce || !cookie.state) {
|
|
882
|
+
cookie.destroy();
|
|
883
|
+
return void 0;
|
|
884
|
+
}
|
|
885
|
+
const result = {
|
|
886
|
+
code_verifier: cookie.code_verifier,
|
|
887
|
+
nonce: cookie.nonce,
|
|
888
|
+
state: cookie.state,
|
|
889
|
+
max_age: cookie.max_age,
|
|
890
|
+
return_to: cookie.return_to
|
|
891
|
+
};
|
|
892
|
+
cookie.destroy();
|
|
893
|
+
return result;
|
|
894
|
+
}
|
|
895
|
+
};
|
|
896
|
+
|
|
897
|
+
// src/routes/callback.ts
|
|
898
|
+
var callbackHandlerFactory = (instance) => (options) => async (req) => {
|
|
899
|
+
try {
|
|
900
|
+
const cookieStore = await cookieFactory();
|
|
901
|
+
return await handler(
|
|
902
|
+
instance,
|
|
903
|
+
new URL(req.url),
|
|
904
|
+
transactionStoreFactory(instance.config, cookieStore),
|
|
905
|
+
sessionStoreFactory(instance.config),
|
|
906
|
+
options
|
|
907
|
+
);
|
|
908
|
+
} catch (e) {
|
|
909
|
+
throw new CallbackHandlerError(e);
|
|
910
|
+
}
|
|
911
|
+
};
|
|
912
|
+
async function handler({ config }, requestUrl, transactionStore, sessionStore, options) {
|
|
913
|
+
const oidc2 = await import('openid-client');
|
|
914
|
+
const authVerification = await transactionStore.read();
|
|
915
|
+
if (!authVerification) {
|
|
916
|
+
throw new MissingStateCookieError();
|
|
917
|
+
}
|
|
918
|
+
const clientConfig = await discoverOIDC(config);
|
|
919
|
+
const tokens = await oidc2.authorizationCodeGrant(
|
|
920
|
+
clientConfig,
|
|
921
|
+
requestUrl,
|
|
922
|
+
{
|
|
923
|
+
pkceCodeVerifier: authVerification.code_verifier,
|
|
924
|
+
expectedState: authVerification.state,
|
|
925
|
+
expectedNonce: authVerification.nonce,
|
|
926
|
+
idTokenExpected: true,
|
|
927
|
+
maxAge: authVerification.max_age
|
|
928
|
+
},
|
|
929
|
+
options?.tokenParameters
|
|
930
|
+
);
|
|
931
|
+
const session = await fromTokenEndpointResponse(tokens);
|
|
932
|
+
if (session) {
|
|
933
|
+
await sessionStore.set(session);
|
|
934
|
+
}
|
|
935
|
+
return server_js.NextResponse.redirect(authVerification.return_to || config.baseURL);
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
// src/oauth/types.ts
|
|
939
|
+
var CodeChallengeMethod = {
|
|
940
|
+
S256: "S256"
|
|
941
|
+
};
|
|
942
|
+
|
|
943
|
+
// src/http/url.ts
|
|
944
|
+
function toSafeRedirect(dangerousRedirect, safeBaseUrl) {
|
|
945
|
+
let url;
|
|
946
|
+
try {
|
|
947
|
+
url = new URL(dangerousRedirect, safeBaseUrl);
|
|
948
|
+
} catch (_e) {
|
|
949
|
+
return void 0;
|
|
950
|
+
}
|
|
951
|
+
if (url.origin === safeBaseUrl.origin) {
|
|
952
|
+
return url.toString();
|
|
953
|
+
}
|
|
954
|
+
return void 0;
|
|
955
|
+
}
|
|
956
|
+
function getAuthorizationRedirectURL(config, origin) {
|
|
957
|
+
return pathOrURLToURL(config, config.routes.callback, origin);
|
|
958
|
+
}
|
|
959
|
+
function pathOrURLToURL(config, pathOrUrl, origin) {
|
|
960
|
+
if (pathOrUrl instanceof URL) {
|
|
961
|
+
return pathOrUrl;
|
|
962
|
+
}
|
|
963
|
+
try {
|
|
964
|
+
return new URL(pathOrUrl);
|
|
965
|
+
} catch (_) {
|
|
966
|
+
return new URL(joinURL(origin || config.baseURL, pathOrUrl));
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
function joinURL(base, path) {
|
|
970
|
+
return `${base.replace(/\/+$/, "")}/${path.replace(/^\/+/, "")}`;
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
// src/routes/login.ts
|
|
974
|
+
var loginHandlerFactory = (instance) => (options) => async (req) => {
|
|
975
|
+
try {
|
|
976
|
+
const url = new URL(req.url);
|
|
977
|
+
return await handler2(
|
|
978
|
+
instance,
|
|
979
|
+
transactionStoreFactory(instance.config, await cookieFactory()),
|
|
980
|
+
buildOptions(
|
|
981
|
+
instance.config,
|
|
982
|
+
options,
|
|
983
|
+
url.searchParams.get("returnTo"),
|
|
984
|
+
url.origin
|
|
985
|
+
),
|
|
986
|
+
url.origin
|
|
987
|
+
);
|
|
988
|
+
} catch (e) {
|
|
989
|
+
throw new LoginHandlerError(e);
|
|
990
|
+
}
|
|
991
|
+
};
|
|
992
|
+
async function handler2({ config }, transactionStore, options, requestOrigin) {
|
|
993
|
+
const oidc2 = await import('openid-client');
|
|
994
|
+
const returnTo = options?.returnTo || config.baseURL;
|
|
995
|
+
const authVerification = {
|
|
996
|
+
nonce: oidc2.randomNonce(),
|
|
997
|
+
state: oidc2.randomState(),
|
|
998
|
+
code_verifier: oidc2.randomPKCECodeVerifier(),
|
|
999
|
+
return_to: returnTo
|
|
1000
|
+
};
|
|
1001
|
+
const parameters = {
|
|
1002
|
+
redirect_uri: getAuthorizationRedirectURL(config, requestOrigin).toString(),
|
|
1003
|
+
...config.authorization,
|
|
1004
|
+
...options?.authorization || {},
|
|
1005
|
+
nonce: authVerification.nonce,
|
|
1006
|
+
state: authVerification.state,
|
|
1007
|
+
code_challenge_method: CodeChallengeMethod.S256,
|
|
1008
|
+
code_challenge: await oidc2.calculatePKCECodeChallenge(
|
|
1009
|
+
authVerification.code_verifier
|
|
1010
|
+
)
|
|
1011
|
+
};
|
|
1012
|
+
if (parameters.max_age) {
|
|
1013
|
+
authVerification.max_age = parameters.max_age;
|
|
1014
|
+
}
|
|
1015
|
+
await transactionStore.save(authVerification);
|
|
1016
|
+
const clientConfig = await discoverOIDC(config);
|
|
1017
|
+
const authorizationUrl = oidc2.buildAuthorizationUrl(
|
|
1018
|
+
clientConfig,
|
|
1019
|
+
toAuthorizationUrlParameters(parameters)
|
|
1020
|
+
);
|
|
1021
|
+
return server_js.NextResponse.redirect(authorizationUrl);
|
|
1022
|
+
}
|
|
1023
|
+
function toAuthorizationUrlParameters(parameters) {
|
|
1024
|
+
const authorizationUrlParameters = {};
|
|
1025
|
+
for (const [key, value] of Object.entries(parameters)) {
|
|
1026
|
+
if (value !== void 0) {
|
|
1027
|
+
authorizationUrlParameters[key] = String(value);
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
return authorizationUrlParameters;
|
|
1031
|
+
}
|
|
1032
|
+
var buildOptions = (config, opts, dangerousReturnTo, requestOrigin) => {
|
|
1033
|
+
const options = opts || {};
|
|
1034
|
+
if (dangerousReturnTo) {
|
|
1035
|
+
const safeBaseUrl = new URL(
|
|
1036
|
+
options?.authorization?.redirect_uri || requestOrigin || config.baseURL
|
|
1037
|
+
);
|
|
1038
|
+
options.returnTo = toSafeRedirect(dangerousReturnTo, safeBaseUrl);
|
|
1039
|
+
}
|
|
1040
|
+
return options;
|
|
1041
|
+
};
|
|
1042
|
+
var logoutHandlerFactory = (instance) => (options) => async (req) => {
|
|
1043
|
+
try {
|
|
1044
|
+
const url = new URL(req.url);
|
|
1045
|
+
return await handler3(
|
|
1046
|
+
instance,
|
|
1047
|
+
sessionStoreFactory(instance.config),
|
|
1048
|
+
buildOptions2(
|
|
1049
|
+
instance.config,
|
|
1050
|
+
options,
|
|
1051
|
+
url.searchParams.get("returnTo")
|
|
1052
|
+
)
|
|
1053
|
+
);
|
|
1054
|
+
} catch (e) {
|
|
1055
|
+
throw new LogoutHandlerError(e);
|
|
1056
|
+
}
|
|
1057
|
+
};
|
|
1058
|
+
async function handler3({ config }, sessionCache, options) {
|
|
1059
|
+
let returnURL = pathOrURLToURL(
|
|
1060
|
+
config,
|
|
1061
|
+
options?.returnTo || config.routes.postLogoutRedirect
|
|
1062
|
+
);
|
|
1063
|
+
await sessionCache.delete();
|
|
1064
|
+
if (options?.singleLogOut) {
|
|
1065
|
+
returnURL = new URL(
|
|
1066
|
+
["/logout", `redirectTo=${returnURL.toString()}`].join("?"),
|
|
1067
|
+
config.issuerBaseURL
|
|
1068
|
+
);
|
|
1069
|
+
}
|
|
1070
|
+
return server_js.NextResponse.redirect(returnURL);
|
|
1071
|
+
}
|
|
1072
|
+
var buildOptions2 = (config, opts, dangerousReturnTo) => {
|
|
1073
|
+
const options = opts || {};
|
|
1074
|
+
if (dangerousReturnTo) {
|
|
1075
|
+
const safeBaseUrl = new URL(config.baseURL);
|
|
1076
|
+
options.returnTo = toSafeRedirect(dangerousReturnTo, safeBaseUrl);
|
|
1077
|
+
}
|
|
1078
|
+
return options;
|
|
1079
|
+
};
|
|
1080
|
+
var sessionHandlerFactory = (instance) => (options) => async (_req) => {
|
|
1081
|
+
return await handler4(
|
|
1082
|
+
sessionStoreFactory(instance.config),
|
|
1083
|
+
options
|
|
1084
|
+
);
|
|
1085
|
+
};
|
|
1086
|
+
async function handler4(sessionStore, options) {
|
|
1087
|
+
const session = await (options?.touch !== false ? sessionStore.touch() : sessionStore.get());
|
|
1088
|
+
const result = options?.transform ? options?.transform(session) : session;
|
|
1089
|
+
if (!result) {
|
|
1090
|
+
return Response.json(
|
|
1091
|
+
{
|
|
1092
|
+
error: "SessionNotFound",
|
|
1093
|
+
error_description: "Session does not exist or has expired"
|
|
1094
|
+
},
|
|
1095
|
+
{ status: 401, statusText: "Unauthorized" }
|
|
1096
|
+
);
|
|
1097
|
+
}
|
|
1098
|
+
return server_js.NextResponse.json(result);
|
|
1099
|
+
}
|
|
1100
|
+
var accessTokenHandlerFactory = (instance) => (options) => async (req) => {
|
|
1101
|
+
try {
|
|
1102
|
+
const { transform, ...staticOptions } = options ?? {};
|
|
1103
|
+
const requestOptions = await getRequestOptions(req);
|
|
1104
|
+
const token = await getAccessTokenFactory(instance)({
|
|
1105
|
+
...staticOptions,
|
|
1106
|
+
...requestOptions ?? {}
|
|
1107
|
+
});
|
|
1108
|
+
return server_js.NextResponse.json(transform?.(token) ?? token);
|
|
1109
|
+
} catch (error) {
|
|
1110
|
+
if (error instanceof AccessTokenError) {
|
|
1111
|
+
return server_js.NextResponse.json(
|
|
1112
|
+
{
|
|
1113
|
+
error: error.code,
|
|
1114
|
+
error_description: error.message
|
|
1115
|
+
},
|
|
1116
|
+
{ status: getStatusCode(error.code) }
|
|
1117
|
+
);
|
|
1118
|
+
}
|
|
1119
|
+
throw error;
|
|
1120
|
+
}
|
|
1121
|
+
};
|
|
1122
|
+
async function getRequestOptions(req) {
|
|
1123
|
+
if (req.method !== "POST") {
|
|
1124
|
+
return void 0;
|
|
1125
|
+
}
|
|
1126
|
+
const body = await readJsonBody(req);
|
|
1127
|
+
if (!isRecord(body)) {
|
|
1128
|
+
return void 0;
|
|
1129
|
+
}
|
|
1130
|
+
const options = {};
|
|
1131
|
+
const scopes = getScopes(body.scopes);
|
|
1132
|
+
if (typeof body.refresh === "boolean") {
|
|
1133
|
+
options.refresh = body.refresh;
|
|
1134
|
+
}
|
|
1135
|
+
if (typeof body.refreshBeforeExpiresIn === "number") {
|
|
1136
|
+
options.refreshBeforeExpiresIn = body.refreshBeforeExpiresIn;
|
|
1137
|
+
}
|
|
1138
|
+
if (scopes) {
|
|
1139
|
+
options.scopes = scopes;
|
|
1140
|
+
}
|
|
1141
|
+
return options;
|
|
1142
|
+
}
|
|
1143
|
+
async function readJsonBody(req) {
|
|
1144
|
+
try {
|
|
1145
|
+
return await req.json();
|
|
1146
|
+
} catch {
|
|
1147
|
+
return void 0;
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
function getScopes(value) {
|
|
1151
|
+
if (typeof value === "string") {
|
|
1152
|
+
return value;
|
|
1153
|
+
}
|
|
1154
|
+
if (Array.isArray(value) && value.every((scope) => typeof scope === "string")) {
|
|
1155
|
+
return value;
|
|
1156
|
+
}
|
|
1157
|
+
return void 0;
|
|
1158
|
+
}
|
|
1159
|
+
function isRecord(value) {
|
|
1160
|
+
return Boolean(value && typeof value === "object");
|
|
1161
|
+
}
|
|
1162
|
+
function getStatusCode(code) {
|
|
1163
|
+
switch (code) {
|
|
1164
|
+
case "ERR_MISSING_SESSION" /* MISSING_SESSION */:
|
|
1165
|
+
case "ERR_MISSING_ACCESS_TOKEN" /* MISSING_ACCESS_TOKEN */:
|
|
1166
|
+
case "ERR_MISSING_REFRESH_TOKEN" /* MISSING_REFRESH_TOKEN */:
|
|
1167
|
+
case "ERR_EXPIRED_ACCESS_TOKEN" /* EXPIRED_ACCESS_TOKEN */:
|
|
1168
|
+
return 401;
|
|
1169
|
+
case "ERR_INSUFFICIENT_SCOPE" /* INSUFFICIENT_SCOPE */:
|
|
1170
|
+
return 403;
|
|
1171
|
+
case "ERR_FAILED_REFRESH_GRANT" /* FAILED_REFRESH_GRANT */:
|
|
1172
|
+
return 502;
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
// src/client.ts
|
|
1177
|
+
var MondoAuthClient = class {
|
|
1178
|
+
instance;
|
|
1179
|
+
/**
|
|
1180
|
+
* Creates a client and validates configuration immediately.
|
|
1181
|
+
*
|
|
1182
|
+
* @param config - Optional explicit config. Environment variables provide the
|
|
1183
|
+
* remaining values.
|
|
1184
|
+
*/
|
|
1185
|
+
constructor(config) {
|
|
1186
|
+
this.instance = initInstance(config);
|
|
1187
|
+
}
|
|
1188
|
+
/**
|
|
1189
|
+
* Validated auth configuration used by this client.
|
|
1190
|
+
*/
|
|
1191
|
+
get config() {
|
|
1192
|
+
return this.instance.config;
|
|
1193
|
+
}
|
|
1194
|
+
/**
|
|
1195
|
+
* Returns one route handler that serves all configured auth routes.
|
|
1196
|
+
*
|
|
1197
|
+
* Mount this from a catch-all route such as
|
|
1198
|
+
* `src/app/auth/[...auth]/route.ts`.
|
|
1199
|
+
*/
|
|
1200
|
+
handleAuth(options = {}) {
|
|
1201
|
+
return async (request) => {
|
|
1202
|
+
const { pathname } = new URL(request.url);
|
|
1203
|
+
const { routes } = this.config;
|
|
1204
|
+
if (pathname === routes.login) {
|
|
1205
|
+
return this.handleLogin(options.login)(request);
|
|
1206
|
+
}
|
|
1207
|
+
if (pathname === routes.callback) {
|
|
1208
|
+
return this.handleCallback(options.callback)(request);
|
|
1209
|
+
}
|
|
1210
|
+
if (pathname === routes.logout) {
|
|
1211
|
+
return this.handleLogout(options.logout)(request);
|
|
1212
|
+
}
|
|
1213
|
+
if (pathname === routes.session) {
|
|
1214
|
+
return this.handleSession(options.session)(request);
|
|
1215
|
+
}
|
|
1216
|
+
if (pathname === routes.accessToken) {
|
|
1217
|
+
return this.handleAccessToken(options.accessToken)(request);
|
|
1218
|
+
}
|
|
1219
|
+
return server_js.NextResponse.json(
|
|
1220
|
+
{
|
|
1221
|
+
error: "NotFound",
|
|
1222
|
+
error_description: `No Mondo auth route is configured for ${pathname}.`
|
|
1223
|
+
},
|
|
1224
|
+
{ status: 404 }
|
|
1225
|
+
);
|
|
1226
|
+
};
|
|
1227
|
+
}
|
|
1228
|
+
/**
|
|
1229
|
+
* Creates a route handler that starts the OIDC login redirect.
|
|
1230
|
+
*/
|
|
1231
|
+
handleLogin(options) {
|
|
1232
|
+
return loginHandlerFactory(this.instance)(options);
|
|
1233
|
+
}
|
|
1234
|
+
/**
|
|
1235
|
+
* Creates a route handler that completes the OIDC callback.
|
|
1236
|
+
*/
|
|
1237
|
+
handleCallback(options) {
|
|
1238
|
+
return callbackHandlerFactory(this.instance)(options);
|
|
1239
|
+
}
|
|
1240
|
+
/**
|
|
1241
|
+
* Creates a route handler that clears the local session.
|
|
1242
|
+
*/
|
|
1243
|
+
handleLogout(options) {
|
|
1244
|
+
return logoutHandlerFactory(this.instance)(options);
|
|
1245
|
+
}
|
|
1246
|
+
/**
|
|
1247
|
+
* Creates a route handler that returns the current session as JSON.
|
|
1248
|
+
*/
|
|
1249
|
+
handleSession(options) {
|
|
1250
|
+
return sessionHandlerFactory(this.instance)(options);
|
|
1251
|
+
}
|
|
1252
|
+
/**
|
|
1253
|
+
* Creates a route handler that returns or refreshes the current access token.
|
|
1254
|
+
*/
|
|
1255
|
+
handleAccessToken(options) {
|
|
1256
|
+
return accessTokenHandlerFactory(this.instance)(options);
|
|
1257
|
+
}
|
|
1258
|
+
/**
|
|
1259
|
+
* Reads the current sealed-cookie session in server code.
|
|
1260
|
+
*/
|
|
1261
|
+
getSession = async () => {
|
|
1262
|
+
return sessionStoreFactory(this.config).get();
|
|
1263
|
+
};
|
|
1264
|
+
/**
|
|
1265
|
+
* Returns the current access token, refreshing with the stored refresh token
|
|
1266
|
+
* when the token is expired or missing required scopes.
|
|
1267
|
+
*/
|
|
1268
|
+
getAccessToken = (options) => {
|
|
1269
|
+
return getAccessTokenFactory(this.instance)(options);
|
|
1270
|
+
};
|
|
1271
|
+
/**
|
|
1272
|
+
* Drop this into `proxy.ts` to protect matched routes and keep idle sessions
|
|
1273
|
+
* fresh at the request boundary.
|
|
1274
|
+
*/
|
|
1275
|
+
proxy = async (request, options = {}) => {
|
|
1276
|
+
const url = new URL(request.url);
|
|
1277
|
+
if (isAuthRoute(url.pathname, this.config.routes)) {
|
|
1278
|
+
return void 0;
|
|
1279
|
+
}
|
|
1280
|
+
if (isPublicPath(url.pathname, options.publicPaths)) {
|
|
1281
|
+
return void 0;
|
|
1282
|
+
}
|
|
1283
|
+
const response = server_js.NextResponse.next();
|
|
1284
|
+
const sessionStore = sessionStoreFactory(
|
|
1285
|
+
this.config,
|
|
1286
|
+
request,
|
|
1287
|
+
response
|
|
1288
|
+
);
|
|
1289
|
+
const session = await sessionStore.get();
|
|
1290
|
+
if (!session?.user) {
|
|
1291
|
+
const returnTo = typeof options.returnTo === "function" ? await options.returnTo(request) : options.returnTo || `${url.pathname}${url.search}`;
|
|
1292
|
+
return server_js.NextResponse.redirect(
|
|
1293
|
+
new URL(
|
|
1294
|
+
`${this.config.routes.login}?returnTo=${encodeURIComponent(returnTo)}`,
|
|
1295
|
+
url.origin
|
|
1296
|
+
)
|
|
1297
|
+
);
|
|
1298
|
+
}
|
|
1299
|
+
await sessionStore.touch();
|
|
1300
|
+
return response;
|
|
1301
|
+
};
|
|
1302
|
+
};
|
|
1303
|
+
function createAuth(config) {
|
|
1304
|
+
return new MondoAuthClient(config);
|
|
1305
|
+
}
|
|
1306
|
+
function isAuthRoute(pathname, routes) {
|
|
1307
|
+
return [
|
|
1308
|
+
routes.login,
|
|
1309
|
+
routes.callback,
|
|
1310
|
+
routes.logout,
|
|
1311
|
+
routes.session,
|
|
1312
|
+
routes.accessToken
|
|
1313
|
+
].includes(pathname);
|
|
1314
|
+
}
|
|
1315
|
+
function isPublicPath(pathname, publicPaths = []) {
|
|
1316
|
+
return publicPaths.some(
|
|
1317
|
+
(path) => typeof path === "string" ? pathname.startsWith(path) : path.test(pathname)
|
|
1318
|
+
);
|
|
1319
|
+
}
|
|
1320
|
+
|
|
1321
|
+
exports.MondoAuthClient = MondoAuthClient;
|
|
1322
|
+
exports.createAuth = createAuth;
|
|
1323
|
+
//# sourceMappingURL=client.cjs.map
|
|
1324
|
+
//# sourceMappingURL=client.cjs.map
|