@frontmcp/auth 1.8.2 → 1.8.3
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/authorities/authorities.engine.d.ts +24 -2
- package/authorities/authorities.engine.d.ts.map +1 -1
- package/authorities/authorities.validation.d.ts +27 -0
- package/authorities/authorities.validation.d.ts.map +1 -0
- package/authorities/index.d.ts +1 -0
- package/authorities/index.d.ts.map +1 -1
- package/authorization/dcr-client.registry.d.ts +13 -0
- package/authorization/dcr-client.registry.d.ts.map +1 -1
- package/esm/index.mjs +497 -85
- package/esm/package.json +5 -5
- package/index.d.ts +4 -4
- package/index.d.ts.map +1 -1
- package/index.js +581 -160
- package/jwks/jwks.service.d.ts.map +1 -1
- package/options/app-auth.schema.d.ts +4 -0
- package/options/app-auth.schema.d.ts.map +1 -1
- package/options/interfaces.d.ts +48 -7
- package/options/interfaces.d.ts.map +1 -1
- package/options/orchestrated.schema.d.ts +8 -0
- package/options/orchestrated.schema.d.ts.map +1 -1
- package/options/schema.d.ts +4 -0
- package/options/schema.d.ts.map +1 -1
- package/options/shared.schemas.d.ts +2 -0
- package/options/shared.schemas.d.ts.map +1 -1
- package/package.json +5 -5
- package/session/authorization.store.d.ts +19 -3
- package/session/authorization.store.d.ts.map +1 -1
- package/session/federated-auth.session.d.ts +16 -0
- package/session/federated-auth.session.d.ts.map +1 -1
- package/session/index.d.ts +4 -0
- package/session/index.d.ts.map +1 -1
- package/session/pending-login.d.ts +23 -0
- package/session/pending-login.d.ts.map +1 -0
- package/session/signin-binding.d.ts +39 -0
- package/session/signin-binding.d.ts.map +1 -0
- package/ui/base-layout.d.ts +26 -0
- package/ui/base-layout.d.ts.map +1 -1
- package/ui/index.d.ts +2 -2
- package/ui/index.d.ts.map +1 -1
- package/ui/local-login.helper.d.ts +9 -2
- package/ui/local-login.helper.d.ts.map +1 -1
- package/ui/templates.d.ts +5 -4
- package/ui/templates.d.ts.map +1 -1
- package/utils/index.d.ts +2 -0
- package/utils/index.d.ts.map +1 -1
- package/utils/redirect-uri.utils.d.ts +16 -0
- package/utils/redirect-uri.utils.d.ts.map +1 -0
- package/utils/scope-grant.utils.d.ts +11 -0
- package/utils/scope-grant.utils.d.ts.map +1 -0
package/esm/index.mjs
CHANGED
|
@@ -699,7 +699,9 @@ var JwksService = class {
|
|
|
699
699
|
// Pin to asymmetric algorithms so a symmetric key in the provider JWKS
|
|
700
700
|
// can't be used to accept an HMAC-signed token, and `none` is refused.
|
|
701
701
|
algorithms: [...TRANSPARENT_JWT_ALGS],
|
|
702
|
-
...issuerConstraint ? { issuer: issuerConstraint } : {}
|
|
702
|
+
...issuerConstraint ? { issuer: issuerConstraint } : {},
|
|
703
|
+
// A bearer token without `exp` would be valid forever (#272).
|
|
704
|
+
requiredClaims: ["exp"]
|
|
703
705
|
});
|
|
704
706
|
return {
|
|
705
707
|
ok: true,
|
|
@@ -802,7 +804,10 @@ var JwksService = class {
|
|
|
802
804
|
}
|
|
803
805
|
}
|
|
804
806
|
const nowSec = Math.floor(Date.now() / 1e3);
|
|
805
|
-
if (payload.exp
|
|
807
|
+
if (payload.exp === void 0) {
|
|
808
|
+
return { ok: false, error: "missing_exp" };
|
|
809
|
+
}
|
|
810
|
+
if (typeof payload.exp !== "number" || !Number.isFinite(payload.exp) || payload.exp <= nowSec) {
|
|
806
811
|
return { ok: false, error: "token_expired" };
|
|
807
812
|
}
|
|
808
813
|
if (payload.nbf !== void 0 && (typeof payload.nbf !== "number" || !Number.isFinite(payload.nbf) || payload.nbf > nowSec)) {
|
|
@@ -1058,6 +1063,26 @@ var CDN = {
|
|
|
1058
1063
|
stylesheet: "https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"
|
|
1059
1064
|
}
|
|
1060
1065
|
};
|
|
1066
|
+
var BUILT_IN_AUTH_PAGE_CSP = [
|
|
1067
|
+
"default-src 'self'",
|
|
1068
|
+
"script-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net",
|
|
1069
|
+
"style-src 'self' 'unsafe-inline' https://fonts.googleapis.com",
|
|
1070
|
+
"font-src 'self' https://fonts.gstatic.com",
|
|
1071
|
+
"img-src 'self' data: https:",
|
|
1072
|
+
"connect-src 'self'",
|
|
1073
|
+
"object-src 'none'",
|
|
1074
|
+
"base-uri 'none'",
|
|
1075
|
+
"frame-ancestors 'none'"
|
|
1076
|
+
].join("; ");
|
|
1077
|
+
function builtInAuthPageHeaders(options = {}) {
|
|
1078
|
+
return {
|
|
1079
|
+
...options.csp === false ? {} : { "Content-Security-Policy": BUILT_IN_AUTH_PAGE_CSP },
|
|
1080
|
+
"X-Frame-Options": "DENY",
|
|
1081
|
+
"X-Content-Type-Options": "nosniff",
|
|
1082
|
+
"Referrer-Policy": "same-origin",
|
|
1083
|
+
"Cache-Control": "no-store"
|
|
1084
|
+
};
|
|
1085
|
+
}
|
|
1061
1086
|
var DEFAULT_THEME = {
|
|
1062
1087
|
colors: {
|
|
1063
1088
|
primary: "#3b82f6",
|
|
@@ -1295,7 +1320,7 @@ function buildIncrementalAuthPage(params) {
|
|
|
1295
1320
|
</div>
|
|
1296
1321
|
</div>
|
|
1297
1322
|
|
|
1298
|
-
<form method="
|
|
1323
|
+
<form method="POST" action="${escapeHtml3(callbackPath)}" class="flex gap-3 pt-4 border-t border-gray-100">
|
|
1299
1324
|
<input type="hidden" name="pending_auth_id" value="${escapeHtml3(sessionHint)}">
|
|
1300
1325
|
<button type="button" onclick="window.close()"
|
|
1301
1326
|
class="flex-1 px-4 py-2.5 text-gray-600 hover:text-gray-900 hover:bg-gray-100 font-medium rounded-lg transition-colors">
|
|
@@ -1341,7 +1366,7 @@ function buildFederatedLoginPage(params) {
|
|
|
1341
1366
|
${escapeHtml3(clientName)} uses multiple authentication providers. Select which ones you want to authorize.
|
|
1342
1367
|
</p>
|
|
1343
1368
|
|
|
1344
|
-
<form method="
|
|
1369
|
+
<form method="POST" action="${escapeHtml3(callbackPath)}" id="federated-form">
|
|
1345
1370
|
<input type="hidden" name="pending_auth_id" value="${escapeHtml3(pendingAuthId)}">
|
|
1346
1371
|
<input type="hidden" name="federated" value="true">
|
|
1347
1372
|
|
|
@@ -1486,7 +1511,7 @@ function buildToolConsentPage(params) {
|
|
|
1486
1511
|
${errorBanner}
|
|
1487
1512
|
${userInfo}
|
|
1488
1513
|
|
|
1489
|
-
<form method="
|
|
1514
|
+
<form method="POST" action="${escapeHtml3(callbackPath)}" id="consent-form">
|
|
1490
1515
|
<input type="hidden" name="csrf" value="${escapeHtml3(csrfToken)}">
|
|
1491
1516
|
<input type="hidden" name="pending_auth_id" value="${escapeHtml3(pendingAuthId)}">
|
|
1492
1517
|
<input type="hidden" name="consent_submitted" value="1">
|
|
@@ -1584,7 +1609,7 @@ function buildLoginPage(params) {
|
|
|
1584
1609
|
|
|
1585
1610
|
${scopesHtml}
|
|
1586
1611
|
|
|
1587
|
-
<form method="
|
|
1612
|
+
<form method="POST" action="${escapeHtml3(callbackPath)}">
|
|
1588
1613
|
<input type="hidden" name="pending_auth_id" value="${escapeHtml3(pendingAuthId)}">
|
|
1589
1614
|
${fieldsHtml}
|
|
1590
1615
|
|
|
@@ -1681,7 +1706,17 @@ function toLoginExtraFields(fields, values) {
|
|
|
1681
1706
|
value: values?.[name]
|
|
1682
1707
|
}));
|
|
1683
1708
|
}
|
|
1684
|
-
function
|
|
1709
|
+
function withoutSecretFieldValues(values, fields) {
|
|
1710
|
+
if (!values) return void 0;
|
|
1711
|
+
const kept = {};
|
|
1712
|
+
for (const [name, value] of Object.entries(values)) {
|
|
1713
|
+
if (fields?.[name]?.type === "password") continue;
|
|
1714
|
+
kept[name] = value;
|
|
1715
|
+
}
|
|
1716
|
+
return kept;
|
|
1717
|
+
}
|
|
1718
|
+
function renderLocalLoginPage(login, ctx, submitted) {
|
|
1719
|
+
const values = withoutSecretFieldValues(submitted, login?.fields);
|
|
1685
1720
|
if (login?.render) {
|
|
1686
1721
|
return login.render({ ...ctx, values });
|
|
1687
1722
|
}
|
|
@@ -1788,7 +1823,8 @@ function buildPendingRecord(params) {
|
|
|
1788
1823
|
priorAuthorizedAppIds: params.priorAuthorizedAppIds,
|
|
1789
1824
|
federatedLogin: params.federatedLogin,
|
|
1790
1825
|
consent: params.consent,
|
|
1791
|
-
authUiCsrf: params.authUiCsrf
|
|
1826
|
+
authUiCsrf: params.authUiCsrf,
|
|
1827
|
+
signinBinding: params.signinBinding
|
|
1792
1828
|
};
|
|
1793
1829
|
}
|
|
1794
1830
|
function buildRefreshTokenRecord(params) {
|
|
@@ -2018,6 +2054,63 @@ var RedisAuthorizationStore = class {
|
|
|
2018
2054
|
}
|
|
2019
2055
|
};
|
|
2020
2056
|
|
|
2057
|
+
// libs/auth/src/session/pending-login.ts
|
|
2058
|
+
import {
|
|
2059
|
+
base64urlDecode,
|
|
2060
|
+
base64urlEncode,
|
|
2061
|
+
decryptAesGcm,
|
|
2062
|
+
encryptAesGcm,
|
|
2063
|
+
hkdfSha256,
|
|
2064
|
+
randomBytes as randomBytes2
|
|
2065
|
+
} from "@frontmcp/utils";
|
|
2066
|
+
var SALT = new TextEncoder().encode("frontmcp-pending-login");
|
|
2067
|
+
function keyFor(secret, pendingAuthId) {
|
|
2068
|
+
return hkdfSha256(secret, SALT, new TextEncoder().encode(`pending-login:${pendingAuthId}`), 32);
|
|
2069
|
+
}
|
|
2070
|
+
function sealPendingLogin(secret, pendingAuthId, state) {
|
|
2071
|
+
const iv = randomBytes2(12);
|
|
2072
|
+
const { ciphertext, tag } = encryptAesGcm(
|
|
2073
|
+
keyFor(secret, pendingAuthId),
|
|
2074
|
+
new TextEncoder().encode(JSON.stringify(state)),
|
|
2075
|
+
iv
|
|
2076
|
+
);
|
|
2077
|
+
return [iv, tag, ciphertext].map((part) => base64urlEncode(part)).join(".");
|
|
2078
|
+
}
|
|
2079
|
+
function openPendingLogin(secret, pendingAuthId, sealed) {
|
|
2080
|
+
try {
|
|
2081
|
+
const [iv, tag, ciphertext] = sealed.split(".").map((part) => base64urlDecode(part));
|
|
2082
|
+
if (!iv || !tag || !ciphertext) return void 0;
|
|
2083
|
+
const plaintext = decryptAesGcm(keyFor(secret, pendingAuthId), ciphertext, iv, tag);
|
|
2084
|
+
const state = JSON.parse(new TextDecoder().decode(plaintext));
|
|
2085
|
+
return typeof state?.sub === "string" && state.sub.length > 0 ? state : void 0;
|
|
2086
|
+
} catch {
|
|
2087
|
+
return void 0;
|
|
2088
|
+
}
|
|
2089
|
+
}
|
|
2090
|
+
|
|
2091
|
+
// libs/auth/src/session/signin-binding.ts
|
|
2092
|
+
import { base64urlEncode as base64urlEncode2, getCookie, randomBytes as randomBytes3, sha256Hex, timingSafeEqual } from "@frontmcp/utils";
|
|
2093
|
+
var SIGNIN_BINDING_COOKIE_PREFIX = "frontmcp_signin_";
|
|
2094
|
+
var SIGNIN_BINDING_SECURE_COOKIE_PREFIX = `__Host-${SIGNIN_BINDING_COOKIE_PREFIX}`;
|
|
2095
|
+
var SIGNIN_BINDING_MAX_AGE_SECONDS = 30 * 60;
|
|
2096
|
+
function signinBindingCookieName(pendingAuthId, options = {}) {
|
|
2097
|
+
const prefix = options.secure ? SIGNIN_BINDING_SECURE_COOKIE_PREFIX : SIGNIN_BINDING_COOKIE_PREFIX;
|
|
2098
|
+
return `${prefix}${sha256Hex(`signin:${pendingAuthId}`).slice(0, 16)}`;
|
|
2099
|
+
}
|
|
2100
|
+
function createSigninBinding(pendingAuthId, options = {}) {
|
|
2101
|
+
const value = base64urlEncode2(randomBytes3(32));
|
|
2102
|
+
return { cookieName: signinBindingCookieName(pendingAuthId, options), value, hash: sha256Hex(value) };
|
|
2103
|
+
}
|
|
2104
|
+
function signinBindingMatches(cookieHeader, pendingAuthId, expectedHash, options = {}) {
|
|
2105
|
+
if (!expectedHash) return false;
|
|
2106
|
+
const value = getCookie(cookieHeader, signinBindingCookieName(pendingAuthId, options));
|
|
2107
|
+
if (!value) return false;
|
|
2108
|
+
const encoder = new TextEncoder();
|
|
2109
|
+
const actual = encoder.encode(sha256Hex(value));
|
|
2110
|
+
const expected = encoder.encode(expectedHash);
|
|
2111
|
+
return actual.length === expected.length && timingSafeEqual(actual, expected);
|
|
2112
|
+
}
|
|
2113
|
+
|
|
2021
2114
|
// libs/auth/src/session/storage-authorization.store.ts
|
|
2022
2115
|
import { TypedStorage } from "@frontmcp/utils";
|
|
2023
2116
|
var StorageAuthorizationStore = class {
|
|
@@ -2410,12 +2503,12 @@ import { getEnv, randomUUID as randomUUID2 } from "@frontmcp/utils";
|
|
|
2410
2503
|
// libs/auth/src/session/vault-encryption.ts
|
|
2411
2504
|
import { z as z3 } from "@frontmcp/lazy-zod";
|
|
2412
2505
|
import {
|
|
2413
|
-
base64urlDecode,
|
|
2414
|
-
base64urlEncode,
|
|
2415
|
-
decryptAesGcm,
|
|
2416
|
-
encryptAesGcm,
|
|
2417
|
-
hkdfSha256,
|
|
2418
|
-
randomBytes as
|
|
2506
|
+
base64urlDecode as base64urlDecode2,
|
|
2507
|
+
base64urlEncode as base64urlEncode3,
|
|
2508
|
+
decryptAesGcm as decryptAesGcm2,
|
|
2509
|
+
encryptAesGcm as encryptAesGcm2,
|
|
2510
|
+
hkdfSha256 as hkdfSha2562,
|
|
2511
|
+
randomBytes as randomBytes4
|
|
2419
2512
|
} from "@frontmcp/utils";
|
|
2420
2513
|
var encryptedDataSchema = z3.object({
|
|
2421
2514
|
/** Version for future algorithm changes */
|
|
@@ -2456,7 +2549,7 @@ var VaultEncryption = class {
|
|
|
2456
2549
|
];
|
|
2457
2550
|
const ikm = new TextEncoder().encode(ikmParts.join(""));
|
|
2458
2551
|
const infoBytes = new TextEncoder().encode(this.hkdfInfo);
|
|
2459
|
-
const key = await
|
|
2552
|
+
const key = await hkdfSha2562(ikm, new Uint8Array(0), infoBytes, 32);
|
|
2460
2553
|
return key;
|
|
2461
2554
|
}
|
|
2462
2555
|
/**
|
|
@@ -2483,7 +2576,7 @@ var VaultEncryption = class {
|
|
|
2483
2576
|
];
|
|
2484
2577
|
const ikm = new TextEncoder().encode(ikmParts.join(""));
|
|
2485
2578
|
const infoBytes = new TextEncoder().encode(this.hkdfInfo);
|
|
2486
|
-
const key = await
|
|
2579
|
+
const key = await hkdfSha2562(ikm, new Uint8Array(0), infoBytes, 32);
|
|
2487
2580
|
return key;
|
|
2488
2581
|
}
|
|
2489
2582
|
/**
|
|
@@ -2497,14 +2590,14 @@ var VaultEncryption = class {
|
|
|
2497
2590
|
if (key.length !== 32) {
|
|
2498
2591
|
throw new Error("Encryption key must be 32 bytes");
|
|
2499
2592
|
}
|
|
2500
|
-
const iv =
|
|
2501
|
-
const { ciphertext, tag } = await
|
|
2593
|
+
const iv = randomBytes4(12);
|
|
2594
|
+
const { ciphertext, tag } = await encryptAesGcm2(key, new TextEncoder().encode(plaintext), iv);
|
|
2502
2595
|
return {
|
|
2503
2596
|
v: 1,
|
|
2504
2597
|
alg: "aes-256-gcm",
|
|
2505
|
-
iv:
|
|
2506
|
-
ct:
|
|
2507
|
-
tag:
|
|
2598
|
+
iv: base64urlEncode3(iv),
|
|
2599
|
+
ct: base64urlEncode3(ciphertext),
|
|
2600
|
+
tag: base64urlEncode3(tag)
|
|
2508
2601
|
};
|
|
2509
2602
|
}
|
|
2510
2603
|
/**
|
|
@@ -2524,11 +2617,11 @@ var VaultEncryption = class {
|
|
|
2524
2617
|
throw new Error("Invalid encrypted data format");
|
|
2525
2618
|
}
|
|
2526
2619
|
const { iv, ct, tag } = parsed.data;
|
|
2527
|
-
const ivBuffer =
|
|
2528
|
-
const ciphertext =
|
|
2529
|
-
const tagBuffer =
|
|
2620
|
+
const ivBuffer = base64urlDecode2(iv);
|
|
2621
|
+
const ciphertext = base64urlDecode2(ct);
|
|
2622
|
+
const tagBuffer = base64urlDecode2(tag);
|
|
2530
2623
|
try {
|
|
2531
|
-
const plaintext = await
|
|
2624
|
+
const plaintext = await decryptAesGcm2(key, ciphertext, ivBuffer, tagBuffer);
|
|
2532
2625
|
return new TextDecoder().decode(plaintext);
|
|
2533
2626
|
} catch (_error) {
|
|
2534
2627
|
throw new Error("Decryption failed: invalid key or corrupted data");
|
|
@@ -3124,7 +3217,7 @@ function errMsg2(err) {
|
|
|
3124
3217
|
var SECURE_STORE_ACCESSOR = /* @__PURE__ */ Symbol.for("frontmcp:SECURE_STORE_ACCESSOR");
|
|
3125
3218
|
|
|
3126
3219
|
// libs/auth/src/session/secure-store-accessor.impl.ts
|
|
3127
|
-
import { sha256Hex } from "@frontmcp/utils";
|
|
3220
|
+
import { sha256Hex as sha256Hex2 } from "@frontmcp/utils";
|
|
3128
3221
|
var GLOBAL_NAMESPACE = "global";
|
|
3129
3222
|
var SecureStoreAccessorImpl = class {
|
|
3130
3223
|
backend;
|
|
@@ -3153,12 +3246,12 @@ var SecureStoreAccessorImpl = class {
|
|
|
3153
3246
|
return GLOBAL_NAMESPACE;
|
|
3154
3247
|
case "session": {
|
|
3155
3248
|
const sid = this.resolveSessionId();
|
|
3156
|
-
return sid ? `s:${
|
|
3249
|
+
return sid ? `s:${sha256Hex2(sid).slice(0, 32)}` : void 0;
|
|
3157
3250
|
}
|
|
3158
3251
|
case "user":
|
|
3159
3252
|
default: {
|
|
3160
3253
|
const sub = this.resolveSub();
|
|
3161
|
-
return sub ? `u:${
|
|
3254
|
+
return sub ? `u:${sha256Hex2(sub).slice(0, 32)}` : void 0;
|
|
3162
3255
|
}
|
|
3163
3256
|
}
|
|
3164
3257
|
}
|
|
@@ -3262,7 +3355,7 @@ async function createSecureStore(options) {
|
|
|
3262
3355
|
}
|
|
3263
3356
|
|
|
3264
3357
|
// libs/auth/src/session/token.vault.ts
|
|
3265
|
-
import { encryptAesGcm as
|
|
3358
|
+
import { encryptAesGcm as encryptAesGcm3, decryptAesGcm as decryptAesGcm3, randomBytes as randomBytes5, base64urlEncode as base64urlEncode4, base64urlDecode as base64urlDecode3 } from "@frontmcp/utils";
|
|
3266
3359
|
var TokenVault = class {
|
|
3267
3360
|
/** Active key used for new encryptions */
|
|
3268
3361
|
active;
|
|
@@ -3291,14 +3384,14 @@ var TokenVault = class {
|
|
|
3291
3384
|
this.keys.set(k.kid, k.key);
|
|
3292
3385
|
}
|
|
3293
3386
|
async encrypt(plaintext, opts) {
|
|
3294
|
-
const iv =
|
|
3295
|
-
const { ciphertext, tag } = await
|
|
3387
|
+
const iv = randomBytes5(12);
|
|
3388
|
+
const { ciphertext, tag } = await encryptAesGcm3(this.active.key, new TextEncoder().encode(plaintext), iv);
|
|
3296
3389
|
return {
|
|
3297
3390
|
alg: "A256GCM",
|
|
3298
3391
|
kid: this.active.kid,
|
|
3299
|
-
iv:
|
|
3300
|
-
tag:
|
|
3301
|
-
data:
|
|
3392
|
+
iv: base64urlEncode4(iv),
|
|
3393
|
+
tag: base64urlEncode4(tag),
|
|
3394
|
+
data: base64urlEncode4(ciphertext),
|
|
3302
3395
|
exp: opts?.exp,
|
|
3303
3396
|
meta: opts?.meta
|
|
3304
3397
|
};
|
|
@@ -3312,21 +3405,21 @@ var TokenVault = class {
|
|
|
3312
3405
|
}
|
|
3313
3406
|
const key = this.keys.get(blob.kid);
|
|
3314
3407
|
if (!key) throw new Error(`vault_unknown_kid:${blob.kid}`);
|
|
3315
|
-
const iv =
|
|
3316
|
-
const tag =
|
|
3317
|
-
const data =
|
|
3318
|
-
const plaintext = await
|
|
3408
|
+
const iv = base64urlDecode3(blob.iv);
|
|
3409
|
+
const tag = base64urlDecode3(blob.tag);
|
|
3410
|
+
const data = base64urlDecode3(blob.data);
|
|
3411
|
+
const plaintext = await decryptAesGcm3(key, data, iv, tag);
|
|
3319
3412
|
return new TextDecoder().decode(plaintext);
|
|
3320
3413
|
}
|
|
3321
3414
|
};
|
|
3322
3415
|
|
|
3323
3416
|
// libs/auth/src/session/index.ts
|
|
3324
3417
|
import {
|
|
3325
|
-
hkdfSha256 as
|
|
3418
|
+
hkdfSha256 as hkdfSha2565,
|
|
3326
3419
|
encryptValue as encryptValue2,
|
|
3327
3420
|
decryptValue as decryptValue2,
|
|
3328
|
-
encryptAesGcm as
|
|
3329
|
-
decryptAesGcm as
|
|
3421
|
+
encryptAesGcm as encryptAesGcm6,
|
|
3422
|
+
decryptAesGcm as decryptAesGcm6
|
|
3330
3423
|
} from "@frontmcp/utils";
|
|
3331
3424
|
|
|
3332
3425
|
// libs/auth/src/session/transport-session.types.ts
|
|
@@ -3433,7 +3526,7 @@ import {
|
|
|
3433
3526
|
} from "@frontmcp/utils";
|
|
3434
3527
|
|
|
3435
3528
|
// libs/auth/src/errors/auth-internal.error.ts
|
|
3436
|
-
import { randomBytes as
|
|
3529
|
+
import { randomBytes as randomBytes6, bytesToHex as bytesToHex2 } from "@frontmcp/utils";
|
|
3437
3530
|
var AuthInternalError = class extends Error {
|
|
3438
3531
|
/**
|
|
3439
3532
|
* Unique error ID for tracking in logs.
|
|
@@ -3455,7 +3548,7 @@ var AuthInternalError = class extends Error {
|
|
|
3455
3548
|
super(message);
|
|
3456
3549
|
this.name = this.constructor.name;
|
|
3457
3550
|
this.code = code;
|
|
3458
|
-
this.errorId = `err_${bytesToHex2(
|
|
3551
|
+
this.errorId = `err_${bytesToHex2(randomBytes6(8))}`;
|
|
3459
3552
|
Error.captureStackTrace(this, this.constructor);
|
|
3460
3553
|
}
|
|
3461
3554
|
/**
|
|
@@ -4761,7 +4854,7 @@ var VercelKvSessionStore = class {
|
|
|
4761
4854
|
};
|
|
4762
4855
|
|
|
4763
4856
|
// libs/auth/src/session/orchestrated-token.store.ts
|
|
4764
|
-
import { encryptAesGcm as
|
|
4857
|
+
import { encryptAesGcm as encryptAesGcm4, decryptAesGcm as decryptAesGcm4, randomBytes as randomBytes7, hkdfSha256 as hkdfSha2563 } from "@frontmcp/utils";
|
|
4765
4858
|
var InMemoryOrchestratedTokenStore = class {
|
|
4766
4859
|
/** Token storage: Map<compositeKey, ProviderTokenRecord> */
|
|
4767
4860
|
tokens = /* @__PURE__ */ new Map();
|
|
@@ -4803,7 +4896,7 @@ var InMemoryOrchestratedTokenStore = class {
|
|
|
4803
4896
|
}
|
|
4804
4897
|
const info = new TextEncoder().encode(`orchestrated-token:${compositeKey}`);
|
|
4805
4898
|
const salt = new TextEncoder().encode("frontmcp-token-store");
|
|
4806
|
-
const derivedKey =
|
|
4899
|
+
const derivedKey = hkdfSha2563(this.encryptionKey, salt, info, 32);
|
|
4807
4900
|
this.derivedKeys.set(compositeKey, derivedKey);
|
|
4808
4901
|
return derivedKey;
|
|
4809
4902
|
}
|
|
@@ -4813,8 +4906,8 @@ var InMemoryOrchestratedTokenStore = class {
|
|
|
4813
4906
|
async encryptRecord(compositeKey, record) {
|
|
4814
4907
|
const key = await this.deriveKeyForRecord(compositeKey);
|
|
4815
4908
|
const plaintext = JSON.stringify(record);
|
|
4816
|
-
const iv =
|
|
4817
|
-
const { ciphertext, tag } =
|
|
4909
|
+
const iv = randomBytes7(12);
|
|
4910
|
+
const { ciphertext, tag } = encryptAesGcm4(key, new TextEncoder().encode(plaintext), iv);
|
|
4818
4911
|
return JSON.stringify({
|
|
4819
4912
|
iv: Buffer.from(iv).toString("base64url"),
|
|
4820
4913
|
tag: Buffer.from(tag).toString("base64url"),
|
|
@@ -4830,7 +4923,7 @@ var InMemoryOrchestratedTokenStore = class {
|
|
|
4830
4923
|
const ivBytes = Buffer.from(iv, "base64url");
|
|
4831
4924
|
const tagBytes = Buffer.from(tag, "base64url");
|
|
4832
4925
|
const ciphertextBytes = Buffer.from(data, "base64url");
|
|
4833
|
-
const plaintext =
|
|
4926
|
+
const plaintext = decryptAesGcm4(key, ciphertextBytes, ivBytes, tagBytes);
|
|
4834
4927
|
return JSON.parse(new TextDecoder().decode(plaintext));
|
|
4835
4928
|
}
|
|
4836
4929
|
/**
|
|
@@ -5032,7 +5125,7 @@ var InMemoryOrchestratedTokenStore = class {
|
|
|
5032
5125
|
};
|
|
5033
5126
|
|
|
5034
5127
|
// libs/auth/src/session/orchestrated-token.crypto.ts
|
|
5035
|
-
import { decryptAesGcm as
|
|
5128
|
+
import { decryptAesGcm as decryptAesGcm5, encryptAesGcm as encryptAesGcm5, hkdfSha256 as hkdfSha2564, randomBytes as randomBytes8 } from "@frontmcp/utils";
|
|
5036
5129
|
var HKDF_SALT = new TextEncoder().encode("frontmcp-token-store");
|
|
5037
5130
|
function deriveKeyForRecord(masterKey, compositeKey, cache) {
|
|
5038
5131
|
const cached = cache.get(compositeKey);
|
|
@@ -5040,14 +5133,14 @@ function deriveKeyForRecord(masterKey, compositeKey, cache) {
|
|
|
5040
5133
|
return cached;
|
|
5041
5134
|
}
|
|
5042
5135
|
const info = new TextEncoder().encode(`orchestrated-token:${compositeKey}`);
|
|
5043
|
-
const derived =
|
|
5136
|
+
const derived = hkdfSha2564(masterKey, HKDF_SALT, info, 32);
|
|
5044
5137
|
cache.set(compositeKey, derived);
|
|
5045
5138
|
return derived;
|
|
5046
5139
|
}
|
|
5047
5140
|
function encryptRecord(key, record) {
|
|
5048
5141
|
const plaintext = JSON.stringify(record);
|
|
5049
|
-
const iv =
|
|
5050
|
-
const { ciphertext, tag } =
|
|
5142
|
+
const iv = randomBytes8(12);
|
|
5143
|
+
const { ciphertext, tag } = encryptAesGcm5(key, new TextEncoder().encode(plaintext), iv);
|
|
5051
5144
|
return JSON.stringify({
|
|
5052
5145
|
iv: Buffer.from(iv).toString("base64url"),
|
|
5053
5146
|
tag: Buffer.from(tag).toString("base64url"),
|
|
@@ -5059,7 +5152,7 @@ function decryptRecord(key, encrypted) {
|
|
|
5059
5152
|
const ivBytes = Buffer.from(iv, "base64url");
|
|
5060
5153
|
const tagBytes = Buffer.from(tag, "base64url");
|
|
5061
5154
|
const ciphertextBytes = Buffer.from(data, "base64url");
|
|
5062
|
-
const plaintext =
|
|
5155
|
+
const plaintext = decryptAesGcm5(key, ciphertextBytes, ivBytes, tagBytes);
|
|
5063
5156
|
return JSON.parse(new TextDecoder().decode(plaintext));
|
|
5064
5157
|
}
|
|
5065
5158
|
|
|
@@ -5325,6 +5418,7 @@ var InMemoryFederatedAuthSessionStore = class {
|
|
|
5325
5418
|
providerQueue: [...params.providerIds],
|
|
5326
5419
|
completedProviders: /* @__PURE__ */ new Map(),
|
|
5327
5420
|
skippedProviders: [],
|
|
5421
|
+
signinBinding: params.signinBinding,
|
|
5328
5422
|
createdAt: now,
|
|
5329
5423
|
expiresAt: now + this.sessionTtlMs
|
|
5330
5424
|
};
|
|
@@ -5357,6 +5451,7 @@ function createFederatedAuthSession(params, ttlMs = 15 * 60 * 1e3) {
|
|
|
5357
5451
|
providerQueue: [...params.providerIds],
|
|
5358
5452
|
completedProviders: /* @__PURE__ */ new Map(),
|
|
5359
5453
|
skippedProviders: [],
|
|
5454
|
+
signinBinding: params.signinBinding,
|
|
5360
5455
|
createdAt: now,
|
|
5361
5456
|
expiresAt: now + ttlMs
|
|
5362
5457
|
};
|
|
@@ -5911,7 +6006,7 @@ function createEncryptedVault(redis, config = {}) {
|
|
|
5911
6006
|
}
|
|
5912
6007
|
|
|
5913
6008
|
// libs/auth/src/session/token.refresh.ts
|
|
5914
|
-
import { base64urlDecode as
|
|
6009
|
+
import { base64urlDecode as base64urlDecode4 } from "@frontmcp/utils";
|
|
5915
6010
|
function toEpochSeconds(exp) {
|
|
5916
6011
|
if (exp == null) return void 0;
|
|
5917
6012
|
if (exp instanceof Date) return Math.floor(exp.getTime() / 1e3);
|
|
@@ -5933,7 +6028,7 @@ function tryJwtExp(token) {
|
|
|
5933
6028
|
const parts = token.split(".");
|
|
5934
6029
|
if (parts.length < 2) return void 0;
|
|
5935
6030
|
try {
|
|
5936
|
-
const json = JSON.parse(new TextDecoder().decode(
|
|
6031
|
+
const json = JSON.parse(new TextDecoder().decode(base64urlDecode4(parts[1])));
|
|
5937
6032
|
const e = json?.exp;
|
|
5938
6033
|
return typeof e === "number" ? toEpochSeconds(e) : void 0;
|
|
5939
6034
|
} catch {
|
|
@@ -5996,7 +6091,7 @@ var progressiveAuthStateSchema = z6.object({
|
|
|
5996
6091
|
});
|
|
5997
6092
|
|
|
5998
6093
|
// libs/auth/src/authorization/authorization.class.ts
|
|
5999
|
-
import { base64urlDecode as
|
|
6094
|
+
import { base64urlDecode as base64urlDecode5, getMachineId as getMachineId2, randomUUID as randomUUID11 } from "@frontmcp/utils";
|
|
6000
6095
|
var AuthorizationBase = class _AuthorizationBase {
|
|
6001
6096
|
id;
|
|
6002
6097
|
isAnonymous;
|
|
@@ -6192,7 +6287,7 @@ var AuthorizationBase = class _AuthorizationBase {
|
|
|
6192
6287
|
*/
|
|
6193
6288
|
static isJwtHeader(segment) {
|
|
6194
6289
|
try {
|
|
6195
|
-
const bytes =
|
|
6290
|
+
const bytes = base64urlDecode5(segment);
|
|
6196
6291
|
const text = new TextDecoder().decode(bytes);
|
|
6197
6292
|
const parsed = JSON.parse(text);
|
|
6198
6293
|
return typeof parsed === "object" && parsed !== null && typeof parsed.alg === "string";
|
|
@@ -6364,7 +6459,7 @@ var PublicAuthorization = class _PublicAuthorization extends AuthorizationBase {
|
|
|
6364
6459
|
};
|
|
6365
6460
|
|
|
6366
6461
|
// libs/auth/src/authorization/transparent.authorization.ts
|
|
6367
|
-
import { sha256Hex as
|
|
6462
|
+
import { sha256Hex as sha256Hex3 } from "@frontmcp/utils";
|
|
6368
6463
|
var TransparentAuthorization = class _TransparentAuthorization extends AuthorizationBase {
|
|
6369
6464
|
mode = "transparent";
|
|
6370
6465
|
/**
|
|
@@ -6464,7 +6559,7 @@ var TransparentAuthorization = class _TransparentAuthorization extends Authoriza
|
|
|
6464
6559
|
static generateAuthorizationId(token) {
|
|
6465
6560
|
const parts = token.split(".");
|
|
6466
6561
|
const signature = parts[2] || token;
|
|
6467
|
-
return
|
|
6562
|
+
return sha256Hex3(signature).substring(0, 16);
|
|
6468
6563
|
}
|
|
6469
6564
|
/**
|
|
6470
6565
|
* Get the issuer from the token claims
|
|
@@ -6490,11 +6585,11 @@ var TransparentAuthorization = class _TransparentAuthorization extends Authoriza
|
|
|
6490
6585
|
};
|
|
6491
6586
|
|
|
6492
6587
|
// libs/auth/src/utils/authorization-id.utils.ts
|
|
6493
|
-
import { sha256Hex as
|
|
6588
|
+
import { sha256Hex as sha256Hex4 } from "@frontmcp/utils";
|
|
6494
6589
|
function deriveAuthorizationId(token) {
|
|
6495
6590
|
const parts = token.split(".");
|
|
6496
6591
|
const signature = parts[2] || token;
|
|
6497
|
-
return
|
|
6592
|
+
return sha256Hex4(signature).substring(0, 16);
|
|
6498
6593
|
}
|
|
6499
6594
|
|
|
6500
6595
|
// libs/auth/src/authorization/orchestrated.authorization.ts
|
|
@@ -6863,7 +6958,7 @@ var OrchestratedAuthAccessorAdapter = class {
|
|
|
6863
6958
|
};
|
|
6864
6959
|
|
|
6865
6960
|
// libs/auth/src/authorization/dcr-client.registry.ts
|
|
6866
|
-
import { sha256 as sha2562, timingSafeEqual } from "@frontmcp/utils";
|
|
6961
|
+
import { sha256 as sha2562, timingSafeEqual as timingSafeEqual2 } from "@frontmcp/utils";
|
|
6867
6962
|
var DEFAULT_MAX_DYNAMIC_CLIENTS = 1e3;
|
|
6868
6963
|
function globMatch(pattern, input) {
|
|
6869
6964
|
let p = 0;
|
|
@@ -6989,7 +7084,7 @@ var DcrClientRegistry = class {
|
|
|
6989
7084
|
if (!isConfidential) return "ok";
|
|
6990
7085
|
if (!client.client_secret) return "invalid";
|
|
6991
7086
|
if (!presentedSecret) return "invalid";
|
|
6992
|
-
return
|
|
7087
|
+
return timingSafeEqual2(sha2562(presentedSecret), sha2562(client.client_secret)) ? "ok" : "invalid";
|
|
6993
7088
|
}
|
|
6994
7089
|
/** Whether a client id is known to the registry. */
|
|
6995
7090
|
has(clientId) {
|
|
@@ -7077,7 +7172,7 @@ var DcrClientRegistry = class {
|
|
|
7077
7172
|
if (typeof presented !== "string" || presented.length === 0) {
|
|
7078
7173
|
return false;
|
|
7079
7174
|
}
|
|
7080
|
-
return
|
|
7175
|
+
return timingSafeEqual2(sha2562(presented), sha2562(expected));
|
|
7081
7176
|
}
|
|
7082
7177
|
};
|
|
7083
7178
|
|
|
@@ -7894,7 +7989,16 @@ var upstreamProviderSchema = z10.object({
|
|
|
7894
7989
|
/** User info endpoint (optional, used to enrich the session identity). */
|
|
7895
7990
|
userInfoEndpoint: z10.string().url().optional(),
|
|
7896
7991
|
/** JWKS URI for upstream id_token validation (optional). */
|
|
7897
|
-
jwksUri: z10.string().url().optional()
|
|
7992
|
+
jwksUri: z10.string().url().optional(),
|
|
7993
|
+
/**
|
|
7994
|
+
* The provider's issuer identifier (its OIDC `iss`). When set, an RFC 9207
|
|
7995
|
+
* `iss` on the provider's callback and the `iss` of its `id_token` must name
|
|
7996
|
+
* it (or one of {@link additionalIssuers}). Without it the provider's
|
|
7997
|
+
* `id_token` is not used for identity; `userInfoEndpoint` is asked instead.
|
|
7998
|
+
*/
|
|
7999
|
+
issuer: z10.string().url().optional(),
|
|
8000
|
+
/** Other issuer values this provider legitimately uses. */
|
|
8001
|
+
additionalIssuers: z10.array(z10.string().trim().min(1, "additionalIssuers entries must be non-empty")).optional()
|
|
7898
8002
|
}).refine((p) => !!(p.authorizationEndpoint ?? p.authorizeUrl), {
|
|
7899
8003
|
message: "authorizationEndpoint (or authorizeUrl) is required",
|
|
7900
8004
|
path: ["authorizationEndpoint"]
|
|
@@ -8303,17 +8407,21 @@ var sharedAuthFields = {
|
|
|
8303
8407
|
* Require the OAuth client to be KNOWN (registered via DCR / pre-registered,
|
|
8304
8408
|
* or a CIMD client-id URL) before an authorization request is accepted.
|
|
8305
8409
|
*
|
|
8306
|
-
* @default
|
|
8410
|
+
* @default true
|
|
8307
8411
|
*
|
|
8308
|
-
* SECURITY:
|
|
8309
|
-
*
|
|
8310
|
-
*
|
|
8311
|
-
* (auth-code interception
|
|
8312
|
-
* `
|
|
8313
|
-
|
|
8314
|
-
|
|
8315
|
-
|
|
8316
|
-
|
|
8412
|
+
* SECURITY: an unregistered client id has no trusted `redirect_uris` to
|
|
8413
|
+
* validate against, so accepting it lets anyone start a sign-in whose
|
|
8414
|
+
* authorization code is delivered to a redirect_uri of their choosing
|
|
8415
|
+
* (auth-code interception). `false` is for local development only; a
|
|
8416
|
+
* `dcr.allowedRedirectUris` allowlist still constrains such clients.
|
|
8417
|
+
*/
|
|
8418
|
+
requireRegisteredClients: z14.boolean().default(true),
|
|
8419
|
+
/**
|
|
8420
|
+
* Scopes the server may grant (exact values or `*` globs). Requested scopes
|
|
8421
|
+
* outside this list are dropped from the grant. Unset → the standard OpenID
|
|
8422
|
+
* scopes only (see `DEFAULT_ALLOWED_SCOPES`).
|
|
8423
|
+
*/
|
|
8424
|
+
allowedScopes: z14.array(z14.string().trim().min(1, "allowedScopes entries must be non-empty")).optional(),
|
|
8317
8425
|
cimd: cimdConfigSchema.optional(),
|
|
8318
8426
|
// #469 — custom auth UI as a slot→file map + extras name→handler map (per-app
|
|
8319
8427
|
// under splitByApp). Both optional; omitting them serves the built-in pages.
|
|
@@ -8924,6 +9032,43 @@ var AudienceValidator = class _AudienceValidator {
|
|
|
8924
9032
|
}
|
|
8925
9033
|
};
|
|
8926
9034
|
|
|
9035
|
+
// libs/auth/src/utils/scope-grant.utils.ts
|
|
9036
|
+
var DEFAULT_ALLOWED_SCOPES = Object.freeze([
|
|
9037
|
+
"openid",
|
|
9038
|
+
"profile",
|
|
9039
|
+
"email",
|
|
9040
|
+
"offline_access"
|
|
9041
|
+
]);
|
|
9042
|
+
function grantScopes(requested, allowed) {
|
|
9043
|
+
const patterns = allowed ?? DEFAULT_ALLOWED_SCOPES;
|
|
9044
|
+
const granted = [];
|
|
9045
|
+
for (const scope of requested) {
|
|
9046
|
+
if (!scope || granted.includes(scope)) continue;
|
|
9047
|
+
if (patterns.some((pattern) => globMatch(pattern, scope))) granted.push(scope);
|
|
9048
|
+
}
|
|
9049
|
+
return granted;
|
|
9050
|
+
}
|
|
9051
|
+
|
|
9052
|
+
// libs/auth/src/utils/redirect-uri.utils.ts
|
|
9053
|
+
function isLoopbackRedirectUri(uri) {
|
|
9054
|
+
let url;
|
|
9055
|
+
try {
|
|
9056
|
+
url = new URL(uri);
|
|
9057
|
+
} catch {
|
|
9058
|
+
return false;
|
|
9059
|
+
}
|
|
9060
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") return false;
|
|
9061
|
+
if (url.username || url.password) return false;
|
|
9062
|
+
const host = url.hostname.replace(/^\[|\]$/g, "").toLowerCase();
|
|
9063
|
+
if (host === "localhost" || host === "::1") return true;
|
|
9064
|
+
const m = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(host);
|
|
9065
|
+
if (m) {
|
|
9066
|
+
const octets = m.slice(1).map((n) => Number(n));
|
|
9067
|
+
return octets.every((o) => o >= 0 && o <= 255) && octets[0] === 127;
|
|
9068
|
+
}
|
|
9069
|
+
return false;
|
|
9070
|
+
}
|
|
9071
|
+
|
|
8927
9072
|
// libs/auth/src/vault/auth-providers.types.ts
|
|
8928
9073
|
import { z as z19 } from "@frontmcp/lazy-zod";
|
|
8929
9074
|
var credentialScopeSchema = z19.enum(["global", "user", "session"]);
|
|
@@ -10489,6 +10634,211 @@ async function evaluateRebac(policy, ctx) {
|
|
|
10489
10634
|
return { granted: true, evaluatedPolicies: ["relationships"] };
|
|
10490
10635
|
}
|
|
10491
10636
|
|
|
10637
|
+
// libs/auth/src/authorities/authorities.validation.ts
|
|
10638
|
+
var ABAC_OPERATORS = /* @__PURE__ */ new Set([
|
|
10639
|
+
"eq",
|
|
10640
|
+
"neq",
|
|
10641
|
+
"in",
|
|
10642
|
+
"notIn",
|
|
10643
|
+
"gt",
|
|
10644
|
+
"gte",
|
|
10645
|
+
"lt",
|
|
10646
|
+
"lte",
|
|
10647
|
+
"contains",
|
|
10648
|
+
"startsWith",
|
|
10649
|
+
"endsWith",
|
|
10650
|
+
"exists",
|
|
10651
|
+
"matches"
|
|
10652
|
+
]);
|
|
10653
|
+
var CHECK_FIELDS = [
|
|
10654
|
+
"roles",
|
|
10655
|
+
"permissions",
|
|
10656
|
+
"attributes",
|
|
10657
|
+
"relationships",
|
|
10658
|
+
"custom",
|
|
10659
|
+
"guards",
|
|
10660
|
+
"allOf",
|
|
10661
|
+
"anyOf",
|
|
10662
|
+
"not"
|
|
10663
|
+
];
|
|
10664
|
+
var RULE_FIELDS = /* @__PURE__ */ new Set([...CHECK_FIELDS, "operator"]);
|
|
10665
|
+
function isPlainObject(value) {
|
|
10666
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
10667
|
+
}
|
|
10668
|
+
function isNonEmptyString(value) {
|
|
10669
|
+
return typeof value === "string" && value.length > 0;
|
|
10670
|
+
}
|
|
10671
|
+
function unknownFields(value, known, path) {
|
|
10672
|
+
const prefix = path ? `${path} has` : "has";
|
|
10673
|
+
return Object.keys(value).filter((key) => !known.has(key)).map((key) => `${prefix} an unknown field "${key}"`);
|
|
10674
|
+
}
|
|
10675
|
+
function checkStringList(value, path) {
|
|
10676
|
+
if (!Array.isArray(value)) return [`${path} must be a list of names`];
|
|
10677
|
+
if (value.length === 0) return [`${path} is empty`];
|
|
10678
|
+
return value.every(isNonEmptyString) ? [] : [`${path} must contain only non-empty names`];
|
|
10679
|
+
}
|
|
10680
|
+
var ALL_OR_ANY = /* @__PURE__ */ new Set(["all", "any"]);
|
|
10681
|
+
function checkAllOrAny(value, path) {
|
|
10682
|
+
if (!isPlainObject(value)) return [`${path} must be an object with "all" or "any"`];
|
|
10683
|
+
const problems = unknownFields(value, ALL_OR_ANY, path);
|
|
10684
|
+
if (value["all"] === void 0 && value["any"] === void 0) {
|
|
10685
|
+
problems.push(`${path} needs "all" or "any"`);
|
|
10686
|
+
}
|
|
10687
|
+
if (value["all"] !== void 0) problems.push(...checkStringList(value["all"], `${path}.all`));
|
|
10688
|
+
if (value["any"] !== void 0) problems.push(...checkStringList(value["any"], `${path}.any`));
|
|
10689
|
+
return problems;
|
|
10690
|
+
}
|
|
10691
|
+
var ATTRIBUTE_FIELDS = /* @__PURE__ */ new Set(["match", "conditions"]);
|
|
10692
|
+
var CONDITION_FIELDS = /* @__PURE__ */ new Set(["path", "op", "value"]);
|
|
10693
|
+
function isValueReference(value) {
|
|
10694
|
+
return isPlainObject(value) && ("fromInput" in value || "fromClaims" in value);
|
|
10695
|
+
}
|
|
10696
|
+
function checkValueReference(value, path) {
|
|
10697
|
+
const ref = value["fromInput"] ?? value["fromClaims"];
|
|
10698
|
+
return Object.keys(value).length === 1 && isNonEmptyString(ref) ? [] : [`${path} must be { fromInput: "<name>" } or { fromClaims: "<path>" }`];
|
|
10699
|
+
}
|
|
10700
|
+
var OPERATOR_VALUES = {
|
|
10701
|
+
in: { accepts: Array.isArray, needs: "a list" },
|
|
10702
|
+
notIn: { accepts: Array.isArray, needs: "a list" },
|
|
10703
|
+
gt: { accepts: (value) => typeof value === "number", needs: "a number" },
|
|
10704
|
+
gte: { accepts: (value) => typeof value === "number", needs: "a number" },
|
|
10705
|
+
lt: { accepts: (value) => typeof value === "number", needs: "a number" },
|
|
10706
|
+
lte: { accepts: (value) => typeof value === "number", needs: "a number" },
|
|
10707
|
+
startsWith: { accepts: (value) => typeof value === "string", needs: "a string" },
|
|
10708
|
+
endsWith: { accepts: (value) => typeof value === "string", needs: "a string" },
|
|
10709
|
+
matches: { accepts: (value) => typeof value === "string", needs: "a string" }
|
|
10710
|
+
};
|
|
10711
|
+
function checkConditionValue(op, condition, path) {
|
|
10712
|
+
const value = condition["value"];
|
|
10713
|
+
if (value === void 0) return [`${path} is missing`];
|
|
10714
|
+
if (op === "exists") {
|
|
10715
|
+
return typeof value === "boolean" ? [] : [`${path} must be true or false for "exists"`];
|
|
10716
|
+
}
|
|
10717
|
+
if (isValueReference(value)) return checkValueReference(value, path);
|
|
10718
|
+
const expected = OPERATOR_VALUES[op];
|
|
10719
|
+
if (expected && !expected.accepts(value)) return [`${path} must be ${expected.needs} for "${op}"`];
|
|
10720
|
+
if (Array.isArray(value) && value.length === 0 && (op === "in" || op === "notIn")) return [`${path} is empty`];
|
|
10721
|
+
return [];
|
|
10722
|
+
}
|
|
10723
|
+
function checkAttributes(value, path) {
|
|
10724
|
+
if (!isPlainObject(value)) return [`${path} must be an object with "match" or "conditions"`];
|
|
10725
|
+
const problems = unknownFields(value, ATTRIBUTE_FIELDS, path);
|
|
10726
|
+
const { match, conditions } = value;
|
|
10727
|
+
if (match === void 0 && conditions === void 0) {
|
|
10728
|
+
problems.push(`${path} needs "match" or "conditions"`);
|
|
10729
|
+
}
|
|
10730
|
+
if (match !== void 0) {
|
|
10731
|
+
if (!isPlainObject(match)) problems.push(`${path}.match must be an object`);
|
|
10732
|
+
else if (Object.keys(match).length === 0) problems.push(`${path}.match is empty`);
|
|
10733
|
+
else {
|
|
10734
|
+
for (const [attribute, expected] of Object.entries(match)) {
|
|
10735
|
+
const at = `${path}.match[${JSON.stringify(attribute)}]`;
|
|
10736
|
+
if (expected === void 0) problems.push(`${at} has no value`);
|
|
10737
|
+
else if (isValueReference(expected)) problems.push(...checkValueReference(expected, at));
|
|
10738
|
+
}
|
|
10739
|
+
}
|
|
10740
|
+
}
|
|
10741
|
+
if (conditions !== void 0) {
|
|
10742
|
+
if (!Array.isArray(conditions)) problems.push(`${path}.conditions must be a list`);
|
|
10743
|
+
else if (conditions.length === 0) problems.push(`${path}.conditions is empty`);
|
|
10744
|
+
else {
|
|
10745
|
+
conditions.forEach((condition, index) => {
|
|
10746
|
+
const at = `${path}.conditions[${index}]`;
|
|
10747
|
+
if (!isPlainObject(condition)) {
|
|
10748
|
+
problems.push(`${at} must be an object with "path" and "op"`);
|
|
10749
|
+
return;
|
|
10750
|
+
}
|
|
10751
|
+
problems.push(...unknownFields(condition, CONDITION_FIELDS, at));
|
|
10752
|
+
if (!isNonEmptyString(condition["path"])) problems.push(`${at}.path must be a non-empty string`);
|
|
10753
|
+
const op = condition["op"];
|
|
10754
|
+
if (!ABAC_OPERATORS.has(op)) {
|
|
10755
|
+
problems.push(`${at}.op "${String(condition["op"])}" is not an operator`);
|
|
10756
|
+
} else {
|
|
10757
|
+
problems.push(...checkConditionValue(op, condition, `${at}.value`));
|
|
10758
|
+
}
|
|
10759
|
+
});
|
|
10760
|
+
}
|
|
10761
|
+
}
|
|
10762
|
+
return problems;
|
|
10763
|
+
}
|
|
10764
|
+
var RELATIONSHIP_FIELDS = /* @__PURE__ */ new Set(["type", "resource", "resourceId"]);
|
|
10765
|
+
function checkResourceId(value, path) {
|
|
10766
|
+
if (isNonEmptyString(value)) return [];
|
|
10767
|
+
if (isPlainObject(value) && Object.keys(value).length === 1) {
|
|
10768
|
+
const ref = value["fromInput"] ?? value["fromClaims"];
|
|
10769
|
+
if (isNonEmptyString(ref)) return [];
|
|
10770
|
+
}
|
|
10771
|
+
return [`${path} must be a string, { fromInput } or { fromClaims }`];
|
|
10772
|
+
}
|
|
10773
|
+
function checkRelationship(value, path) {
|
|
10774
|
+
if (!isPlainObject(value)) return [`${path} must be an object with "type", "resource" and "resourceId"`];
|
|
10775
|
+
const problems = unknownFields(value, RELATIONSHIP_FIELDS, path);
|
|
10776
|
+
if (!isNonEmptyString(value["type"])) problems.push(`${path}.type must be a non-empty string`);
|
|
10777
|
+
if (!isNonEmptyString(value["resource"])) problems.push(`${path}.resource must be a non-empty string`);
|
|
10778
|
+
problems.push(...checkResourceId(value["resourceId"], `${path}.resourceId`));
|
|
10779
|
+
return problems;
|
|
10780
|
+
}
|
|
10781
|
+
function checkRelationships(value, path) {
|
|
10782
|
+
if (!Array.isArray(value)) return checkRelationship(value, path);
|
|
10783
|
+
if (value.length === 0) return [`${path} is empty`];
|
|
10784
|
+
return value.flatMap((relationship, index) => checkRelationship(relationship, `${path}[${index}]`));
|
|
10785
|
+
}
|
|
10786
|
+
function checkRuleList(value, path) {
|
|
10787
|
+
if (!Array.isArray(value)) return [`${path} must be a list of rules`];
|
|
10788
|
+
if (value.length === 0) return [`${path} is empty`];
|
|
10789
|
+
return value.flatMap((rule, index) => checkRule(rule, `${path}[${index}]`));
|
|
10790
|
+
}
|
|
10791
|
+
function checkRule(rule, path) {
|
|
10792
|
+
if (!isPlainObject(rule)) {
|
|
10793
|
+
return [`${path || "the rule"} must be a rule object${typeof rule === "string" ? ", not a profile name" : ""}`];
|
|
10794
|
+
}
|
|
10795
|
+
const problems = unknownFields(rule, RULE_FIELDS, path);
|
|
10796
|
+
if (!CHECK_FIELDS.some((field) => rule[field] !== void 0)) {
|
|
10797
|
+
problems.push(`${path ? `${path} ` : ""}checks nothing`);
|
|
10798
|
+
}
|
|
10799
|
+
if (rule["operator"] !== void 0 && rule["operator"] !== "AND" && rule["operator"] !== "OR") {
|
|
10800
|
+
problems.push(`${path}.operator must be "AND" or "OR"`);
|
|
10801
|
+
}
|
|
10802
|
+
if (rule["roles"] !== void 0) problems.push(...checkAllOrAny(rule["roles"], `${path}.roles`));
|
|
10803
|
+
if (rule["permissions"] !== void 0) problems.push(...checkAllOrAny(rule["permissions"], `${path}.permissions`));
|
|
10804
|
+
if (rule["attributes"] !== void 0) problems.push(...checkAttributes(rule["attributes"], `${path}.attributes`));
|
|
10805
|
+
if (rule["relationships"] !== void 0) {
|
|
10806
|
+
problems.push(...checkRelationships(rule["relationships"], `${path}.relationships`));
|
|
10807
|
+
}
|
|
10808
|
+
if (rule["custom"] !== void 0) {
|
|
10809
|
+
if (!isPlainObject(rule["custom"])) problems.push(`${path}.custom must be an object`);
|
|
10810
|
+
else if (Object.keys(rule["custom"]).length === 0) problems.push(`${path}.custom is empty`);
|
|
10811
|
+
}
|
|
10812
|
+
if (rule["guards"] !== void 0) {
|
|
10813
|
+
const guards = rule["guards"];
|
|
10814
|
+
if (!Array.isArray(guards)) problems.push(`${path}.guards must be a list of functions`);
|
|
10815
|
+
else if (guards.length === 0) problems.push(`${path}.guards is empty`);
|
|
10816
|
+
else if (!guards.every((guard) => typeof guard === "function")) {
|
|
10817
|
+
problems.push(`${path}.guards must contain only functions`);
|
|
10818
|
+
}
|
|
10819
|
+
}
|
|
10820
|
+
if (rule["allOf"] !== void 0) problems.push(...checkRuleList(rule["allOf"], `${path}.allOf`));
|
|
10821
|
+
if (rule["anyOf"] !== void 0) problems.push(...checkRuleList(rule["anyOf"], `${path}.anyOf`));
|
|
10822
|
+
if (rule["not"] !== void 0) problems.push(...checkRule(rule["not"], `${path}.not`));
|
|
10823
|
+
return problems;
|
|
10824
|
+
}
|
|
10825
|
+
function findAuthoritiesRuleProblems(authorities) {
|
|
10826
|
+
if (typeof authorities === "string") {
|
|
10827
|
+
return authorities.length > 0 ? [] : ["the profile name is empty"];
|
|
10828
|
+
}
|
|
10829
|
+
if (Array.isArray(authorities)) {
|
|
10830
|
+
if (authorities.length === 0) return ["the list of profiles is empty"];
|
|
10831
|
+
return authorities.every(isNonEmptyString) ? [] : ["a list of profiles must contain only non-empty profile names"];
|
|
10832
|
+
}
|
|
10833
|
+
if (!isPlainObject(authorities)) {
|
|
10834
|
+
return ["must be a profile name, a list of profile names, or a rule object"];
|
|
10835
|
+
}
|
|
10836
|
+
return checkRule(authorities, "");
|
|
10837
|
+
}
|
|
10838
|
+
function findAuthoritiesProfileProblems(name, policy) {
|
|
10839
|
+
return checkRule(policy, "").map((problem) => `profile "${name}": ${problem.replace(/^\./, "")}`);
|
|
10840
|
+
}
|
|
10841
|
+
|
|
10492
10842
|
// libs/auth/src/authorities/authorities.engine.ts
|
|
10493
10843
|
function mergeResult(base, ...others) {
|
|
10494
10844
|
const evaluatedPolicies = [...base.evaluatedPolicies];
|
|
@@ -10497,8 +10847,12 @@ function mergeResult(base, ...others) {
|
|
|
10497
10847
|
}
|
|
10498
10848
|
return { ...base, evaluatedPolicies };
|
|
10499
10849
|
}
|
|
10500
|
-
function
|
|
10501
|
-
return {
|
|
10850
|
+
function invalidRule(problems, policies = []) {
|
|
10851
|
+
return {
|
|
10852
|
+
granted: false,
|
|
10853
|
+
deniedBy: `invalid authorities rule: ${problems.join("; ")}`,
|
|
10854
|
+
evaluatedPolicies: policies
|
|
10855
|
+
};
|
|
10502
10856
|
}
|
|
10503
10857
|
var AuthoritiesEngine = class {
|
|
10504
10858
|
constructor(profiles, evaluators) {
|
|
@@ -10507,10 +10861,32 @@ var AuthoritiesEngine = class {
|
|
|
10507
10861
|
}
|
|
10508
10862
|
profiles;
|
|
10509
10863
|
evaluators;
|
|
10864
|
+
/** Problems found per rule object, so a rule is validated once however often it is evaluated. */
|
|
10865
|
+
ruleProblems = /* @__PURE__ */ new WeakMap();
|
|
10866
|
+
/**
|
|
10867
|
+
* Problems with an `authorities` value declared on an entry (see {@link findAuthoritiesRuleProblems}).
|
|
10868
|
+
* The server reports them when it starts; {@link evaluate} denies such a value.
|
|
10869
|
+
*/
|
|
10870
|
+
findRuleProblems(authorities) {
|
|
10871
|
+
return findAuthoritiesRuleProblems(authorities);
|
|
10872
|
+
}
|
|
10873
|
+
/**
|
|
10874
|
+
* Problems with every registered profile's rule (see {@link findAuthoritiesRuleProblems}).
|
|
10875
|
+
* The server reports them when it starts.
|
|
10876
|
+
*/
|
|
10877
|
+
findProfileProblems() {
|
|
10878
|
+
return Object.entries(this.profiles.getAll()).flatMap(
|
|
10879
|
+
([name, policy]) => findAuthoritiesProfileProblems(name, policy)
|
|
10880
|
+
);
|
|
10881
|
+
}
|
|
10510
10882
|
/**
|
|
10511
10883
|
* Evaluate an AuthoritiesMetadata value (string, string[], or policy object).
|
|
10884
|
+
*
|
|
10885
|
+
* A value that is malformed or checks nothing (see {@link findAuthoritiesRuleProblems}) is denied.
|
|
10512
10886
|
*/
|
|
10513
10887
|
async evaluate(authorities, ctx) {
|
|
10888
|
+
const problems = this.problemsOf(authorities, findAuthoritiesRuleProblems);
|
|
10889
|
+
if (problems.length > 0) return invalidRule(problems);
|
|
10514
10890
|
if (typeof authorities === "string") {
|
|
10515
10891
|
return this.evaluateProfile(authorities, ctx);
|
|
10516
10892
|
}
|
|
@@ -10531,6 +10907,8 @@ var AuthoritiesEngine = class {
|
|
|
10531
10907
|
evaluatedPolicies: [`profile:${name}`]
|
|
10532
10908
|
};
|
|
10533
10909
|
}
|
|
10910
|
+
const problems = this.problemsOf(policy, (rule) => findAuthoritiesProfileProblems(name, rule));
|
|
10911
|
+
if (problems.length > 0) return invalidRule(problems, [`profile:${name}`]);
|
|
10534
10912
|
const result = await this.evaluatePolicy(policy, ctx);
|
|
10535
10913
|
if (!result.granted) {
|
|
10536
10914
|
return {
|
|
@@ -10541,6 +10919,16 @@ var AuthoritiesEngine = class {
|
|
|
10541
10919
|
}
|
|
10542
10920
|
return mergeResult(result, { granted: true, evaluatedPolicies: [`profile:${name}`] });
|
|
10543
10921
|
}
|
|
10922
|
+
/** Validate a rule, reusing the result for a rule object seen before. */
|
|
10923
|
+
problemsOf(rule, find) {
|
|
10924
|
+
if (typeof rule !== "object" || rule === null) return find(rule);
|
|
10925
|
+
let problems = this.ruleProblems.get(rule);
|
|
10926
|
+
if (!problems) {
|
|
10927
|
+
problems = find(rule);
|
|
10928
|
+
this.ruleProblems.set(rule, problems);
|
|
10929
|
+
}
|
|
10930
|
+
return problems;
|
|
10931
|
+
}
|
|
10544
10932
|
/**
|
|
10545
10933
|
* Evaluate an array of profile names (AND semantics).
|
|
10546
10934
|
*/
|
|
@@ -10589,7 +10977,7 @@ var AuthoritiesEngine = class {
|
|
|
10589
10977
|
results.push(await this.evaluateNot(policy.not, ctx));
|
|
10590
10978
|
}
|
|
10591
10979
|
if (results.length === 0) {
|
|
10592
|
-
return
|
|
10980
|
+
return invalidRule(["checks nothing"]);
|
|
10593
10981
|
}
|
|
10594
10982
|
return this.combineResults(results, operator);
|
|
10595
10983
|
}
|
|
@@ -10640,14 +11028,15 @@ var AuthoritiesEngine = class {
|
|
|
10640
11028
|
}
|
|
10641
11029
|
/**
|
|
10642
11030
|
* Evaluate async guard functions in sequence.
|
|
10643
|
-
*
|
|
11031
|
+
* Only `true` grants. A string is the denial message; anything else (`false`, but also
|
|
11032
|
+
* `undefined` from a guard that forgot to return, `null`, `0` or an object) denies.
|
|
10644
11033
|
*/
|
|
10645
11034
|
async evaluateGuards(guards, ctx) {
|
|
10646
11035
|
for (let i = 0; i < guards.length; i++) {
|
|
10647
11036
|
const guard = guards[i];
|
|
10648
11037
|
const result = await guard(ctx);
|
|
10649
|
-
if (result
|
|
10650
|
-
const denialMessage = typeof result === "string" ? result : `guard[${i}] denied`;
|
|
11038
|
+
if (result !== true) {
|
|
11039
|
+
const denialMessage = typeof result === "string" ? result : result === false ? `guard[${i}] denied` : `guard[${i}] did not return true (returned ${result === null ? "null" : typeof result})`;
|
|
10651
11040
|
return {
|
|
10652
11041
|
granted: false,
|
|
10653
11042
|
deniedBy: `guards[${i}]: ${denialMessage}`,
|
|
@@ -10705,6 +11094,13 @@ var AuthoritiesEngine = class {
|
|
|
10705
11094
|
evaluatedPolicies: ["not", ...result.evaluatedPolicies]
|
|
10706
11095
|
};
|
|
10707
11096
|
}
|
|
11097
|
+
/**
|
|
11098
|
+
* The policy a profile name stands for when `evaluate()` is given that name, or `undefined`
|
|
11099
|
+
* when no such profile is registered. Lets callers inspect a named rule without evaluating it.
|
|
11100
|
+
*/
|
|
11101
|
+
resolveProfile(name) {
|
|
11102
|
+
return this.profiles.resolve(name);
|
|
11103
|
+
}
|
|
10708
11104
|
};
|
|
10709
11105
|
|
|
10710
11106
|
// libs/auth/src/authorities/authorities.registry.ts
|
|
@@ -10949,6 +11345,7 @@ export {
|
|
|
10949
11345
|
AuthoritiesProfileRegistry,
|
|
10950
11346
|
AuthorityDeniedError,
|
|
10951
11347
|
AuthorizationBase,
|
|
11348
|
+
BUILT_IN_AUTH_PAGE_CSP,
|
|
10952
11349
|
CDN,
|
|
10953
11350
|
CREDENTIALS_ACCESSOR,
|
|
10954
11351
|
CimdClientIdMismatchError,
|
|
@@ -10963,6 +11360,7 @@ export {
|
|
|
10963
11360
|
CredentialProviderAlreadyRegisteredError,
|
|
10964
11361
|
CredentialStorageError,
|
|
10965
11362
|
CredentialsAccessorImpl,
|
|
11363
|
+
DEFAULT_ALLOWED_SCOPES,
|
|
10966
11364
|
DEFAULT_INCREMENTAL_TICKET_TTL_MS,
|
|
10967
11365
|
DEFAULT_RESUME_TTL_MS,
|
|
10968
11366
|
DEFAULT_THEME,
|
|
@@ -11001,6 +11399,9 @@ export {
|
|
|
11001
11399
|
RedisAuthorizationStore,
|
|
11002
11400
|
RedisSessionStore,
|
|
11003
11401
|
SECURE_STORE_ACCESSOR,
|
|
11402
|
+
SIGNIN_BINDING_COOKIE_PREFIX,
|
|
11403
|
+
SIGNIN_BINDING_MAX_AGE_SECONDS,
|
|
11404
|
+
SIGNIN_BINDING_SECURE_COOKIE_PREFIX,
|
|
11004
11405
|
ScopeDeniedError,
|
|
11005
11406
|
SecureStoreAccessorImpl,
|
|
11006
11407
|
SessionCredentialVault,
|
|
@@ -11076,6 +11477,7 @@ export {
|
|
|
11076
11477
|
buildToolConsentPage,
|
|
11077
11478
|
buildUnauthorizedHeader,
|
|
11078
11479
|
buildWwwAuthenticate,
|
|
11480
|
+
builtInAuthPageHeaders,
|
|
11079
11481
|
centeredCardLayout,
|
|
11080
11482
|
checkSsrfProtection,
|
|
11081
11483
|
cimdCacheConfigSchema,
|
|
@@ -11095,6 +11497,7 @@ export {
|
|
|
11095
11497
|
createLayout,
|
|
11096
11498
|
createSecureStore,
|
|
11097
11499
|
createSessionCredentialVault,
|
|
11500
|
+
createSigninBinding,
|
|
11098
11501
|
createTokenStorageAdapter,
|
|
11099
11502
|
credentialProviderConfigSchema,
|
|
11100
11503
|
credentialSchema,
|
|
@@ -11102,7 +11505,7 @@ export {
|
|
|
11102
11505
|
credentialTypeSchema,
|
|
11103
11506
|
customCredentialSchema,
|
|
11104
11507
|
decodeJwtPayloadSafe,
|
|
11105
|
-
|
|
11508
|
+
decryptAesGcm6 as decryptAesGcm,
|
|
11106
11509
|
decryptSessionJson,
|
|
11107
11510
|
decryptValue2 as decryptValue,
|
|
11108
11511
|
defaultSessionRateLimiter,
|
|
@@ -11112,7 +11515,7 @@ export {
|
|
|
11112
11515
|
deriveTypedUser,
|
|
11113
11516
|
detectAuthProviders,
|
|
11114
11517
|
detectedAuthProviderSchema,
|
|
11115
|
-
|
|
11518
|
+
encryptAesGcm6 as encryptAesGcm,
|
|
11116
11519
|
encryptJson,
|
|
11117
11520
|
encryptValue2 as encryptValue,
|
|
11118
11521
|
encryptedBlobSchema,
|
|
@@ -11127,6 +11530,8 @@ export {
|
|
|
11127
11530
|
federatedLoginStateSchema,
|
|
11128
11531
|
federatedProviderItemSchema,
|
|
11129
11532
|
federatedSelectionSchema,
|
|
11533
|
+
findAuthoritiesProfileProblems,
|
|
11534
|
+
findAuthoritiesRuleProblems,
|
|
11130
11535
|
flatRemoteProviderFields,
|
|
11131
11536
|
fromSessionRecord,
|
|
11132
11537
|
generateAuthorizationCode,
|
|
@@ -11138,15 +11543,17 @@ export {
|
|
|
11138
11543
|
getProviderApps,
|
|
11139
11544
|
getProviderScopes,
|
|
11140
11545
|
getTokenSignatureFingerprint,
|
|
11546
|
+
grantScopes,
|
|
11141
11547
|
hasOnlyLocalhostRedirectUris,
|
|
11142
11548
|
headerApplier,
|
|
11143
|
-
|
|
11549
|
+
hkdfSha2565 as hkdfSha256,
|
|
11144
11550
|
incrementalAuthConfigSchema,
|
|
11145
11551
|
isAnonymousSubject,
|
|
11146
11552
|
isCimdClientId,
|
|
11147
11553
|
isFrontMcpCredentials,
|
|
11148
11554
|
isJwt,
|
|
11149
11555
|
isLocalMode,
|
|
11556
|
+
isLoopbackRedirectUri,
|
|
11150
11557
|
isOrchestratedLocal,
|
|
11151
11558
|
isOrchestratedMode,
|
|
11152
11559
|
isOrchestratedRemote,
|
|
@@ -11176,6 +11583,7 @@ export {
|
|
|
11176
11583
|
noopLogger,
|
|
11177
11584
|
normalizeIssuer,
|
|
11178
11585
|
oauthCredentialSchema,
|
|
11586
|
+
openPendingLogin,
|
|
11179
11587
|
orchestratedLocalSchema,
|
|
11180
11588
|
orchestratedRemoteSchema,
|
|
11181
11589
|
parseAuthOptions,
|
|
@@ -11203,6 +11611,7 @@ export {
|
|
|
11203
11611
|
resolveRequiredScopes,
|
|
11204
11612
|
resourceIdRefSchema,
|
|
11205
11613
|
safeDecrypt,
|
|
11614
|
+
sealPendingLogin,
|
|
11206
11615
|
secureStoreConfigSchema,
|
|
11207
11616
|
secureStoreCustomBackendSchema,
|
|
11208
11617
|
secureStoreEncryptionSchema,
|
|
@@ -11213,6 +11622,8 @@ export {
|
|
|
11213
11622
|
signCredentialResumeToken,
|
|
11214
11623
|
signIncrementalAuthTicket,
|
|
11215
11624
|
signSession,
|
|
11625
|
+
signinBindingCookieName,
|
|
11626
|
+
signinBindingMatches,
|
|
11216
11627
|
skippedAppBehaviorSchema,
|
|
11217
11628
|
sseTransportStateSchema,
|
|
11218
11629
|
sshKeyCredentialSchema,
|
|
@@ -11245,5 +11656,6 @@ export {
|
|
|
11245
11656
|
verifyOrParseSession,
|
|
11246
11657
|
verifyPkce,
|
|
11247
11658
|
verifySession,
|
|
11248
|
-
wideLayout
|
|
11659
|
+
wideLayout,
|
|
11660
|
+
withoutSecretFieldValues
|
|
11249
11661
|
};
|