@frontmcp/auth 1.10.15 → 1.11.0-rc.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/browser/authorities/authorities.context.mjs +115 -0
- package/browser/authorities/authorities.engine.mjs +272 -0
- package/browser/authorities/authorities.errors.mjs +59 -0
- package/browser/authorities/authorities.evaluator.mjs +225 -0
- package/browser/authorities/authorities.metadata-augment.mjs +18 -0
- package/browser/authorities/authorities.registry.mjs +112 -0
- package/browser/authorities/authorities.schema.mjs +92 -0
- package/browser/authorities/authorities.scope-mapping.mjs +30 -0
- package/browser/authorities/authorities.validation.mjs +208 -0
- package/browser/authorities/index.mjs +43 -0
- package/browser/authorization/authorization.class.mjs +252 -0
- package/browser/authorization/authorization.types.mjs +64 -0
- package/browser/authorization/dcr-client.registry.mjs +222 -0
- package/browser/authorization/index.mjs +41 -0
- package/browser/authorization/orchestrated.accessor.mjs +86 -0
- package/browser/authorization/orchestrated.authorization.mjs +289 -0
- package/browser/authorization/public.authorization.mjs +124 -0
- package/browser/authorization/transparent.authorization.mjs +130 -0
- package/browser/cimd/cimd-redis.cache.mjs +231 -0
- package/browser/cimd/cimd.cache.mjs +215 -0
- package/browser/cimd/cimd.errors.mjs +142 -0
- package/browser/cimd/cimd.logger.mjs +15 -0
- package/browser/cimd/cimd.service.mjs +376 -0
- package/browser/cimd/cimd.types.mjs +228 -0
- package/browser/cimd/cimd.validator.mjs +217 -0
- package/browser/cimd/index.mjs +63 -0
- package/browser/common/auth-logger.interface.mjs +14 -0
- package/browser/common/index.mjs +6 -0
- package/browser/common/jwt.types.mjs +38 -0
- package/browser/common/session-user.types.mjs +0 -0
- package/browser/common/session.types.mjs +58 -0
- package/browser/common/zod-utils.mjs +0 -0
- package/browser/consent/consent.types.mjs +94 -0
- package/browser/consent/index.mjs +17 -0
- package/browser/context/frontmcp-auth-context.factory.mjs +29 -0
- package/browser/context/frontmcp-auth-context.impl.mjs +112 -0
- package/browser/context/index.mjs +7 -0
- package/browser/detection/auth-provider-detection.mjs +176 -0
- package/browser/detection/index.mjs +19 -0
- package/browser/errors/auth-internal.error.mjs +42 -0
- package/browser/errors/auth-internal.errors.mjs +150 -0
- package/browser/errors/index.mjs +53 -0
- package/browser/fetch/fetch-credential-middleware.mjs +91 -0
- package/browser/fetch/index.mjs +19 -0
- package/browser/index.mjs +573 -0
- package/browser/jwks/index.mjs +9 -0
- package/browser/jwks/jose.loader.mjs +28 -0
- package/browser/jwks/jwks.service.mjs +521 -0
- package/browser/jwks/jwks.utils.mjs +33 -0
- package/browser/options/app-auth.schema.mjs +18 -0
- package/browser/options/index.mjs +89 -0
- package/browser/options/orchestrated.schema.mjs +128 -0
- package/browser/options/public.schema.mjs +39 -0
- package/browser/options/schema.mjs +16 -0
- package/browser/options/shared.schemas.mjs +506 -0
- package/browser/options/static.schema.mjs +41 -0
- package/browser/options/transparent.schema.mjs +43 -0
- package/browser/options/utils.mjs +47 -0
- package/browser/people/index.mjs +15 -0
- package/browser/people/loopback-token.auth.mjs +115 -0
- package/browser/people/people-auth.options.mjs +37 -0
- package/browser/session/authorization-vault.mjs +279 -0
- package/browser/session/authorization.store.mjs +336 -0
- package/browser/session/consent.store.mjs +34 -0
- package/browser/session/credential-resume-link.mjs +43 -0
- package/browser/session/credentials-accessor.impl.mjs +54 -0
- package/browser/session/credentials-accessor.mjs +5 -0
- package/browser/session/encrypted-authorization-vault.mjs +405 -0
- package/browser/session/federated-auth.session.mjs +176 -0
- package/browser/session/incremental-auth-ticket.mjs +42 -0
- package/browser/session/index.mjs +266 -0
- package/browser/session/orchestrated-token.crypto.mjs +47 -0
- package/browser/session/orchestrated-token.store.mjs +286 -0
- package/browser/session/pending-login.mjs +37 -0
- package/browser/session/redis-session.store.mjs +255 -0
- package/browser/session/secure-store-accessor.impl.mjs +78 -0
- package/browser/session/secure-store-accessor.mjs +5 -0
- package/browser/session/secure-store-backends.mjs +111 -0
- package/browser/session/secure-store.factory.mjs +77 -0
- package/browser/session/session-credential-vault.factory.mjs +18 -0
- package/browser/session/session-credential-vault.mjs +243 -0
- package/browser/session/session-crypto.mjs +39 -0
- package/browser/session/session-rate-limiter.mjs +126 -0
- package/browser/session/session.transport.mjs +16 -0
- package/browser/session/signin-binding.mjs +30 -0
- package/browser/session/storage/in-memory-authorization-vault.mjs +28 -0
- package/browser/session/storage/index.mjs +14 -0
- package/browser/session/storage/storage-authorization-vault.mjs +301 -0
- package/browser/session/storage/storage-token-store.mjs +83 -0
- package/browser/session/storage-authorization.store.mjs +134 -0
- package/browser/session/storage-consent.store.mjs +33 -0
- package/browser/session/storage-federated-auth.session.mjs +55 -0
- package/browser/session/storage-orchestrated-token.store.mjs +197 -0
- package/browser/session/token-storage.factory.mjs +58 -0
- package/browser/session/token.refresh.mjs +36 -0
- package/browser/session/token.vault.mjs +61 -0
- package/browser/session/transport-session.types.mjs +108 -0
- package/browser/session/utils/auth-token.utils.mjs +58 -0
- package/browser/session/utils/index.mjs +23 -0
- package/browser/session/utils/session-crypto.utils.mjs +49 -0
- package/browser/session/utils/tiny-ttl-cache.mjs +46 -0
- package/browser/session/vault-encryption.mjs +187 -0
- package/browser/session/vercel-kv-session.store.mjs +230 -0
- package/browser/shared-server/index.mjs +17 -0
- package/browser/shared-server/shared-server-identity.mjs +55 -0
- package/browser/ui/base-layout.mjs +184 -0
- package/browser/ui/index.mjs +51 -0
- package/browser/ui/local-login.helper.mjs +46 -0
- package/browser/ui/templates.mjs +482 -0
- package/browser/utils/audience.validator.mjs +110 -0
- package/browser/utils/authorization-id.utils.mjs +10 -0
- package/browser/utils/index.mjs +45 -0
- package/browser/utils/redirect-uri.utils.mjs +22 -0
- package/browser/utils/scope-grant.utils.mjs +36 -0
- package/browser/utils/token-scopes.utils.mjs +12 -0
- package/browser/utils/www-authenticate.utils.mjs +164 -0
- package/browser/vault/auth-providers.accessor.impl.mjs +236 -0
- package/browser/vault/auth-providers.accessor.mjs +5 -0
- package/browser/vault/auth-providers.registry.mjs +140 -0
- package/browser/vault/auth-providers.types.mjs +47 -0
- package/browser/vault/auth-providers.vault.mjs +206 -0
- package/browser/vault/credential-cache.mjs +187 -0
- package/browser/vault/credential-helpers.mjs +15 -0
- package/browser/vault/credential-loaders/eager-loader.mjs +91 -0
- package/browser/vault/credential-loaders/lazy-loader.mjs +120 -0
- package/browser/vault/index.mjs +35 -0
- package/cimd/cimd.types.d.ts +1 -1
- package/cimd/cimd.types.d.ts.map +1 -1
- package/common/jwt.types.d.ts +1 -1
- package/common/jwt.types.d.ts.map +1 -1
- package/common/session.types.d.ts +9 -1
- package/common/session.types.d.ts.map +1 -1
- package/consent/consent.types.d.ts +1 -1
- package/consent/consent.types.d.ts.map +1 -1
- package/detection/auth-provider-detection.d.ts +1 -1
- package/detection/auth-provider-detection.d.ts.map +1 -1
- package/errors/auth-internal.errors.d.ts +6 -0
- package/errors/auth-internal.errors.d.ts.map +1 -1
- package/errors/index.d.ts +1 -1
- package/errors/index.d.ts.map +1 -1
- package/esm/index.mjs +2 -2
- package/esm/package.json +21 -5
- package/index.d.ts +5 -1
- package/index.d.ts.map +1 -1
- package/index.js +2 -2
- package/options/app-auth.schema.d.ts +19 -1
- package/options/app-auth.schema.d.ts.map +1 -1
- package/options/orchestrated.schema.d.ts +37 -1
- package/options/orchestrated.schema.d.ts.map +1 -1
- package/options/public.schema.d.ts +1 -1
- package/options/public.schema.d.ts.map +1 -1
- package/options/schema.d.ts +19 -1
- package/options/schema.d.ts.map +1 -1
- package/options/shared.schemas.d.ts +10 -14
- package/options/shared.schemas.d.ts.map +1 -1
- package/options/static.schema.d.ts +1 -1
- package/options/static.schema.d.ts.map +1 -1
- package/options/transparent.schema.d.ts +1 -1
- package/options/transparent.schema.d.ts.map +1 -1
- package/package.json +21 -5
- package/people/index.d.ts +3 -0
- package/people/index.d.ts.map +1 -0
- package/people/loopback-token.auth.d.ts +75 -0
- package/people/loopback-token.auth.d.ts.map +1 -0
- package/people/people-auth.options.d.ts +36 -0
- package/people/people-auth.options.d.ts.map +1 -0
- package/session/authorization-vault.d.ts +1 -1
- package/session/authorization-vault.d.ts.map +1 -1
- package/session/encrypted-authorization-vault.d.ts +1 -1
- package/session/encrypted-authorization-vault.d.ts.map +1 -1
- package/session/secure-store.factory.d.ts.map +1 -1
- package/shared-server/index.d.ts +3 -0
- package/shared-server/index.d.ts.map +1 -0
- package/shared-server/shared-server-identity.d.ts +26 -0
- package/shared-server/shared-server-identity.d.ts.map +1 -0
|
@@ -0,0 +1,521 @@
|
|
|
1
|
+
var __frontmcpModule = typeof process !== "undefined" && typeof process.getBuiltinModule === "function" ? process.getBuiltinModule("module") : undefined;
|
|
2
|
+
const require = __frontmcpModule ? __frontmcpModule.createRequire(import.meta.url || 'file:///') : undefined;
|
|
3
|
+
// __frontmcpCreateRequire
|
|
4
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
5
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
6
|
+
}) : x)(function(x) {
|
|
7
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
8
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
// libs/auth/src/jwks/jwks.service.ts
|
|
12
|
+
import {
|
|
13
|
+
bytesToHex,
|
|
14
|
+
createKeyPersistence,
|
|
15
|
+
isProduction,
|
|
16
|
+
isRedirectResponse,
|
|
17
|
+
randomBytes,
|
|
18
|
+
rsaVerify
|
|
19
|
+
} from "@frontmcp/utils";
|
|
20
|
+
import { resolveAndCheckHostname } from "../cimd/cimd.validator.mjs";
|
|
21
|
+
import { noopAuthLogger } from "../common/auth-logger.interface.mjs";
|
|
22
|
+
import { loadJose } from "./jose.loader.mjs";
|
|
23
|
+
import { normalizeIssuer, trimSlash } from "./jwks.utils.mjs";
|
|
24
|
+
var TRANSPARENT_JWT_ALGS = [
|
|
25
|
+
"RS256",
|
|
26
|
+
"RS384",
|
|
27
|
+
"RS512",
|
|
28
|
+
"PS256",
|
|
29
|
+
"PS384",
|
|
30
|
+
"PS512",
|
|
31
|
+
"ES256",
|
|
32
|
+
"ES384",
|
|
33
|
+
"ES512",
|
|
34
|
+
"EdDSA"
|
|
35
|
+
];
|
|
36
|
+
var MAX_JWKS_FETCH_BYTES = 1048576;
|
|
37
|
+
var MAX_JWKS_FETCH_HOPS = 3;
|
|
38
|
+
var UNKNOWN_KID_REFETCH_COOLDOWN_MS = 6e4;
|
|
39
|
+
var MISSING_EXP_ERROR = 'missing required "exp" claim';
|
|
40
|
+
function isMissingExpError(error) {
|
|
41
|
+
if (typeof error !== "object" || error === null) return false;
|
|
42
|
+
const { code, claim, reason } = error;
|
|
43
|
+
return code === "ERR_JWT_CLAIM_VALIDATION_FAILED" && claim === "exp" && reason === "missing";
|
|
44
|
+
}
|
|
45
|
+
var WEAK_KEY_WARNING = `
|
|
46
|
+
\u26A0\uFE0F SECURITY WARNING: OAuth provider is using an RSA key smaller than 2048 bits.
|
|
47
|
+
This is considered insecure and should be updated.
|
|
48
|
+
Please contact your OAuth provider to upgrade their signing keys.
|
|
49
|
+
Verification will proceed but with reduced security guarantees.
|
|
50
|
+
`;
|
|
51
|
+
var JwksService = class {
|
|
52
|
+
opts;
|
|
53
|
+
logger;
|
|
54
|
+
warnedProviders = /* @__PURE__ */ new Set();
|
|
55
|
+
// Orchestrator signing material
|
|
56
|
+
orchestratorKey;
|
|
57
|
+
// Provider JWKS cache (providerId -> jwks + fetchedAt)
|
|
58
|
+
providerJwks = /* @__PURE__ */ new Map();
|
|
59
|
+
// The last key refetch an unknown `kid` started, per provider (see refetchForUnknownKid)
|
|
60
|
+
unknownKidRefetches = /* @__PURE__ */ new Map();
|
|
61
|
+
// Track if key has been initialized (for async loading)
|
|
62
|
+
keyInitialized = false;
|
|
63
|
+
// Promise guard to prevent concurrent key generation
|
|
64
|
+
keyInitPromise;
|
|
65
|
+
// KeyPersistence instance for unified key storage
|
|
66
|
+
keyPersistence;
|
|
67
|
+
constructor(opts) {
|
|
68
|
+
this.logger = opts?.logger ?? noopAuthLogger;
|
|
69
|
+
this.opts = {
|
|
70
|
+
orchestratorAlg: opts?.orchestratorAlg ?? "RS256",
|
|
71
|
+
rotateDays: opts?.rotateDays ?? 30,
|
|
72
|
+
providerJwksTtlMs: opts?.providerJwksTtlMs ?? 6 * 60 * 60 * 1e3,
|
|
73
|
+
// 6h
|
|
74
|
+
networkTimeoutMs: opts?.networkTimeoutMs ?? 5e3
|
|
75
|
+
// 5s
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
// ===========================================================================
|
|
79
|
+
// Key Persistence Helpers
|
|
80
|
+
// ===========================================================================
|
|
81
|
+
/**
|
|
82
|
+
* Get or create the KeyPersistence instance.
|
|
83
|
+
* Returns null if persistence is disabled (production).
|
|
84
|
+
*/
|
|
85
|
+
async getKeyPersistence() {
|
|
86
|
+
if (isProduction()) return null;
|
|
87
|
+
if (!this.keyPersistence) {
|
|
88
|
+
this.keyPersistence = await createKeyPersistence({
|
|
89
|
+
baseDir: ".frontmcp/keys"
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
return this.keyPersistence;
|
|
93
|
+
}
|
|
94
|
+
// ===========================================================================
|
|
95
|
+
// Public JWKS (what /.well-known/jwks.json serves)
|
|
96
|
+
// ===========================================================================
|
|
97
|
+
/** Gateway's public JWKS (publish at /.well-known/jwks.json when orchestrated). */
|
|
98
|
+
async getPublicJwks() {
|
|
99
|
+
return this.getOrchestratorJwks();
|
|
100
|
+
}
|
|
101
|
+
// ===========================================================================
|
|
102
|
+
// Scope-aware verification API
|
|
103
|
+
// ===========================================================================
|
|
104
|
+
/**
|
|
105
|
+
* Verify a token against candidate transparent providers.
|
|
106
|
+
* Ensures JWKS are available (cached/TTL/AS discovery) per provider.
|
|
107
|
+
*/
|
|
108
|
+
async verifyTransparentToken(token, candidates) {
|
|
109
|
+
if (!candidates?.length) return { ok: false, error: "no_providers" };
|
|
110
|
+
const { createLocalJWKSet, decodeProtectedHeader, jwtVerify } = await loadJose();
|
|
111
|
+
let kid;
|
|
112
|
+
try {
|
|
113
|
+
const header = decodeProtectedHeader(token);
|
|
114
|
+
kid = typeof header?.kid === "string" ? header.kid : void 0;
|
|
115
|
+
} catch {
|
|
116
|
+
}
|
|
117
|
+
let missingExp = false;
|
|
118
|
+
for (const p of candidates) {
|
|
119
|
+
let jwks;
|
|
120
|
+
try {
|
|
121
|
+
jwks = await this.getJwksForProvider(p);
|
|
122
|
+
if (kid && !p.jwks?.keys?.length && !jwks?.keys?.some((key) => key.kid === kid)) {
|
|
123
|
+
jwks = await this.refetchForUnknownKid(p) ?? jwks;
|
|
124
|
+
}
|
|
125
|
+
if (!jwks?.keys?.length) continue;
|
|
126
|
+
const JWKS = createLocalJWKSet(jwks);
|
|
127
|
+
const issuerConstraint = this.issuerConstraintFor(p);
|
|
128
|
+
const { payload, protectedHeader } = await jwtVerify(token, JWKS, {
|
|
129
|
+
// Pin to asymmetric algorithms so a symmetric key in the provider JWKS
|
|
130
|
+
// can't be used to accept an HMAC-signed token, and `none` is refused.
|
|
131
|
+
algorithms: [...TRANSPARENT_JWT_ALGS],
|
|
132
|
+
...issuerConstraint ? { issuer: issuerConstraint } : {},
|
|
133
|
+
// A bearer token without `exp` would be valid forever (#272).
|
|
134
|
+
requiredClaims: ["exp"]
|
|
135
|
+
});
|
|
136
|
+
return {
|
|
137
|
+
ok: true,
|
|
138
|
+
issuer: payload?.iss,
|
|
139
|
+
sub: payload?.sub,
|
|
140
|
+
providerId: p.id,
|
|
141
|
+
header: protectedHeader,
|
|
142
|
+
payload
|
|
143
|
+
};
|
|
144
|
+
} catch (e) {
|
|
145
|
+
if (this.isWeakKeyError(e)) {
|
|
146
|
+
const fallbackJwks = jwks ?? await this.getJwksForProvider(p);
|
|
147
|
+
if (fallbackJwks?.keys?.length) {
|
|
148
|
+
const fallbackResult = await this.verifyWithWeakKey(token, fallbackJwks, p);
|
|
149
|
+
if (fallbackResult.ok) {
|
|
150
|
+
return fallbackResult;
|
|
151
|
+
}
|
|
152
|
+
if (fallbackResult.error === "missing_exp") missingExp = true;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
if (isMissingExpError(e)) missingExp = true;
|
|
156
|
+
this.logger.debug("[JwksService] Failed to verify token for provider: %s", p.id, e);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
if (missingExp) return { ok: false, error: MISSING_EXP_ERROR };
|
|
160
|
+
return { ok: false, error: `no_provider_verified${kid ? ` (kid=${kid})` : ""}` };
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Issuer constraint passed to `jose` for a provider: the configured issuer
|
|
164
|
+
* URL plus any explicitly configured `additionalIssuers`, each accepted with
|
|
165
|
+
* and without a trailing slash (`jose` compares `iss` byte-for-byte and IdPs
|
|
166
|
+
* differ on the trailing slash).
|
|
167
|
+
*
|
|
168
|
+
* Returns `undefined` ONLY when the provider explicitly opts out via
|
|
169
|
+
* `verifyIssuer: false`, which disables issuer checking entirely. Otherwise
|
|
170
|
+
* the set is derived ONLY from configuration \u2014 the token's own `iss` claim
|
|
171
|
+
* must never be appended, since an allowlist that contains the unverified
|
|
172
|
+
* claim accepts every issuer (GHSA-hvvp-67p3-j379). An empty/whitespace
|
|
173
|
+
* `issuerUrl` yields a set that no real token can satisfy (safe fail), never
|
|
174
|
+
* a silent bypass.
|
|
175
|
+
*/
|
|
176
|
+
issuerConstraintFor(p) {
|
|
177
|
+
if (p.verifyIssuer === false) return void 0;
|
|
178
|
+
const issuers = /* @__PURE__ */ new Set();
|
|
179
|
+
for (const candidate of [p.issuerUrl, ...p.additionalIssuers ?? []]) {
|
|
180
|
+
const normalized = normalizeIssuer(candidate);
|
|
181
|
+
if (!normalized) continue;
|
|
182
|
+
issuers.add(normalized);
|
|
183
|
+
issuers.add(`${normalized}/`);
|
|
184
|
+
}
|
|
185
|
+
return [...issuers];
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Check if the error is due to weak RSA key (< 2048 bits)
|
|
189
|
+
*/
|
|
190
|
+
isWeakKeyError(error) {
|
|
191
|
+
const message = typeof error === "object" && error !== null && "message" in error && typeof error.message === "string" ? error.message : String(error);
|
|
192
|
+
return message.includes("modulusLength") && message.includes("2048");
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Fallback verification for providers using RSA keys smaller than 2048 bits.
|
|
196
|
+
* Logs a security warning but allows verification to proceed.
|
|
197
|
+
*/
|
|
198
|
+
async verifyWithWeakKey(token, jwks, provider) {
|
|
199
|
+
try {
|
|
200
|
+
const parts = token.split(".");
|
|
201
|
+
if (parts.length !== 3) {
|
|
202
|
+
return { ok: false, error: "invalid_token_format" };
|
|
203
|
+
}
|
|
204
|
+
const [headerB64, payloadB64, signatureB64] = parts;
|
|
205
|
+
const header = JSON.parse(Buffer.from(headerB64, "base64url").toString("utf8"));
|
|
206
|
+
const payload = JSON.parse(Buffer.from(payloadB64, "base64url").toString("utf8"));
|
|
207
|
+
const matchingKey = this.findMatchingKey(jwks, header);
|
|
208
|
+
if (!matchingKey) {
|
|
209
|
+
return { ok: false, error: "no_matching_key" };
|
|
210
|
+
}
|
|
211
|
+
const signatureInput = `${headerB64}.${payloadB64}`;
|
|
212
|
+
const signature = Buffer.from(signatureB64, "base64url");
|
|
213
|
+
const jwtAlg = typeof header.alg === "string" ? header.alg : void 0;
|
|
214
|
+
if (!jwtAlg) {
|
|
215
|
+
return { ok: false, error: "missing_alg" };
|
|
216
|
+
}
|
|
217
|
+
const isValid = await rsaVerify(
|
|
218
|
+
jwtAlg,
|
|
219
|
+
Buffer.from(signatureInput),
|
|
220
|
+
matchingKey,
|
|
221
|
+
signature
|
|
222
|
+
);
|
|
223
|
+
if (!isValid) {
|
|
224
|
+
return { ok: false, error: "signature_invalid" };
|
|
225
|
+
}
|
|
226
|
+
if (provider.verifyIssuer !== false) {
|
|
227
|
+
const payloadIssuerRaw = typeof payload.iss === "string" ? payload.iss : void 0;
|
|
228
|
+
if (!payloadIssuerRaw) {
|
|
229
|
+
return { ok: false, error: "issuer_mismatch" };
|
|
230
|
+
}
|
|
231
|
+
const trustedIssuers = new Set(
|
|
232
|
+
[provider.issuerUrl, ...provider.additionalIssuers ?? []].map((issuer) => normalizeIssuer(issuer))
|
|
233
|
+
);
|
|
234
|
+
const payloadIssuer = normalizeIssuer(payloadIssuerRaw);
|
|
235
|
+
if (!trustedIssuers.has(payloadIssuer)) {
|
|
236
|
+
return { ok: false, error: "issuer_mismatch" };
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
const nowSec = Math.floor(Date.now() / 1e3);
|
|
240
|
+
if (payload.exp === void 0) {
|
|
241
|
+
return { ok: false, error: "missing_exp" };
|
|
242
|
+
}
|
|
243
|
+
if (typeof payload.exp !== "number" || !Number.isFinite(payload.exp) || payload.exp <= nowSec) {
|
|
244
|
+
return { ok: false, error: "token_expired" };
|
|
245
|
+
}
|
|
246
|
+
if (payload.nbf !== void 0 && (typeof payload.nbf !== "number" || !Number.isFinite(payload.nbf) || payload.nbf > nowSec)) {
|
|
247
|
+
return { ok: false, error: "token_not_yet_valid" };
|
|
248
|
+
}
|
|
249
|
+
if (!this.warnedProviders.has(provider.id)) {
|
|
250
|
+
this.warnedProviders.add(provider.id);
|
|
251
|
+
this.logger.warn(WEAK_KEY_WARNING);
|
|
252
|
+
this.logger.warn(" Provider: %s (%s)", provider.id, provider.issuerUrl);
|
|
253
|
+
}
|
|
254
|
+
return {
|
|
255
|
+
ok: true,
|
|
256
|
+
issuer: payload.iss,
|
|
257
|
+
sub: payload.sub,
|
|
258
|
+
providerId: provider.id,
|
|
259
|
+
header,
|
|
260
|
+
payload
|
|
261
|
+
};
|
|
262
|
+
} catch (err) {
|
|
263
|
+
const message = err instanceof Error ? err.message : "unknown";
|
|
264
|
+
return { ok: false, error: `weak_key_verification_failed: ${message}` };
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Find a matching key from JWKS based on token header
|
|
269
|
+
*/
|
|
270
|
+
findMatchingKey(jwks, header) {
|
|
271
|
+
if (header.kid) {
|
|
272
|
+
return jwks.keys.find((k) => k.kid === header.kid);
|
|
273
|
+
}
|
|
274
|
+
if (header.alg) {
|
|
275
|
+
const byAlg = jwks.keys.find((k) => k.alg === header.alg || k.kty === "RSA" && header.alg?.startsWith("RS"));
|
|
276
|
+
if (byAlg) return byAlg;
|
|
277
|
+
}
|
|
278
|
+
return jwks.keys.find((k) => k.kty === "RSA");
|
|
279
|
+
}
|
|
280
|
+
// ===========================================================================
|
|
281
|
+
// Provider JWKS (cache + preload + discovery)
|
|
282
|
+
// ===========================================================================
|
|
283
|
+
/** Directly set provider JWKS (e.g., inline keys from config). */
|
|
284
|
+
setProviderJwks(providerId, jwks) {
|
|
285
|
+
this.providerJwks.set(providerId, { jwks, fetchedAt: Date.now() });
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Ensure JWKS for a provider:
|
|
289
|
+
* 1) inline jwks (if provided) \u2192 cache & return
|
|
290
|
+
* 2) cached & fresh (TTL) \u2192 return
|
|
291
|
+
* 3) explicit jwksUri \u2192 fetch, cache, return
|
|
292
|
+
* 4) `<issuer>/.well-known/jwks.json` \u2192 fetch, cache, return
|
|
293
|
+
* 5) discover jwks_uri \u2192 the issuer's OAuth authorization server
|
|
294
|
+
* metadata (RFC 8414), else its OpenID configuration (OpenID Connect
|
|
295
|
+
* Discovery 1.0 \u00a74, where Google, Okta, Auth0 and Entra publish it),
|
|
296
|
+
* then fetch jwks_uri, cache, return
|
|
297
|
+
*/
|
|
298
|
+
async getJwksForProvider(ref) {
|
|
299
|
+
if (ref.jwks?.keys?.length) {
|
|
300
|
+
this.setProviderJwks(ref.id, ref.jwks);
|
|
301
|
+
return ref.jwks;
|
|
302
|
+
}
|
|
303
|
+
const cached = this.providerJwks.get(ref.id);
|
|
304
|
+
if (cached && Date.now() - cached.fetchedAt < this.opts.providerJwksTtlMs) {
|
|
305
|
+
return cached.jwks;
|
|
306
|
+
}
|
|
307
|
+
const fetched = await this.fetchProviderJwks(ref);
|
|
308
|
+
if (fetched) return fetched;
|
|
309
|
+
const maxStaleMs = Math.max(this.opts.providerJwksTtlMs * 4, 6e4);
|
|
310
|
+
if (cached && Date.now() - cached.fetchedAt < maxStaleMs) {
|
|
311
|
+
return cached.jwks;
|
|
312
|
+
}
|
|
313
|
+
return void 0;
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Fetch a provider's keys again for a token whose `kid` the cached keys don't have (a key the
|
|
317
|
+
* provider started using since), ahead of the cache's TTL. At most one refetch per provider per
|
|
318
|
+
* {@link UNKNOWN_KID_REFETCH_COOLDOWN_MS}: tokens that arrive meanwhile wait for the one in flight or
|
|
319
|
+
* use its result, so a flood of tokens with made-up `kid`s can't hammer the provider. Only freshly
|
|
320
|
+
* fetched keys are returned: a failed refetch never revives cached keys past the stale window.
|
|
321
|
+
*/
|
|
322
|
+
refetchForUnknownKid(ref) {
|
|
323
|
+
let refetch = this.unknownKidRefetches.get(ref.id);
|
|
324
|
+
if (!refetch || Date.now() - refetch.startedAt >= UNKNOWN_KID_REFETCH_COOLDOWN_MS) {
|
|
325
|
+
refetch = { startedAt: Date.now(), done: this.fetchProviderJwks(ref) };
|
|
326
|
+
this.unknownKidRefetches.set(ref.id, refetch);
|
|
327
|
+
}
|
|
328
|
+
return refetch.done;
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Fetch a provider's keys, and cache them: from `jwksUri`, else the conventional location, else
|
|
332
|
+
* the `jwks_uri` of the issuer's OAuth or OpenID metadata. Every URL goes through the same scheme
|
|
333
|
+
* and SSRF checks (`fetchJson`), `jwks_uri` included.
|
|
334
|
+
*/
|
|
335
|
+
async fetchProviderJwks(ref) {
|
|
336
|
+
if (ref.jwksUri) {
|
|
337
|
+
const fromUri = await this.tryFetchJwks(ref.id, ref.jwksUri);
|
|
338
|
+
if (fromUri?.keys?.length) return fromUri;
|
|
339
|
+
}
|
|
340
|
+
const issuer = trimSlash(ref.issuerUrl);
|
|
341
|
+
const fromWellKnown = await this.tryFetchJwks(ref.id, `${issuer}/.well-known/jwks.json`);
|
|
342
|
+
if (fromWellKnown?.keys?.length) return fromWellKnown;
|
|
343
|
+
for (const document of ["oauth-authorization-server", "openid-configuration"]) {
|
|
344
|
+
const meta = await this.tryFetchAsMeta(`${issuer}/.well-known/${document}`);
|
|
345
|
+
const uri = meta && typeof meta === "object" && meta["jwks_uri"] ? String(meta["jwks_uri"]) : void 0;
|
|
346
|
+
if (uri) {
|
|
347
|
+
const fromMeta = await this.tryFetchJwks(ref.id, uri);
|
|
348
|
+
if (fromMeta?.keys?.length) return fromMeta;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
return void 0;
|
|
352
|
+
}
|
|
353
|
+
// ===========================================================================
|
|
354
|
+
// Orchestrator keys (generation/rotation)
|
|
355
|
+
// ===========================================================================
|
|
356
|
+
/** Return the orchestrator public JWKS (generates/rotates as needed). */
|
|
357
|
+
async getOrchestratorJwks() {
|
|
358
|
+
await this.ensureOrchestratorKey();
|
|
359
|
+
return this.orchestratorKey.publicJwk;
|
|
360
|
+
}
|
|
361
|
+
/** Return private signing key + kid for issuing orchestrator tokens. */
|
|
362
|
+
async getOrchestratorSigningKey() {
|
|
363
|
+
await this.ensureOrchestratorKey();
|
|
364
|
+
return { kid: this.orchestratorKey.kid, key: this.orchestratorKey.privateKey, alg: this.opts.orchestratorAlg };
|
|
365
|
+
}
|
|
366
|
+
// ===========================================================================
|
|
367
|
+
// Internals (fetch, rotation, helpers)
|
|
368
|
+
// ===========================================================================
|
|
369
|
+
async tryFetchJwks(providerId, uri) {
|
|
370
|
+
try {
|
|
371
|
+
const jwks = await this.fetchJson(uri);
|
|
372
|
+
if (jwks?.keys?.length) {
|
|
373
|
+
this.setProviderJwks(providerId, jwks);
|
|
374
|
+
return jwks;
|
|
375
|
+
}
|
|
376
|
+
} catch {
|
|
377
|
+
}
|
|
378
|
+
return void 0;
|
|
379
|
+
}
|
|
380
|
+
async tryFetchAsMeta(url) {
|
|
381
|
+
try {
|
|
382
|
+
return await this.fetchJson(url);
|
|
383
|
+
} catch {
|
|
384
|
+
return void 0;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
async fetchJson(url) {
|
|
388
|
+
const ctl = typeof AbortController !== "undefined" ? new AbortController() : void 0;
|
|
389
|
+
const timer = setTimeout(() => ctl?.abort(), this.opts.networkTimeoutMs);
|
|
390
|
+
try {
|
|
391
|
+
let currentUrl = url;
|
|
392
|
+
for (let hop = 0; ; hop++) {
|
|
393
|
+
const parsed = new URL(currentUrl);
|
|
394
|
+
const host = parsed.hostname.toLowerCase();
|
|
395
|
+
const isLocalhost = host === "localhost" || host === "127.0.0.1" || host === "::1" || host === "[::1]" || host.endsWith(".localhost");
|
|
396
|
+
if (parsed.protocol !== "https:" && !(parsed.protocol === "http:" && (isLocalhost || !isProduction()))) {
|
|
397
|
+
throw new Error(`insecure scheme "${parsed.protocol}"`);
|
|
398
|
+
}
|
|
399
|
+
if (!(isLocalhost && !isProduction())) {
|
|
400
|
+
const ssrf = await resolveAndCheckHostname(parsed.hostname);
|
|
401
|
+
if (!ssrf.allowed) throw new Error(`blocked host: ${ssrf.reason}`);
|
|
402
|
+
}
|
|
403
|
+
const res = await fetch(currentUrl, {
|
|
404
|
+
method: "GET",
|
|
405
|
+
headers: { accept: "application/json" },
|
|
406
|
+
signal: ctl?.signal,
|
|
407
|
+
// Follow redirects manually so each hop is re-validated (scheme + SSRF).
|
|
408
|
+
redirect: "manual"
|
|
409
|
+
});
|
|
410
|
+
if (isRedirectResponse(res)) {
|
|
411
|
+
const location = res.headers.get("location");
|
|
412
|
+
if (!location) throw new Error("redirect without a readable Location header");
|
|
413
|
+
if (hop >= MAX_JWKS_FETCH_HOPS) throw new Error("too many redirects");
|
|
414
|
+
currentUrl = new URL(location, currentUrl).toString();
|
|
415
|
+
continue;
|
|
416
|
+
}
|
|
417
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
418
|
+
const contentLength = res.headers.get("content-length");
|
|
419
|
+
if (contentLength && Number(contentLength) > MAX_JWKS_FETCH_BYTES) {
|
|
420
|
+
throw new Error("response too large");
|
|
421
|
+
}
|
|
422
|
+
const text = await res.text();
|
|
423
|
+
if (text.length > MAX_JWKS_FETCH_BYTES) {
|
|
424
|
+
throw new Error("response too large");
|
|
425
|
+
}
|
|
426
|
+
return JSON.parse(text);
|
|
427
|
+
}
|
|
428
|
+
} finally {
|
|
429
|
+
clearTimeout(timer);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
async ensureOrchestratorKey() {
|
|
433
|
+
const now = Date.now();
|
|
434
|
+
const maxAge = this.opts.rotateDays * 24 * 60 * 60 * 1e3;
|
|
435
|
+
if (this.orchestratorKey && now - this.orchestratorKey.createdAt <= maxAge) {
|
|
436
|
+
return;
|
|
437
|
+
}
|
|
438
|
+
if (this.keyInitPromise) {
|
|
439
|
+
await this.keyInitPromise;
|
|
440
|
+
return;
|
|
441
|
+
}
|
|
442
|
+
this.keyInitPromise = this.initializeOrchestratorKey(now, maxAge);
|
|
443
|
+
try {
|
|
444
|
+
await this.keyInitPromise;
|
|
445
|
+
} finally {
|
|
446
|
+
this.keyInitPromise = void 0;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
async initializeOrchestratorKey(now, maxAge) {
|
|
450
|
+
const persistence = await this.getKeyPersistence();
|
|
451
|
+
if (persistence && !this.keyInitialized) {
|
|
452
|
+
this.keyInitialized = true;
|
|
453
|
+
const loaded = await persistence.getAsymmetric("jwks-orchestrator");
|
|
454
|
+
if (loaded && now - loaded.createdAt <= maxAge) {
|
|
455
|
+
if (loaded.alg !== this.opts.orchestratorAlg) {
|
|
456
|
+
this.logger.warn(
|
|
457
|
+
"[JwksService] Persisted key algorithm (%s) doesn't match config (%s), generating new key",
|
|
458
|
+
loaded.alg,
|
|
459
|
+
this.opts.orchestratorAlg
|
|
460
|
+
);
|
|
461
|
+
} else {
|
|
462
|
+
try {
|
|
463
|
+
const { createPrivateKey } = __require("node:crypto");
|
|
464
|
+
const privateKey = createPrivateKey({
|
|
465
|
+
key: loaded.privateKey,
|
|
466
|
+
format: "jwk"
|
|
467
|
+
});
|
|
468
|
+
this.orchestratorKey = {
|
|
469
|
+
kid: loaded.kid,
|
|
470
|
+
privateKey,
|
|
471
|
+
publicJwk: loaded.publicJwk,
|
|
472
|
+
createdAt: loaded.createdAt
|
|
473
|
+
};
|
|
474
|
+
return;
|
|
475
|
+
} catch (error) {
|
|
476
|
+
this.logger.warn(
|
|
477
|
+
"[JwksService] Failed to load persisted key: %s, generating new key",
|
|
478
|
+
error.message
|
|
479
|
+
);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
this.orchestratorKey = this.generateKey(this.opts.orchestratorAlg);
|
|
485
|
+
this.keyInitialized = true;
|
|
486
|
+
if (persistence) {
|
|
487
|
+
try {
|
|
488
|
+
await persistence.set({
|
|
489
|
+
type: "asymmetric",
|
|
490
|
+
kid: this.orchestratorKey.kid,
|
|
491
|
+
alg: this.opts.orchestratorAlg,
|
|
492
|
+
privateKey: this.orchestratorKey.privateKey.export({ format: "jwk" }),
|
|
493
|
+
publicJwk: this.orchestratorKey.publicJwk,
|
|
494
|
+
createdAt: this.orchestratorKey.createdAt,
|
|
495
|
+
version: 1
|
|
496
|
+
});
|
|
497
|
+
} catch (error) {
|
|
498
|
+
this.logger.warn("[JwksService] Failed to persist dev key: %s", error.message);
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
generateKey(alg) {
|
|
503
|
+
const { generateKeyPairSync } = __require("node:crypto");
|
|
504
|
+
if (alg === "RS256") {
|
|
505
|
+
const { privateKey, publicKey } = generateKeyPairSync("rsa", { modulusLength: 2048 });
|
|
506
|
+
const kid = bytesToHex(randomBytes(8));
|
|
507
|
+
const publicJwk = publicKey.export({ format: "jwk" });
|
|
508
|
+
Object.assign(publicJwk, { kid, alg: "RS256", use: "sig", kty: "RSA" });
|
|
509
|
+
return { kid, privateKey, publicJwk: { keys: [publicJwk] }, createdAt: Date.now() };
|
|
510
|
+
} else {
|
|
511
|
+
const { privateKey, publicKey } = generateKeyPairSync("ec", { namedCurve: "P-256" });
|
|
512
|
+
const kid = bytesToHex(randomBytes(8));
|
|
513
|
+
const publicJwk = publicKey.export({ format: "jwk" });
|
|
514
|
+
Object.assign(publicJwk, { kid, alg: "ES256", use: "sig", kty: "EC" });
|
|
515
|
+
return { kid, privateKey, publicJwk: { keys: [publicJwk] }, createdAt: Date.now() };
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
};
|
|
519
|
+
export {
|
|
520
|
+
JwksService
|
|
521
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// libs/auth/src/jwks/jwks.utils.ts
|
|
2
|
+
function trimSlash(s) {
|
|
3
|
+
const str = s ?? "";
|
|
4
|
+
let end = str.length;
|
|
5
|
+
while (end > 0 && str[end - 1] === "/") {
|
|
6
|
+
end--;
|
|
7
|
+
}
|
|
8
|
+
return str.slice(0, end);
|
|
9
|
+
}
|
|
10
|
+
function normalizeIssuer(u) {
|
|
11
|
+
return trimSlash(String(u ?? ""));
|
|
12
|
+
}
|
|
13
|
+
function decodeJwtPayloadSafe(token) {
|
|
14
|
+
if (!token) return void 0;
|
|
15
|
+
const parts = token.split(".");
|
|
16
|
+
if (parts.length < 2) return void 0;
|
|
17
|
+
try {
|
|
18
|
+
const b64 = parts[1].replace(/-/g, "+").replace(/_/g, "/");
|
|
19
|
+
const json = typeof Buffer !== "undefined" ? Buffer.from(b64, "base64").toString("utf8") : (
|
|
20
|
+
// browser fallback
|
|
21
|
+
atob(b64)
|
|
22
|
+
);
|
|
23
|
+
const obj = JSON.parse(json);
|
|
24
|
+
return obj && typeof obj === "object" && !Array.isArray(obj) ? obj : void 0;
|
|
25
|
+
} catch {
|
|
26
|
+
return void 0;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export {
|
|
30
|
+
decodeJwtPayloadSafe,
|
|
31
|
+
normalizeIssuer,
|
|
32
|
+
trimSlash
|
|
33
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// libs/auth/src/options/app-auth.schema.ts
|
|
2
|
+
import { internalZ as z } from "@frontmcp/lazy-zod";
|
|
3
|
+
import { localAuthSchema, remoteAuthSchema } from "./orchestrated.schema.mjs";
|
|
4
|
+
import { publicAuthOptionsSchema } from "./public.schema.mjs";
|
|
5
|
+
import { transparentAuthOptionsSchema } from "./transparent.schema.mjs";
|
|
6
|
+
var standaloneOptionSchema = {
|
|
7
|
+
standalone: z.boolean().optional(),
|
|
8
|
+
excludeFromParent: z.boolean().optional()
|
|
9
|
+
};
|
|
10
|
+
var appAuthOptionsSchema = z.union([
|
|
11
|
+
publicAuthOptionsSchema.extend(standaloneOptionSchema),
|
|
12
|
+
transparentAuthOptionsSchema.extend(standaloneOptionSchema),
|
|
13
|
+
localAuthSchema.extend(standaloneOptionSchema),
|
|
14
|
+
remoteAuthSchema.extend(standaloneOptionSchema)
|
|
15
|
+
]);
|
|
16
|
+
export {
|
|
17
|
+
appAuthOptionsSchema
|
|
18
|
+
};
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
// libs/auth/src/options/index.ts
|
|
2
|
+
import {
|
|
3
|
+
publicAccessConfigSchema,
|
|
4
|
+
localSigningConfigSchema,
|
|
5
|
+
providerConfigSchema,
|
|
6
|
+
remoteProviderConfigSchema,
|
|
7
|
+
flatRemoteProviderFields,
|
|
8
|
+
tokenStorageConfigSchema,
|
|
9
|
+
tokenStorageSqliteSchema,
|
|
10
|
+
secureStoreConfigSchema,
|
|
11
|
+
secureStoreScopeSchema,
|
|
12
|
+
secureStoreEncryptionSchema,
|
|
13
|
+
secureStoreCustomBackendSchema,
|
|
14
|
+
tokenRefreshConfigSchema,
|
|
15
|
+
skippedAppBehaviorSchema,
|
|
16
|
+
consentConfigSchema,
|
|
17
|
+
federatedAuthConfigSchema,
|
|
18
|
+
incrementalAuthConfigSchema,
|
|
19
|
+
upstreamProviderSchema,
|
|
20
|
+
localDcrClientSchema,
|
|
21
|
+
localDcrConfigSchema
|
|
22
|
+
} from "./shared.schemas.mjs";
|
|
23
|
+
import { publicAuthOptionsSchema } from "./public.schema.mjs";
|
|
24
|
+
import { staticAuthOptionsSchema } from "./static.schema.mjs";
|
|
25
|
+
import { transparentAuthOptionsSchema } from "./transparent.schema.mjs";
|
|
26
|
+
import {
|
|
27
|
+
localAuthSchema,
|
|
28
|
+
remoteAuthSchema,
|
|
29
|
+
loginConfigSchema,
|
|
30
|
+
authenticateFnSchema,
|
|
31
|
+
orchestratedLocalSchema,
|
|
32
|
+
orchestratedRemoteSchema
|
|
33
|
+
} from "./orchestrated.schema.mjs";
|
|
34
|
+
import { authOptionsSchema } from "./schema.mjs";
|
|
35
|
+
import { appAuthOptionsSchema } from "./app-auth.schema.mjs";
|
|
36
|
+
import {
|
|
37
|
+
parseAuthOptions,
|
|
38
|
+
isPublicMode,
|
|
39
|
+
isStaticMode,
|
|
40
|
+
isTransparentMode,
|
|
41
|
+
isLocalMode,
|
|
42
|
+
isRemoteMode,
|
|
43
|
+
isOrchestratedMode,
|
|
44
|
+
isOrchestratedLocal,
|
|
45
|
+
isOrchestratedRemote,
|
|
46
|
+
allowsPublicAccess
|
|
47
|
+
} from "./utils.mjs";
|
|
48
|
+
export {
|
|
49
|
+
allowsPublicAccess,
|
|
50
|
+
appAuthOptionsSchema,
|
|
51
|
+
authOptionsSchema,
|
|
52
|
+
authenticateFnSchema,
|
|
53
|
+
consentConfigSchema,
|
|
54
|
+
federatedAuthConfigSchema,
|
|
55
|
+
flatRemoteProviderFields,
|
|
56
|
+
incrementalAuthConfigSchema,
|
|
57
|
+
isLocalMode,
|
|
58
|
+
isOrchestratedLocal,
|
|
59
|
+
isOrchestratedMode,
|
|
60
|
+
isOrchestratedRemote,
|
|
61
|
+
isPublicMode,
|
|
62
|
+
isRemoteMode,
|
|
63
|
+
isStaticMode,
|
|
64
|
+
isTransparentMode,
|
|
65
|
+
localAuthSchema,
|
|
66
|
+
localDcrClientSchema,
|
|
67
|
+
localDcrConfigSchema,
|
|
68
|
+
localSigningConfigSchema,
|
|
69
|
+
loginConfigSchema,
|
|
70
|
+
orchestratedLocalSchema,
|
|
71
|
+
orchestratedRemoteSchema,
|
|
72
|
+
parseAuthOptions,
|
|
73
|
+
providerConfigSchema,
|
|
74
|
+
publicAccessConfigSchema,
|
|
75
|
+
publicAuthOptionsSchema,
|
|
76
|
+
remoteAuthSchema,
|
|
77
|
+
remoteProviderConfigSchema,
|
|
78
|
+
secureStoreConfigSchema,
|
|
79
|
+
secureStoreCustomBackendSchema,
|
|
80
|
+
secureStoreEncryptionSchema,
|
|
81
|
+
secureStoreScopeSchema,
|
|
82
|
+
skippedAppBehaviorSchema,
|
|
83
|
+
staticAuthOptionsSchema,
|
|
84
|
+
tokenRefreshConfigSchema,
|
|
85
|
+
tokenStorageConfigSchema,
|
|
86
|
+
tokenStorageSqliteSchema,
|
|
87
|
+
transparentAuthOptionsSchema,
|
|
88
|
+
upstreamProviderSchema
|
|
89
|
+
};
|