@iqauth/sdk 2.7.0 → 2.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser-session.d.mts +3 -3
- package/dist/browser-session.d.ts +3 -3
- package/dist/browser-session.js +31 -5
- package/dist/browser-session.mjs +1 -1
- package/dist/browser.d.mts +3 -3
- package/dist/browser.d.ts +3 -3
- package/dist/browser.js +23 -3
- package/dist/browser.mjs +1 -1
- package/dist/{chunk-YVALAG3B.mjs → chunk-25SSYDIP.mjs} +1 -1
- package/dist/{chunk-RTJAIBXY.mjs → chunk-4V7FKOTG.mjs} +23 -3
- package/dist/{chunk-SL3KRS4W.mjs → chunk-CIJORODR.mjs} +23 -1
- package/dist/chunk-JRDVUWAL.mjs +46 -0
- package/dist/{chunk-5T7GHBX6.mjs → chunk-TLET552H.mjs} +36 -0
- package/dist/{chunk-PMAFENVI.mjs → chunk-VYQ3ETCK.mjs} +27 -12
- package/dist/{chunk-RR2MGPTK.mjs → chunk-WHT6WKTY.mjs} +539 -83
- package/dist/{chunk-RUJXRTEW.mjs → chunk-WSH4SW7F.mjs} +122 -8
- package/dist/{chunk-JXQI62A7.mjs → chunk-ZLJPABB7.mjs} +31 -5
- package/dist/{client-BGFnBpfc.d.mts → client-D8L-PaWr.d.mts} +14 -4
- package/dist/{client-CDQ21LvW.d.ts → client-DkPL0EPZ.d.ts} +14 -4
- package/dist/{express-Piv2WhWM.d.ts → express-Budysq4h.d.ts} +2 -2
- package/dist/{express-CVNQEkOr.d.mts → express-DDTA3qV1.d.mts} +2 -2
- package/dist/express.d.mts +5 -5
- package/dist/express.d.ts +5 -5
- package/dist/express.js +217 -36
- package/dist/express.mjs +38 -26
- package/dist/fastify.d.mts +10 -2
- package/dist/fastify.d.ts +10 -2
- package/dist/fastify.js +260 -16
- package/dist/fastify.mjs +80 -5
- package/dist/hono.d.mts +10 -2
- package/dist/hono.d.ts +10 -2
- package/dist/hono.js +240 -16
- package/dist/hono.mjs +60 -5
- package/dist/{index-5KSZEnDe.d.ts → index-Cko-d5po.d.mts} +227 -5
- package/dist/{index-CKoZHAoc.d.mts → index-RNqwEcmY.d.ts} +227 -5
- package/dist/index.d.mts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.js +149 -26
- package/dist/index.mjs +5 -5
- package/dist/locales.d.mts +1 -1
- package/dist/locales.d.ts +1 -1
- package/dist/locales.js +36 -0
- package/dist/locales.mjs +1 -1
- package/dist/mobile.d.mts +3 -3
- package/dist/mobile.d.ts +3 -3
- package/dist/mobile.js +31 -5
- package/dist/mobile.mjs +1 -1
- package/dist/next.d.mts +10 -2
- package/dist/next.d.ts +10 -2
- package/dist/next.js +212 -11
- package/dist/next.mjs +62 -4
- package/dist/{provisioningBridge-M5G47LWO.d.mts → provisioningBridge-BXPMZCLe.d.ts} +30 -2
- package/dist/{provisioningBridge-CGpMRie4.d.ts → provisioningBridge-IEycmsgb.d.mts} +30 -2
- package/dist/react-permissions.d.mts +4 -4
- package/dist/react-permissions.d.ts +4 -4
- package/dist/react-permissions.mjs +4 -3
- package/dist/react.d.mts +4 -4
- package/dist/react.d.ts +4 -4
- package/dist/react.js +570 -41
- package/dist/react.mjs +19 -5
- package/dist/server/handlers.d.mts +56 -5
- package/dist/server/handlers.d.ts +56 -5
- package/dist/server/handlers.js +123 -8
- package/dist/server/handlers.mjs +3 -1
- package/dist/server.d.mts +28 -8
- package/dist/server.d.ts +28 -8
- package/dist/server.js +176 -14
- package/dist/server.mjs +9 -4
- package/dist/service.d.mts +3 -3
- package/dist/service.d.ts +3 -3
- package/dist/service.js +31 -5
- package/dist/service.mjs +1 -1
- package/dist/{signIn-T-CZ6t6r.d.mts → signIn-CReqfXsh.d.mts} +18 -1
- package/dist/{signIn-BLFnz8SV.d.ts → signIn-Cfa1GTpO.d.ts} +18 -1
- package/dist/{tokens-Bqhmqq_R.d.ts → tokens-9F6ETrzk.d.ts} +1 -1
- package/dist/{tokens-CITeoG6P.d.mts → tokens-B06VtvUi.d.mts} +1 -1
- package/dist/{types-XOV9XPVi.d.mts → types-Bn8O-OEd.d.mts} +66 -2
- package/dist/{types-XOV9XPVi.d.ts → types-Bn8O-OEd.d.ts} +66 -2
- package/dist/{types-BdQ2lqfT.d.mts → types-DnU2LhXR.d.mts} +6 -0
- package/dist/{types-BdQ2lqfT.d.ts → types-DnU2LhXR.d.ts} +6 -0
- package/dist/webhooks.d.mts +22 -9
- package/dist/webhooks.d.ts +22 -9
- package/dist/webhooks.js +27 -12
- package/dist/webhooks.mjs +1 -1
- package/dist/ws.d.mts +2 -2
- package/dist/ws.d.ts +2 -2
- package/docs/guides/invitations.md +65 -0
- package/package.json +7 -2
package/dist/server.js
CHANGED
|
@@ -35,6 +35,7 @@ __export(server_exports, {
|
|
|
35
35
|
ErrorCodes: () => ErrorCodes,
|
|
36
36
|
IQAuthClient: () => IQAuthClient,
|
|
37
37
|
IQAuthError: () => IQAuthError,
|
|
38
|
+
ProvisioningError: () => ProvisioningError,
|
|
38
39
|
ServerIQAuthClient: () => ServerIQAuthClient,
|
|
39
40
|
buildUserinfoResponse: () => buildUserinfoResponse,
|
|
40
41
|
createDrizzleLinkAdapter: () => createDrizzleLinkAdapter,
|
|
@@ -347,17 +348,27 @@ function parseLoginResponse(data, browserSessionMode) {
|
|
|
347
348
|
tenants: data.tenants
|
|
348
349
|
};
|
|
349
350
|
}
|
|
351
|
+
if (data.type === "scope_selection" && data.scopeSelectionToken && data.scopes && data.tenantId) {
|
|
352
|
+
return {
|
|
353
|
+
status: "scope_selection",
|
|
354
|
+
scopeSelectionToken: data.scopeSelectionToken,
|
|
355
|
+
tenantId: data.tenantId,
|
|
356
|
+
scopes: data.scopes
|
|
357
|
+
};
|
|
358
|
+
}
|
|
350
359
|
throw new Error("Unexpected login response shape");
|
|
351
360
|
}
|
|
352
361
|
var AuthModule = class {
|
|
353
362
|
constructor(http) {
|
|
354
363
|
this.http = http;
|
|
355
364
|
}
|
|
356
|
-
async login(email, password) {
|
|
365
|
+
async login(email, password, opts) {
|
|
366
|
+
const body = { email, password };
|
|
367
|
+
if (opts?.scopeHint) body.scopeHint = opts.scopeHint;
|
|
357
368
|
const data = await this.http.request(
|
|
358
369
|
"POST",
|
|
359
370
|
"/api/v1/auth/login",
|
|
360
|
-
|
|
371
|
+
body,
|
|
361
372
|
{ skipAutoRefresh: true }
|
|
362
373
|
);
|
|
363
374
|
return parseLoginResponse(data, this.http.isBrowserSession());
|
|
@@ -395,13 +406,29 @@ var AuthModule = class {
|
|
|
395
406
|
method
|
|
396
407
|
}, { skipAutoRefresh: true });
|
|
397
408
|
}
|
|
398
|
-
async selectTenant(tenantSelectionToken, tenantId) {
|
|
409
|
+
async selectTenant(tenantSelectionToken, tenantId, opts) {
|
|
410
|
+
const body = { tenantSelectionToken, tenantId };
|
|
411
|
+
if (opts?.scopeHint) body.scopeHint = opts.scopeHint;
|
|
399
412
|
const data = await this.http.request(
|
|
400
413
|
"POST",
|
|
401
414
|
"/api/v1/auth/select-tenant",
|
|
415
|
+
body,
|
|
416
|
+
{ skipAutoRefresh: true }
|
|
417
|
+
);
|
|
418
|
+
return parseLoginResponse(data, this.http.isBrowserSession());
|
|
419
|
+
}
|
|
420
|
+
/**
|
|
421
|
+
* Task #171 — redeem a scope-selection token + chosen membership for a
|
|
422
|
+
* real authenticated session. `membershipId` must be one of the scopes
|
|
423
|
+
* returned in the prior `scope_selection` envelope.
|
|
424
|
+
*/
|
|
425
|
+
async selectScope(scopeSelectionToken, membershipId) {
|
|
426
|
+
const data = await this.http.request(
|
|
427
|
+
"POST",
|
|
428
|
+
"/api/v1/auth/select-scope",
|
|
402
429
|
{
|
|
403
|
-
|
|
404
|
-
|
|
430
|
+
scopeSelectionToken,
|
|
431
|
+
membershipId
|
|
405
432
|
},
|
|
406
433
|
{ skipAutoRefresh: true }
|
|
407
434
|
);
|
|
@@ -2240,7 +2267,11 @@ async function buildUserinfoResponse(claims, opts = {}) {
|
|
|
2240
2267
|
tenantId: claims.tenantId,
|
|
2241
2268
|
vendorId: claims.vendorId,
|
|
2242
2269
|
roles: claims.roles ?? [],
|
|
2243
|
-
entitlements: claims.entitlements ?? []
|
|
2270
|
+
entitlements: claims.entitlements ?? [],
|
|
2271
|
+
// Task #171 — project the active source/client scope onto the userinfo
|
|
2272
|
+
// payload so server handlers (`getSessionUser`, `/api/iqauth/userinfo`)
|
|
2273
|
+
// expose it without consumers having to re-decode the JWT.
|
|
2274
|
+
...claims.scopeContext !== void 0 ? { scopeContext: claims.scopeContext } : {}
|
|
2244
2275
|
};
|
|
2245
2276
|
const enriched = opts.enrich ? await opts.enrich(claims) : null;
|
|
2246
2277
|
const user = enriched ? { ...baseUser, ...enriched } : baseUser;
|
|
@@ -2285,19 +2316,62 @@ function shouldClearCookiesOnFailure(policy, status, errorCode) {
|
|
|
2285
2316
|
}
|
|
2286
2317
|
var ACCESS_TOKEN_TTL_SECONDS = 60 * 15;
|
|
2287
2318
|
var REFRESH_TOKEN_TTL_SECONDS = 60 * 60 * 24 * 30;
|
|
2319
|
+
function assertCookiePrefixInvariants(name, secure, path, domain) {
|
|
2320
|
+
if (name.startsWith("__Host-")) {
|
|
2321
|
+
if (!secure) {
|
|
2322
|
+
throw new IQAuthError(
|
|
2323
|
+
"config_invalid",
|
|
2324
|
+
`Cookie "${name}" uses the __Host- prefix, which browsers only accept on a Secure cookie. Set secure:true (and serve over HTTPS).`
|
|
2325
|
+
);
|
|
2326
|
+
}
|
|
2327
|
+
if (path !== "/") {
|
|
2328
|
+
throw new IQAuthError(
|
|
2329
|
+
"config_invalid",
|
|
2330
|
+
`Cookie "${name}" uses the __Host- prefix, which requires Path=/ (got "${path}"). Remove cookiePath or set it to "/".`
|
|
2331
|
+
);
|
|
2332
|
+
}
|
|
2333
|
+
if (domain) {
|
|
2334
|
+
throw new IQAuthError(
|
|
2335
|
+
"config_invalid",
|
|
2336
|
+
`Cookie "${name}" uses the __Host- prefix, which forbids a Domain attribute (the cookie is host-locked). Remove cookieDomain.`
|
|
2337
|
+
);
|
|
2338
|
+
}
|
|
2339
|
+
} else if (name.startsWith("__Secure-") && !secure) {
|
|
2340
|
+
throw new IQAuthError(
|
|
2341
|
+
"config_invalid",
|
|
2342
|
+
`Cookie "${name}" uses the __Secure- prefix, which browsers only accept on a Secure cookie. Set secure:true (and serve over HTTPS).`
|
|
2343
|
+
);
|
|
2344
|
+
}
|
|
2345
|
+
}
|
|
2288
2346
|
function resolve(config) {
|
|
2289
2347
|
const parsed = assertPublishableKey(config.publishableKey, { context: "@iqauth/sdk helpers" });
|
|
2290
2348
|
const inferredIssuer = parsed.iss.startsWith("http") ? parsed.iss : `https://${parsed.iss}`;
|
|
2349
|
+
maybeWarnDefaultSignoutRegistry(config);
|
|
2350
|
+
const secure = config.secure ?? true;
|
|
2351
|
+
if (config.secure === false && config.allowInsecureCookies !== true) {
|
|
2352
|
+
throw new IQAuthError(
|
|
2353
|
+
"config_invalid",
|
|
2354
|
+
"Refusing to issue auth cookies with secure:false \u2014 this exposes session cookies over plaintext HTTP. For local HTTP development, set allowInsecureCookies:true to acknowledge the risk. Production MUST use HTTPS with secure cookies."
|
|
2355
|
+
);
|
|
2356
|
+
}
|
|
2357
|
+
const accessCookieName = config.accessCookieName ?? config.cookieNames?.access ?? "iqauth_at";
|
|
2358
|
+
const refreshCookieName = config.refreshCookieName ?? config.cookieNames?.refresh ?? "iqauth_rt";
|
|
2359
|
+
const stateCookieName = config.stateCookieName ?? "iqauth_state";
|
|
2360
|
+
const cookiePath = config.cookiePath ?? "/";
|
|
2361
|
+
const cookieDomain = config.cookieDomain;
|
|
2362
|
+
for (const name of [accessCookieName, refreshCookieName, stateCookieName]) {
|
|
2363
|
+
assertCookiePrefixInvariants(name, secure, cookiePath, cookieDomain);
|
|
2364
|
+
}
|
|
2291
2365
|
return {
|
|
2292
2366
|
publishableKey: config.publishableKey,
|
|
2293
2367
|
secretKey: config.secretKey,
|
|
2294
2368
|
issuer: (config.issuer ?? inferredIssuer).replace(/\/+$/, ""),
|
|
2295
|
-
accessCookieName
|
|
2296
|
-
refreshCookieName
|
|
2297
|
-
cookieDomain
|
|
2369
|
+
accessCookieName,
|
|
2370
|
+
refreshCookieName,
|
|
2371
|
+
cookieDomain,
|
|
2298
2372
|
sameSite: config.sameSite ?? "lax",
|
|
2299
|
-
secure
|
|
2300
|
-
cookiePath
|
|
2373
|
+
secure,
|
|
2374
|
+
cookiePath,
|
|
2301
2375
|
tokenPath: config.tokenPath ?? "/oidc/token",
|
|
2302
2376
|
refreshPath: config.refreshPath ?? "/api/v1/auth/refresh",
|
|
2303
2377
|
logoutPath: config.logoutPath ?? "/api/v1/auth/logout",
|
|
@@ -2310,9 +2384,19 @@ function resolve(config) {
|
|
|
2310
2384
|
debug: config.debug,
|
|
2311
2385
|
onTimingEvent: config.onTimingEvent,
|
|
2312
2386
|
signoutRegistry: config.signoutRegistry ?? defaultSignoutRegistry,
|
|
2313
|
-
signoutMarkerTtlMs: config.signoutMarkerTtlMs ?? DEFAULT_SIGNOUT_TTL_MS
|
|
2387
|
+
signoutMarkerTtlMs: config.signoutMarkerTtlMs ?? DEFAULT_SIGNOUT_TTL_MS,
|
|
2388
|
+
requireOAuthState: config.requireOAuthState ?? true,
|
|
2389
|
+
stateCookieName: config.stateCookieName ?? "iqauth_state"
|
|
2314
2390
|
};
|
|
2315
2391
|
}
|
|
2392
|
+
function timingSafeEqualStr(a, b) {
|
|
2393
|
+
const len = Math.max(a.length, b.length);
|
|
2394
|
+
let diff = a.length ^ b.length;
|
|
2395
|
+
for (let i = 0; i < len; i++) {
|
|
2396
|
+
diff |= (a.charCodeAt(i) || 0) ^ (b.charCodeAt(i) || 0);
|
|
2397
|
+
}
|
|
2398
|
+
return diff === 0;
|
|
2399
|
+
}
|
|
2316
2400
|
function makeCookie(cfg, name, value, maxAge, httpOnly = true) {
|
|
2317
2401
|
return {
|
|
2318
2402
|
name,
|
|
@@ -2331,6 +2415,9 @@ function clearCookies(cfg) {
|
|
|
2331
2415
|
{ ...makeCookie(cfg, cfg.refreshCookieName, "", 0), clear: true }
|
|
2332
2416
|
];
|
|
2333
2417
|
}
|
|
2418
|
+
function clearStateCookie(cfg) {
|
|
2419
|
+
return { ...makeCookie(cfg, cfg.stateCookieName, "", 0, false), clear: true };
|
|
2420
|
+
}
|
|
2334
2421
|
var DEFAULT_SIGNOUT_TTL_MS = 6e4;
|
|
2335
2422
|
var inMemorySignoutMarkers = /* @__PURE__ */ new Map();
|
|
2336
2423
|
function pruneInMemoryMarkers(now) {
|
|
@@ -2356,6 +2443,15 @@ var defaultSignoutRegistry = {
|
|
|
2356
2443
|
return true;
|
|
2357
2444
|
}
|
|
2358
2445
|
};
|
|
2446
|
+
var warnedDefaultSignoutRegistry = false;
|
|
2447
|
+
function maybeWarnDefaultSignoutRegistry(config) {
|
|
2448
|
+
if (warnedDefaultSignoutRegistry) return;
|
|
2449
|
+
if (config.signoutRegistry) return;
|
|
2450
|
+
warnedDefaultSignoutRegistry = true;
|
|
2451
|
+
console.warn(
|
|
2452
|
+
"[IQAuth] Using the in-memory signout registry (process-local). Signout idempotency is NOT shared across instances \u2014 in a multi-replica deployment a /refresh racing a /signout on another replica can reissue cookies after sign-out. Plug a shared backend (e.g. Redis) into IQAuthHelperConfig.signoutRegistry to fix this and silence this warning."
|
|
2453
|
+
);
|
|
2454
|
+
}
|
|
2359
2455
|
function serializeCookie(d) {
|
|
2360
2456
|
const parts = [`${d.name}=${encodeURIComponent(d.value)}`];
|
|
2361
2457
|
parts.push(`Path=${d.path}`);
|
|
@@ -2378,6 +2474,23 @@ async function handleCallback(config, input) {
|
|
|
2378
2474
|
cookies: []
|
|
2379
2475
|
};
|
|
2380
2476
|
}
|
|
2477
|
+
const provided = input.state;
|
|
2478
|
+
const expected = input.expectedState;
|
|
2479
|
+
const stateOk = cfg.requireOAuthState ? !!expected && !!provided && timingSafeEqualStr(provided, expected) : !expected || !!provided && timingSafeEqualStr(provided, expected);
|
|
2480
|
+
if (!stateOk) {
|
|
2481
|
+
emitTiming(cfg, { phase: "callback", durationMs: Date.now() - t0, ok: false, code: "STATE_MISMATCH" });
|
|
2482
|
+
return {
|
|
2483
|
+
status: 400,
|
|
2484
|
+
body: {
|
|
2485
|
+
success: false,
|
|
2486
|
+
error: {
|
|
2487
|
+
code: "STATE_MISMATCH",
|
|
2488
|
+
message: "OAuth state validation failed; the sign-in could not be verified as originating from this browser."
|
|
2489
|
+
}
|
|
2490
|
+
},
|
|
2491
|
+
cookies: [clearStateCookie(cfg)]
|
|
2492
|
+
};
|
|
2493
|
+
}
|
|
2381
2494
|
if (!cfg.secretKey) {
|
|
2382
2495
|
emitTiming(cfg, { phase: "callback", durationMs: Date.now() - t0, ok: false, code: "INTERNAL_ERROR" });
|
|
2383
2496
|
return {
|
|
@@ -2416,6 +2529,26 @@ async function handleCallback(config, input) {
|
|
|
2416
2529
|
cookies: []
|
|
2417
2530
|
};
|
|
2418
2531
|
}
|
|
2532
|
+
try {
|
|
2533
|
+
await getTokensFor(cfg.issuer).verify(json.access_token, {
|
|
2534
|
+
issuer: cfg.issuer,
|
|
2535
|
+
...config.verify
|
|
2536
|
+
});
|
|
2537
|
+
} catch (err) {
|
|
2538
|
+
const code = err instanceof IQAuthError ? err.code : err.code || "TOKEN_INVALID";
|
|
2539
|
+
emitTiming(cfg, { phase: "callback", durationMs: Date.now() - t0, ok: false, code });
|
|
2540
|
+
return {
|
|
2541
|
+
status: 502,
|
|
2542
|
+
body: {
|
|
2543
|
+
success: false,
|
|
2544
|
+
error: {
|
|
2545
|
+
code: "ACCESS_TOKEN_VERIFICATION_FAILED",
|
|
2546
|
+
message: "The issuer returned an access token that failed verification; no session was established."
|
|
2547
|
+
}
|
|
2548
|
+
},
|
|
2549
|
+
cookies: []
|
|
2550
|
+
};
|
|
2551
|
+
}
|
|
2419
2552
|
const cookies = [];
|
|
2420
2553
|
cookies.push(
|
|
2421
2554
|
makeCookie(cfg, cfg.accessCookieName, json.access_token, json.expires_in ?? ACCESS_TOKEN_TTL_SECONDS)
|
|
@@ -2423,6 +2556,7 @@ async function handleCallback(config, input) {
|
|
|
2423
2556
|
if (json.refresh_token) {
|
|
2424
2557
|
cookies.push(makeCookie(cfg, cfg.refreshCookieName, json.refresh_token, REFRESH_TOKEN_TTL_SECONDS));
|
|
2425
2558
|
}
|
|
2559
|
+
cookies.push(clearStateCookie(cfg));
|
|
2426
2560
|
emitTiming(cfg, { phase: "callback", durationMs: Date.now() - t0, ok: true });
|
|
2427
2561
|
return {
|
|
2428
2562
|
status: 200,
|
|
@@ -2544,7 +2678,10 @@ async function handleUserinfo(config, input) {
|
|
|
2544
2678
|
}
|
|
2545
2679
|
let claims;
|
|
2546
2680
|
try {
|
|
2547
|
-
claims = await getTokensFor(cfg.issuer).verify(input.accessToken,
|
|
2681
|
+
claims = await getTokensFor(cfg.issuer).verify(input.accessToken, {
|
|
2682
|
+
issuer: cfg.issuer,
|
|
2683
|
+
...config.verify
|
|
2684
|
+
});
|
|
2548
2685
|
} catch (err) {
|
|
2549
2686
|
const code = err instanceof IQAuthError ? err.code : err.code || "TOKEN_INVALID";
|
|
2550
2687
|
const message = err instanceof Error ? err.message : "Access token verification failed";
|
|
@@ -2565,6 +2702,13 @@ async function handleUserinfo(config, input) {
|
|
|
2565
2702
|
}
|
|
2566
2703
|
|
|
2567
2704
|
// src/server/provisioningBridge.ts
|
|
2705
|
+
var ProvisioningError = class extends Error {
|
|
2706
|
+
constructor(code, message) {
|
|
2707
|
+
super(message);
|
|
2708
|
+
this.name = "ProvisioningError";
|
|
2709
|
+
this.code = code;
|
|
2710
|
+
}
|
|
2711
|
+
};
|
|
2568
2712
|
function defaultIsUniqueViolation(err) {
|
|
2569
2713
|
if (!err || typeof err !== "object") return false;
|
|
2570
2714
|
const e = err;
|
|
@@ -2576,6 +2720,16 @@ function defaultIsUniqueViolation(err) {
|
|
|
2576
2720
|
function createProvisioningBridge(options) {
|
|
2577
2721
|
const { storage } = options;
|
|
2578
2722
|
const isUniqueViolation = options.isUniqueViolation ?? defaultIsUniqueViolation;
|
|
2723
|
+
const allowUnverifiedEmailAdopt = options.allowUnverifiedEmailAdopt === true;
|
|
2724
|
+
const emailVerified = (claims) => claims.email_verified === true;
|
|
2725
|
+
const assertAdoptAllowed = (claims) => {
|
|
2726
|
+
if (!allowUnverifiedEmailAdopt && !emailVerified(claims)) {
|
|
2727
|
+
throw new ProvisioningError(
|
|
2728
|
+
"UNVERIFIED_EMAIL_ADOPT_REFUSED",
|
|
2729
|
+
"Refusing to adopt a pre-existing local account from an unverified email (claims.email_verified !== true). Set allowUnverifiedEmailAdopt:true only if your issuer is trusted to never emit unverified emails for adoption."
|
|
2730
|
+
);
|
|
2731
|
+
}
|
|
2732
|
+
};
|
|
2579
2733
|
const roleOf = (claims) => {
|
|
2580
2734
|
try {
|
|
2581
2735
|
return options.roleMapper?.(claims) ?? null;
|
|
@@ -2592,6 +2746,7 @@ function createProvisioningBridge(options) {
|
|
|
2592
2746
|
if (claims.email) {
|
|
2593
2747
|
const byEmail = await storage.findByEmail(claims.email);
|
|
2594
2748
|
if (byEmail) {
|
|
2749
|
+
assertAdoptAllowed(claims);
|
|
2595
2750
|
if (storage.adoptByEmail) {
|
|
2596
2751
|
const adopted = await storage.adoptByEmail(byEmail, claims, roleOf(claims));
|
|
2597
2752
|
return { user: adopted, claims, created: false, adopted: true };
|
|
@@ -2607,7 +2762,10 @@ function createProvisioningBridge(options) {
|
|
|
2607
2762
|
if (after) return { user: after, claims, created: false, adopted: false };
|
|
2608
2763
|
if (claims.email) {
|
|
2609
2764
|
const byEmail = await storage.findByEmail(claims.email);
|
|
2610
|
-
if (byEmail)
|
|
2765
|
+
if (byEmail) {
|
|
2766
|
+
assertAdoptAllowed(claims);
|
|
2767
|
+
return { user: byEmail, claims, created: false, adopted: true };
|
|
2768
|
+
}
|
|
2611
2769
|
}
|
|
2612
2770
|
throw err;
|
|
2613
2771
|
}
|
|
@@ -2639,6 +2797,9 @@ async function linkLocalUserToIqAuthSub(options) {
|
|
|
2639
2797
|
if (row.iqauthSub === claims.sub) {
|
|
2640
2798
|
return { status: "already_linked", userId: row.id };
|
|
2641
2799
|
}
|
|
2800
|
+
if (claims.email_verified !== true && options.allowUnverifiedEmail !== true) {
|
|
2801
|
+
return { status: "conflict", userId: row.id, reason: "unverified_email" };
|
|
2802
|
+
}
|
|
2642
2803
|
const wrote = await tx.setIqAuthSub(row.id, claims.sub);
|
|
2643
2804
|
if (wrote === false) {
|
|
2644
2805
|
return { status: "conflict", userId: row.id, reason: "different_sub" };
|
|
@@ -2710,6 +2871,7 @@ function createServerClient(config) {
|
|
|
2710
2871
|
ErrorCodes,
|
|
2711
2872
|
IQAuthClient,
|
|
2712
2873
|
IQAuthError,
|
|
2874
|
+
ProvisioningError,
|
|
2713
2875
|
ServerIQAuthClient,
|
|
2714
2876
|
buildUserinfoResponse,
|
|
2715
2877
|
createDrizzleLinkAdapter,
|
package/dist/server.mjs
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
|
+
ProvisioningError,
|
|
2
3
|
createProvisioningBridge
|
|
3
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-CIJORODR.mjs";
|
|
4
5
|
import {
|
|
5
6
|
DEFAULT_ACCESS_COOKIE,
|
|
6
7
|
DEFAULT_REFRESH_COOKIE,
|
|
7
8
|
iqAuthMiddleware
|
|
8
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-25SSYDIP.mjs";
|
|
9
10
|
import {
|
|
10
11
|
buildUserinfoResponse,
|
|
11
12
|
handleCallback,
|
|
@@ -13,11 +14,11 @@ import {
|
|
|
13
14
|
handleSignout,
|
|
14
15
|
handleUserinfo,
|
|
15
16
|
serializeCookie
|
|
16
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-WSH4SW7F.mjs";
|
|
17
18
|
import "./chunk-HVHNYPDC.mjs";
|
|
18
19
|
import {
|
|
19
20
|
IQAuthClient
|
|
20
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-ZLJPABB7.mjs";
|
|
21
22
|
import "./chunk-NUO2I65G.mjs";
|
|
22
23
|
import {
|
|
23
24
|
ErrorCodes,
|
|
@@ -49,6 +50,9 @@ async function linkLocalUserToIqAuthSub(options) {
|
|
|
49
50
|
if (row.iqauthSub === claims.sub) {
|
|
50
51
|
return { status: "already_linked", userId: row.id };
|
|
51
52
|
}
|
|
53
|
+
if (claims.email_verified !== true && options.allowUnverifiedEmail !== true) {
|
|
54
|
+
return { status: "conflict", userId: row.id, reason: "unverified_email" };
|
|
55
|
+
}
|
|
52
56
|
const wrote = await tx.setIqAuthSub(row.id, claims.sub);
|
|
53
57
|
if (wrote === false) {
|
|
54
58
|
return { status: "conflict", userId: row.id, reason: "different_sub" };
|
|
@@ -119,6 +123,7 @@ export {
|
|
|
119
123
|
ErrorCodes,
|
|
120
124
|
IQAuthClient,
|
|
121
125
|
IQAuthError,
|
|
126
|
+
ProvisioningError,
|
|
122
127
|
ServerIQAuthClient,
|
|
123
128
|
buildUserinfoResponse,
|
|
124
129
|
createDrizzleLinkAdapter,
|
package/dist/service.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { I as IQAuthClient } from './client-
|
|
2
|
-
import { f as IQAuthTokenClientConfig } from './types-
|
|
1
|
+
import { I as IQAuthClient } from './client-D8L-PaWr.mjs';
|
|
2
|
+
import { f as IQAuthTokenClientConfig } from './types-Bn8O-OEd.mjs';
|
|
3
3
|
export { E as ErrorCodes, I as IQAuthError } from './errors-Jl1Jtm-6.mjs';
|
|
4
|
-
import './tokens-
|
|
4
|
+
import './tokens-B06VtvUi.mjs';
|
|
5
5
|
|
|
6
6
|
declare class ServiceIQAuthClient extends IQAuthClient {
|
|
7
7
|
constructor(config: IQAuthTokenClientConfig);
|
package/dist/service.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { I as IQAuthClient } from './client-
|
|
2
|
-
import { f as IQAuthTokenClientConfig } from './types-
|
|
1
|
+
import { I as IQAuthClient } from './client-DkPL0EPZ.js';
|
|
2
|
+
import { f as IQAuthTokenClientConfig } from './types-Bn8O-OEd.js';
|
|
3
3
|
export { E as ErrorCodes, I as IQAuthError } from './errors-Jl1Jtm-6.js';
|
|
4
|
-
import './tokens-
|
|
4
|
+
import './tokens-9F6ETrzk.js';
|
|
5
5
|
|
|
6
6
|
declare class ServiceIQAuthClient extends IQAuthClient {
|
|
7
7
|
constructor(config: IQAuthTokenClientConfig);
|
package/dist/service.js
CHANGED
|
@@ -335,17 +335,27 @@ function parseLoginResponse(data, browserSessionMode) {
|
|
|
335
335
|
tenants: data.tenants
|
|
336
336
|
};
|
|
337
337
|
}
|
|
338
|
+
if (data.type === "scope_selection" && data.scopeSelectionToken && data.scopes && data.tenantId) {
|
|
339
|
+
return {
|
|
340
|
+
status: "scope_selection",
|
|
341
|
+
scopeSelectionToken: data.scopeSelectionToken,
|
|
342
|
+
tenantId: data.tenantId,
|
|
343
|
+
scopes: data.scopes
|
|
344
|
+
};
|
|
345
|
+
}
|
|
338
346
|
throw new Error("Unexpected login response shape");
|
|
339
347
|
}
|
|
340
348
|
var AuthModule = class {
|
|
341
349
|
constructor(http) {
|
|
342
350
|
this.http = http;
|
|
343
351
|
}
|
|
344
|
-
async login(email, password) {
|
|
352
|
+
async login(email, password, opts) {
|
|
353
|
+
const body = { email, password };
|
|
354
|
+
if (opts?.scopeHint) body.scopeHint = opts.scopeHint;
|
|
345
355
|
const data = await this.http.request(
|
|
346
356
|
"POST",
|
|
347
357
|
"/api/v1/auth/login",
|
|
348
|
-
|
|
358
|
+
body,
|
|
349
359
|
{ skipAutoRefresh: true }
|
|
350
360
|
);
|
|
351
361
|
return parseLoginResponse(data, this.http.isBrowserSession());
|
|
@@ -383,13 +393,29 @@ var AuthModule = class {
|
|
|
383
393
|
method
|
|
384
394
|
}, { skipAutoRefresh: true });
|
|
385
395
|
}
|
|
386
|
-
async selectTenant(tenantSelectionToken, tenantId) {
|
|
396
|
+
async selectTenant(tenantSelectionToken, tenantId, opts) {
|
|
397
|
+
const body = { tenantSelectionToken, tenantId };
|
|
398
|
+
if (opts?.scopeHint) body.scopeHint = opts.scopeHint;
|
|
387
399
|
const data = await this.http.request(
|
|
388
400
|
"POST",
|
|
389
401
|
"/api/v1/auth/select-tenant",
|
|
402
|
+
body,
|
|
403
|
+
{ skipAutoRefresh: true }
|
|
404
|
+
);
|
|
405
|
+
return parseLoginResponse(data, this.http.isBrowserSession());
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* Task #171 — redeem a scope-selection token + chosen membership for a
|
|
409
|
+
* real authenticated session. `membershipId` must be one of the scopes
|
|
410
|
+
* returned in the prior `scope_selection` envelope.
|
|
411
|
+
*/
|
|
412
|
+
async selectScope(scopeSelectionToken, membershipId) {
|
|
413
|
+
const data = await this.http.request(
|
|
414
|
+
"POST",
|
|
415
|
+
"/api/v1/auth/select-scope",
|
|
390
416
|
{
|
|
391
|
-
|
|
392
|
-
|
|
417
|
+
scopeSelectionToken,
|
|
418
|
+
membershipId
|
|
393
419
|
},
|
|
394
420
|
{ skipAutoRefresh: true }
|
|
395
421
|
);
|
package/dist/service.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { c as ParsedPublishableKey } from './publishableKey-f2kq-rKw.mjs';
|
|
2
|
-
import { J as JwtClaims, S as SessionUser } from './types-
|
|
2
|
+
import { J as JwtClaims, S as SessionUser } from './types-Bn8O-OEd.mjs';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* SessionManager — core browser-side session state.
|
|
@@ -253,6 +253,23 @@ declare class SessionManager {
|
|
|
253
253
|
* session and notify subscribers and other tabs.
|
|
254
254
|
*/
|
|
255
255
|
applyAccessToken(accessToken: string, refreshToken?: string): void;
|
|
256
|
+
/**
|
|
257
|
+
* Task #197 — Adopt an access token that the server has already minted
|
|
258
|
+
* for us (e.g. from `POST /api/v1/auth/switch-scope`) without contacting
|
|
259
|
+
* the issuer. Swaps the in-memory token, re-decodes claims, bumps
|
|
260
|
+
* `version`, schedules proactive refresh, and broadcasts a
|
|
261
|
+
* `session:update` to peer tabs.
|
|
262
|
+
*
|
|
263
|
+
* This is the safe path for any server endpoint that returns a fresh
|
|
264
|
+
* access token in its JSON body: we want the new claims (scope, roles,
|
|
265
|
+
* etc.) to take effect immediately, even if the refresh-cookie round-trip
|
|
266
|
+
* would have failed (network blip, rate limit, signout race). When the
|
|
267
|
+
* server also rotated the refresh token, pass it via
|
|
268
|
+
* `opts.refreshToken` so the cookie stays aligned.
|
|
269
|
+
*/
|
|
270
|
+
adoptAccessToken(accessToken: string, opts?: {
|
|
271
|
+
refreshToken?: string;
|
|
272
|
+
}): void;
|
|
256
273
|
/**
|
|
257
274
|
* Returns a valid access token, refreshing once if it is expired or about
|
|
258
275
|
* to expire. Resolves to `null` if the session can no longer be revived.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { c as ParsedPublishableKey } from './publishableKey-f2kq-rKw.js';
|
|
2
|
-
import { J as JwtClaims, S as SessionUser } from './types-
|
|
2
|
+
import { J as JwtClaims, S as SessionUser } from './types-Bn8O-OEd.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* SessionManager — core browser-side session state.
|
|
@@ -253,6 +253,23 @@ declare class SessionManager {
|
|
|
253
253
|
* session and notify subscribers and other tabs.
|
|
254
254
|
*/
|
|
255
255
|
applyAccessToken(accessToken: string, refreshToken?: string): void;
|
|
256
|
+
/**
|
|
257
|
+
* Task #197 — Adopt an access token that the server has already minted
|
|
258
|
+
* for us (e.g. from `POST /api/v1/auth/switch-scope`) without contacting
|
|
259
|
+
* the issuer. Swaps the in-memory token, re-decodes claims, bumps
|
|
260
|
+
* `version`, schedules proactive refresh, and broadcasts a
|
|
261
|
+
* `session:update` to peer tabs.
|
|
262
|
+
*
|
|
263
|
+
* This is the safe path for any server endpoint that returns a fresh
|
|
264
|
+
* access token in its JSON body: we want the new claims (scope, roles,
|
|
265
|
+
* etc.) to take effect immediately, even if the refresh-cookie round-trip
|
|
266
|
+
* would have failed (network blip, rate limit, signout race). When the
|
|
267
|
+
* server also rotated the refresh token, pass it via
|
|
268
|
+
* `opts.refreshToken` so the cookie stays aligned.
|
|
269
|
+
*/
|
|
270
|
+
adoptAccessToken(accessToken: string, opts?: {
|
|
271
|
+
refreshToken?: string;
|
|
272
|
+
}): void;
|
|
256
273
|
/**
|
|
257
274
|
* Returns a valid access token, refreshing once if it is expired or about
|
|
258
275
|
* to expire. Resolves to `null` if the session can no longer be revived.
|
|
@@ -176,6 +176,14 @@ interface SessionUser {
|
|
|
176
176
|
givenName?: string;
|
|
177
177
|
familyName?: string;
|
|
178
178
|
locale?: string;
|
|
179
|
+
/**
|
|
180
|
+
* Task #171 — When the active session was minted under a source/client
|
|
181
|
+
* scope (either via a scope_hint, single-resolved scope, or post-pick),
|
|
182
|
+
* the access token carries a `scopeContext` claim and we project it here
|
|
183
|
+
* so SDK consumers (`useUser()`, framework adapters) can read the active
|
|
184
|
+
* scope without re-parsing the JWT. Absent for tenant-wide sessions.
|
|
185
|
+
*/
|
|
186
|
+
scopeContext?: ScopeContext;
|
|
179
187
|
}
|
|
180
188
|
interface Tenant {
|
|
181
189
|
tenantId: string;
|
|
@@ -201,6 +209,24 @@ interface SessionAuthenticatedLoginResult {
|
|
|
201
209
|
authMode: "session";
|
|
202
210
|
user: SessionUser;
|
|
203
211
|
}
|
|
212
|
+
/**
|
|
213
|
+
* Task #171 — A user can have multiple source/client scoped memberships in
|
|
214
|
+
* the same tenant with no tenant-wide role. When login resolves to that
|
|
215
|
+
* state the backend returns a short-lived `scopeSelectionToken` plus the
|
|
216
|
+
* list of choices; the caller redeems it via `AuthModule.selectScope`.
|
|
217
|
+
*/
|
|
218
|
+
interface ScopeChoice {
|
|
219
|
+
membershipId: string;
|
|
220
|
+
scopeType: "vendor" | "source" | "client";
|
|
221
|
+
scopeId: string;
|
|
222
|
+
scopeName: string;
|
|
223
|
+
roleName: string;
|
|
224
|
+
}
|
|
225
|
+
/** Task #171 — Optional hint forwarded with login / select-tenant / OIDC. */
|
|
226
|
+
interface ScopeHint {
|
|
227
|
+
type: "vendor" | "source" | "client";
|
|
228
|
+
id: string;
|
|
229
|
+
}
|
|
204
230
|
type LoginResult = TokenAuthenticatedLoginResult | SessionAuthenticatedLoginResult | {
|
|
205
231
|
status: "mfa_required";
|
|
206
232
|
mfaChallengeToken: string;
|
|
@@ -209,6 +235,11 @@ type LoginResult = TokenAuthenticatedLoginResult | SessionAuthenticatedLoginResu
|
|
|
209
235
|
status: "tenant_selection";
|
|
210
236
|
tenantSelectionToken: string;
|
|
211
237
|
tenants: Tenant[];
|
|
238
|
+
} | {
|
|
239
|
+
status: "scope_selection";
|
|
240
|
+
scopeSelectionToken: string;
|
|
241
|
+
tenantId: string;
|
|
242
|
+
scopes: ScopeChoice[];
|
|
212
243
|
};
|
|
213
244
|
interface Session {
|
|
214
245
|
id: string;
|
|
@@ -718,13 +749,46 @@ interface Invitation {
|
|
|
718
749
|
invitedBy: string;
|
|
719
750
|
expiresAt?: string;
|
|
720
751
|
createdAt?: string;
|
|
752
|
+
/** Scope the invite grants into ("tenant" | "vendor" | "source" | "client"). */
|
|
753
|
+
scopeType?: string | null;
|
|
754
|
+
/** Scope target id (paired with `scopeType`). */
|
|
755
|
+
scopeId?: string | null;
|
|
756
|
+
/** OIDC client bound for post-accept auto-redirect (paired with `redirectUri`). */
|
|
757
|
+
clientId?: string | null;
|
|
758
|
+
/** Registered redirect URI the new invitee is sent to after account creation. */
|
|
759
|
+
redirectUri?: string | null;
|
|
760
|
+
/** Display name pre-filled on the hosted accept page. */
|
|
761
|
+
inviteeName?: string | null;
|
|
721
762
|
}
|
|
722
763
|
interface CreateInviteRequest {
|
|
723
764
|
email: string;
|
|
724
|
-
|
|
765
|
+
/**
|
|
766
|
+
* Target tenant. Optional for service (API-key) callers — the backend
|
|
767
|
+
* derives the tenant from the key and rejects a mismatching value. Platform
|
|
768
|
+
* admins may target any tenant.
|
|
769
|
+
*/
|
|
770
|
+
tenantId?: string;
|
|
725
771
|
vendorId?: string;
|
|
726
772
|
role: string;
|
|
727
773
|
products?: string[];
|
|
774
|
+
/** Scope to grant into. Must match the backend's accepted values. */
|
|
775
|
+
scopeType?: "tenant" | "vendor" | "source" | "client";
|
|
776
|
+
/** Scope target id (paired with `scopeType`). */
|
|
777
|
+
scopeId?: string;
|
|
778
|
+
/**
|
|
779
|
+
* Opt-in auto-redirect after the invitee creates their account. `clientId`
|
|
780
|
+
* and `redirectUri` are all-or-nothing — pass both or neither. The backend
|
|
781
|
+
* validates that `clientId` is an active OIDC client in the invite's tenant
|
|
782
|
+
* and that `redirectUri` is in that client's registered allowlist, then mints
|
|
783
|
+
* an OIDC authorization code and 302s the brand-new invitee to
|
|
784
|
+
* `${redirectUri}?code=…&state=…`. Point this at your app's
|
|
785
|
+
* `/api/iqauth/callback` so the framework adapter signs the user in on first
|
|
786
|
+
* paint. Existing-user accepts do NOT auto-redirect (see the integration guide).
|
|
787
|
+
*/
|
|
788
|
+
clientId?: string;
|
|
789
|
+
redirectUri?: string;
|
|
790
|
+
/** Optional display name to pre-fill on the hosted accept page. Never used for auth. */
|
|
791
|
+
inviteeName?: string;
|
|
728
792
|
}
|
|
729
793
|
interface InviteValidation {
|
|
730
794
|
valid: boolean;
|
|
@@ -992,4 +1056,4 @@ interface BackupCodeCountResult {
|
|
|
992
1056
|
remainingBackupCodes: number;
|
|
993
1057
|
}
|
|
994
1058
|
|
|
995
|
-
export type { AppManifest as $, ApiSuccessResponse as A, BrandingConfig as B, CreateTenantRequest as C, ApiErrorResponse as D, ApiResponse as E, MfaMethod as F, MfaEnrollment as G, TotpEnrollmentResult as H, IQAuthBrowserSessionClientConfig as I, JwtClaims as J, MfaVerifyResult as K, LoginResult as L, MigrateUserRequest as M, PasswordPolicy as N, OidcDiscovery as O, PromoteToVendorRequest as P, MfaPolicy as Q, UserPermissions as R, SessionUser as S, TokenPair as T, UserProfile as U, ProvisionUserRequest as V, ProvisionUserResponse as W, ExpressMiddlewareOptions as X, IQAuthRetryConfig as Y, IQAuthVerifyConfig as Z, PermissionNodeManifest as _, IQAuthRequestLike as a, BackupCodesResult as a$, AppInfo as a0, PermissionNodeInfo as a1, AppSyncResult as a2, Role as a3, CreateRoleRequest as a4, UpdateRoleRequest as a5, AssignRoleRequest as a6, UserRoleAssignment as a7, UserGroupAssignment as a8, TenantUser as a9, Source as aA, CreateSourceRequest as aB, UpdateSourceRequest as aC, Client as aD, CreateClientRequest as aE, UpdateClientRequest as aF, HierarchyVendor as aG, HierarchySource as aH, HierarchyClient as aI, HierarchyLink as aJ, Membership as aK, CreateMembershipRequest as aL, UpdateMembershipRequest as aM, MembershipWithDetails as aN, AvailableScopesTree as aO, ScopeTreeClient as aP, ScopeTreeSource as aQ, ScopeTreeVendor as aR, ScopeSwitchResult as aS, GdprExportData as aT, PinStatus as aU, PinLoginResult as aV, MfaAvailableMethods as aW, TotpEnrollResult as aX, TotpVerifyResult as aY, SmsEnrollResult as aZ, EmailEnrollResult as a_, PermissionGroup as aa, GroupPermission as ab, AddGroupPermissionRequest as ac, InheritanceRelation as ad, UserPermissionOverride as ae, AddUserOverrideRequest as af, EffectivePermission as ag, PermissionCheckResult as ah, ApiKeyInfo as ai, CreateApiKeyRequest as aj, CreateApiKeyResult as ak, ApiKeyIntrospection as al, Invitation as am, CreateInviteRequest as an, InviteValidation as ao, AcceptInviteRequest as ap, WebhookEndpoint as aq, CreateWebhookRequest as ar, CreateWebhookResult as as, WebhookDelivery as at, WebhookTestResult as au, Entitlement as av, GrantEntitlementRequest as aw, Vendor as ax, CreateVendorRequest as ay, UpdateVendorRequest as az, IQAuthResponseLike as b, BackupCodeCountResult as b0,
|
|
1059
|
+
export type { AppManifest as $, ApiSuccessResponse as A, BrandingConfig as B, CreateTenantRequest as C, ApiErrorResponse as D, ApiResponse as E, MfaMethod as F, MfaEnrollment as G, TotpEnrollmentResult as H, IQAuthBrowserSessionClientConfig as I, JwtClaims as J, MfaVerifyResult as K, LoginResult as L, MigrateUserRequest as M, PasswordPolicy as N, OidcDiscovery as O, PromoteToVendorRequest as P, MfaPolicy as Q, UserPermissions as R, SessionUser as S, TokenPair as T, UserProfile as U, ProvisionUserRequest as V, ProvisionUserResponse as W, ExpressMiddlewareOptions as X, IQAuthRetryConfig as Y, IQAuthVerifyConfig as Z, PermissionNodeManifest as _, IQAuthRequestLike as a, BackupCodesResult as a$, AppInfo as a0, PermissionNodeInfo as a1, AppSyncResult as a2, Role as a3, CreateRoleRequest as a4, UpdateRoleRequest as a5, AssignRoleRequest as a6, UserRoleAssignment as a7, UserGroupAssignment as a8, TenantUser as a9, Source as aA, CreateSourceRequest as aB, UpdateSourceRequest as aC, Client as aD, CreateClientRequest as aE, UpdateClientRequest as aF, HierarchyVendor as aG, HierarchySource as aH, HierarchyClient as aI, HierarchyLink as aJ, Membership as aK, CreateMembershipRequest as aL, UpdateMembershipRequest as aM, MembershipWithDetails as aN, AvailableScopesTree as aO, ScopeTreeClient as aP, ScopeTreeSource as aQ, ScopeTreeVendor as aR, ScopeSwitchResult as aS, GdprExportData as aT, PinStatus as aU, PinLoginResult as aV, MfaAvailableMethods as aW, TotpEnrollResult as aX, TotpVerifyResult as aY, SmsEnrollResult as aZ, EmailEnrollResult as a_, PermissionGroup as aa, GroupPermission as ab, AddGroupPermissionRequest as ac, InheritanceRelation as ad, UserPermissionOverride as ae, AddUserOverrideRequest as af, EffectivePermission as ag, PermissionCheckResult as ah, ApiKeyInfo as ai, CreateApiKeyRequest as aj, CreateApiKeyResult as ak, ApiKeyIntrospection as al, Invitation as am, CreateInviteRequest as an, InviteValidation as ao, AcceptInviteRequest as ap, WebhookEndpoint as aq, CreateWebhookRequest as ar, CreateWebhookResult as as, WebhookDelivery as at, WebhookTestResult as au, Entitlement as av, GrantEntitlementRequest as aw, Vendor as ax, CreateVendorRequest as ay, UpdateVendorRequest as az, IQAuthResponseLike as b, BackupCodeCountResult as b0, ScopeHint as b1, SignupRequest as b2, HostedClientContext as b3, IQAuthNextFunction as c, IQAuthEnvironment as d, IQAuthClientConfig as e, IQAuthTokenClientConfig as f, ScopeContext as g, IQAuthClaims as h, IQAuthBaseClaims as i, Tenant as j, TokenAuthenticatedLoginResult as k, SessionAuthenticatedLoginResult as l, Session as m, TenantInfo as n, UpdateTenantRequest as o, PromoteToVendorResult as p, InviteTenantUserRequest as q, InviteTenantUserResult as r, TenantUserRoleUpdate as s, UpdateBrandingRequest as t, BrandingAsset as u, UploadAssetRequest as v, BrandingDomainMapping as w, JwksKey as x, JwksResponse as y, OidcTokenResponse as z };
|