@frontmcp/auth 1.10.16 → 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.
Files changed (175) hide show
  1. package/browser/authorities/authorities.context.mjs +115 -0
  2. package/browser/authorities/authorities.engine.mjs +272 -0
  3. package/browser/authorities/authorities.errors.mjs +59 -0
  4. package/browser/authorities/authorities.evaluator.mjs +225 -0
  5. package/browser/authorities/authorities.metadata-augment.mjs +18 -0
  6. package/browser/authorities/authorities.registry.mjs +112 -0
  7. package/browser/authorities/authorities.schema.mjs +92 -0
  8. package/browser/authorities/authorities.scope-mapping.mjs +30 -0
  9. package/browser/authorities/authorities.validation.mjs +208 -0
  10. package/browser/authorities/index.mjs +43 -0
  11. package/browser/authorization/authorization.class.mjs +252 -0
  12. package/browser/authorization/authorization.types.mjs +64 -0
  13. package/browser/authorization/dcr-client.registry.mjs +222 -0
  14. package/browser/authorization/index.mjs +41 -0
  15. package/browser/authorization/orchestrated.accessor.mjs +86 -0
  16. package/browser/authorization/orchestrated.authorization.mjs +289 -0
  17. package/browser/authorization/public.authorization.mjs +124 -0
  18. package/browser/authorization/transparent.authorization.mjs +130 -0
  19. package/browser/cimd/cimd-redis.cache.mjs +231 -0
  20. package/browser/cimd/cimd.cache.mjs +215 -0
  21. package/browser/cimd/cimd.errors.mjs +142 -0
  22. package/browser/cimd/cimd.logger.mjs +15 -0
  23. package/browser/cimd/cimd.service.mjs +376 -0
  24. package/browser/cimd/cimd.types.mjs +228 -0
  25. package/browser/cimd/cimd.validator.mjs +217 -0
  26. package/browser/cimd/index.mjs +63 -0
  27. package/browser/common/auth-logger.interface.mjs +14 -0
  28. package/browser/common/index.mjs +6 -0
  29. package/browser/common/jwt.types.mjs +38 -0
  30. package/browser/common/session-user.types.mjs +0 -0
  31. package/browser/common/session.types.mjs +58 -0
  32. package/browser/common/zod-utils.mjs +0 -0
  33. package/browser/consent/consent.types.mjs +94 -0
  34. package/browser/consent/index.mjs +17 -0
  35. package/browser/context/frontmcp-auth-context.factory.mjs +29 -0
  36. package/browser/context/frontmcp-auth-context.impl.mjs +112 -0
  37. package/browser/context/index.mjs +7 -0
  38. package/browser/detection/auth-provider-detection.mjs +176 -0
  39. package/browser/detection/index.mjs +19 -0
  40. package/browser/errors/auth-internal.error.mjs +42 -0
  41. package/browser/errors/auth-internal.errors.mjs +150 -0
  42. package/browser/errors/index.mjs +53 -0
  43. package/browser/fetch/fetch-credential-middleware.mjs +91 -0
  44. package/browser/fetch/index.mjs +19 -0
  45. package/browser/index.mjs +573 -0
  46. package/browser/jwks/index.mjs +9 -0
  47. package/browser/jwks/jose.loader.mjs +28 -0
  48. package/browser/jwks/jwks.service.mjs +521 -0
  49. package/browser/jwks/jwks.utils.mjs +33 -0
  50. package/browser/options/app-auth.schema.mjs +18 -0
  51. package/browser/options/index.mjs +89 -0
  52. package/browser/options/orchestrated.schema.mjs +128 -0
  53. package/browser/options/public.schema.mjs +39 -0
  54. package/browser/options/schema.mjs +16 -0
  55. package/browser/options/shared.schemas.mjs +506 -0
  56. package/browser/options/static.schema.mjs +41 -0
  57. package/browser/options/transparent.schema.mjs +43 -0
  58. package/browser/options/utils.mjs +47 -0
  59. package/browser/people/index.mjs +15 -0
  60. package/browser/people/loopback-token.auth.mjs +115 -0
  61. package/browser/people/people-auth.options.mjs +37 -0
  62. package/browser/session/authorization-vault.mjs +279 -0
  63. package/browser/session/authorization.store.mjs +336 -0
  64. package/browser/session/consent.store.mjs +34 -0
  65. package/browser/session/credential-resume-link.mjs +43 -0
  66. package/browser/session/credentials-accessor.impl.mjs +54 -0
  67. package/browser/session/credentials-accessor.mjs +5 -0
  68. package/browser/session/encrypted-authorization-vault.mjs +405 -0
  69. package/browser/session/federated-auth.session.mjs +176 -0
  70. package/browser/session/incremental-auth-ticket.mjs +42 -0
  71. package/browser/session/index.mjs +266 -0
  72. package/browser/session/orchestrated-token.crypto.mjs +47 -0
  73. package/browser/session/orchestrated-token.store.mjs +286 -0
  74. package/browser/session/pending-login.mjs +37 -0
  75. package/browser/session/redis-session.store.mjs +255 -0
  76. package/browser/session/secure-store-accessor.impl.mjs +78 -0
  77. package/browser/session/secure-store-accessor.mjs +5 -0
  78. package/browser/session/secure-store-backends.mjs +111 -0
  79. package/browser/session/secure-store.factory.mjs +77 -0
  80. package/browser/session/session-credential-vault.factory.mjs +18 -0
  81. package/browser/session/session-credential-vault.mjs +243 -0
  82. package/browser/session/session-crypto.mjs +39 -0
  83. package/browser/session/session-rate-limiter.mjs +126 -0
  84. package/browser/session/session.transport.mjs +16 -0
  85. package/browser/session/signin-binding.mjs +30 -0
  86. package/browser/session/storage/in-memory-authorization-vault.mjs +28 -0
  87. package/browser/session/storage/index.mjs +14 -0
  88. package/browser/session/storage/storage-authorization-vault.mjs +301 -0
  89. package/browser/session/storage/storage-token-store.mjs +83 -0
  90. package/browser/session/storage-authorization.store.mjs +134 -0
  91. package/browser/session/storage-consent.store.mjs +33 -0
  92. package/browser/session/storage-federated-auth.session.mjs +55 -0
  93. package/browser/session/storage-orchestrated-token.store.mjs +197 -0
  94. package/browser/session/token-storage.factory.mjs +58 -0
  95. package/browser/session/token.refresh.mjs +36 -0
  96. package/browser/session/token.vault.mjs +61 -0
  97. package/browser/session/transport-session.types.mjs +108 -0
  98. package/browser/session/utils/auth-token.utils.mjs +58 -0
  99. package/browser/session/utils/index.mjs +23 -0
  100. package/browser/session/utils/session-crypto.utils.mjs +49 -0
  101. package/browser/session/utils/tiny-ttl-cache.mjs +46 -0
  102. package/browser/session/vault-encryption.mjs +187 -0
  103. package/browser/session/vercel-kv-session.store.mjs +230 -0
  104. package/browser/shared-server/index.mjs +17 -0
  105. package/browser/shared-server/shared-server-identity.mjs +55 -0
  106. package/browser/ui/base-layout.mjs +184 -0
  107. package/browser/ui/index.mjs +51 -0
  108. package/browser/ui/local-login.helper.mjs +46 -0
  109. package/browser/ui/templates.mjs +482 -0
  110. package/browser/utils/audience.validator.mjs +110 -0
  111. package/browser/utils/authorization-id.utils.mjs +10 -0
  112. package/browser/utils/index.mjs +45 -0
  113. package/browser/utils/redirect-uri.utils.mjs +22 -0
  114. package/browser/utils/scope-grant.utils.mjs +36 -0
  115. package/browser/utils/token-scopes.utils.mjs +12 -0
  116. package/browser/utils/www-authenticate.utils.mjs +164 -0
  117. package/browser/vault/auth-providers.accessor.impl.mjs +236 -0
  118. package/browser/vault/auth-providers.accessor.mjs +5 -0
  119. package/browser/vault/auth-providers.registry.mjs +140 -0
  120. package/browser/vault/auth-providers.types.mjs +47 -0
  121. package/browser/vault/auth-providers.vault.mjs +206 -0
  122. package/browser/vault/credential-cache.mjs +187 -0
  123. package/browser/vault/credential-helpers.mjs +15 -0
  124. package/browser/vault/credential-loaders/eager-loader.mjs +91 -0
  125. package/browser/vault/credential-loaders/lazy-loader.mjs +120 -0
  126. package/browser/vault/index.mjs +35 -0
  127. package/cimd/cimd.types.d.ts +1 -1
  128. package/cimd/cimd.types.d.ts.map +1 -1
  129. package/common/jwt.types.d.ts +1 -1
  130. package/common/jwt.types.d.ts.map +1 -1
  131. package/common/session.types.d.ts +9 -1
  132. package/common/session.types.d.ts.map +1 -1
  133. package/consent/consent.types.d.ts +1 -1
  134. package/consent/consent.types.d.ts.map +1 -1
  135. package/detection/auth-provider-detection.d.ts +1 -1
  136. package/detection/auth-provider-detection.d.ts.map +1 -1
  137. package/errors/auth-internal.errors.d.ts +6 -0
  138. package/errors/auth-internal.errors.d.ts.map +1 -1
  139. package/errors/index.d.ts +1 -1
  140. package/errors/index.d.ts.map +1 -1
  141. package/esm/index.mjs +2 -2
  142. package/esm/package.json +21 -5
  143. package/index.d.ts +5 -1
  144. package/index.d.ts.map +1 -1
  145. package/index.js +2 -2
  146. package/options/app-auth.schema.d.ts +19 -1
  147. package/options/app-auth.schema.d.ts.map +1 -1
  148. package/options/orchestrated.schema.d.ts +37 -1
  149. package/options/orchestrated.schema.d.ts.map +1 -1
  150. package/options/public.schema.d.ts +1 -1
  151. package/options/public.schema.d.ts.map +1 -1
  152. package/options/schema.d.ts +19 -1
  153. package/options/schema.d.ts.map +1 -1
  154. package/options/shared.schemas.d.ts +10 -14
  155. package/options/shared.schemas.d.ts.map +1 -1
  156. package/options/static.schema.d.ts +1 -1
  157. package/options/static.schema.d.ts.map +1 -1
  158. package/options/transparent.schema.d.ts +1 -1
  159. package/options/transparent.schema.d.ts.map +1 -1
  160. package/package.json +21 -5
  161. package/people/index.d.ts +3 -0
  162. package/people/index.d.ts.map +1 -0
  163. package/people/loopback-token.auth.d.ts +75 -0
  164. package/people/loopback-token.auth.d.ts.map +1 -0
  165. package/people/people-auth.options.d.ts +36 -0
  166. package/people/people-auth.options.d.ts.map +1 -0
  167. package/session/authorization-vault.d.ts +1 -1
  168. package/session/authorization-vault.d.ts.map +1 -1
  169. package/session/encrypted-authorization-vault.d.ts +1 -1
  170. package/session/encrypted-authorization-vault.d.ts.map +1 -1
  171. package/session/secure-store.factory.d.ts.map +1 -1
  172. package/shared-server/index.d.ts +3 -0
  173. package/shared-server/index.d.ts.map +1 -0
  174. package/shared-server/shared-server-identity.d.ts +26 -0
  175. package/shared-server/shared-server-identity.d.ts.map +1 -0
@@ -0,0 +1,289 @@
1
+ // libs/auth/src/authorization/orchestrated.authorization.ts
2
+ import { NoProviderIdError, TokenNotAvailableError, TokenStoreRequiredError } from "../errors/auth-internal.errors.mjs";
3
+ import { deriveAuthorizationId } from "../utils/authorization-id.utils.mjs";
4
+ import { AuthorizationBase } from "./authorization.class.mjs";
5
+ var OrchestratedAuthorization = class _OrchestratedAuthorization extends AuthorizationBase {
6
+ mode = "orchestrated";
7
+ /**
8
+ * Primary provider ID (default for getToken)
9
+ */
10
+ primaryProviderId;
11
+ /**
12
+ * Token store for secure token retrieval
13
+ */
14
+ #tokenStore;
15
+ /**
16
+ * Token refresh callback
17
+ */
18
+ #onTokenRefresh;
19
+ /**
20
+ * Provider states (encrypted tokens)
21
+ */
22
+ #providerStates;
23
+ constructor(ctx) {
24
+ super(ctx);
25
+ this.primaryProviderId = ctx.primaryProviderId;
26
+ this.#tokenStore = ctx.tokenStore;
27
+ this.#onTokenRefresh = ctx.onTokenRefresh;
28
+ this.#providerStates = ctx.providerStates ?? /* @__PURE__ */ new Map();
29
+ }
30
+ /**
31
+ * Create an OrchestratedAuthorization
32
+ *
33
+ * @param ctx - Creation context
34
+ * @returns A new OrchestratedAuthorization instance
35
+ *
36
+ * @example
37
+ * ```typescript
38
+ * const auth = OrchestratedAuthorization.create({
39
+ * token: localJwt,
40
+ * user: { sub: 'user123', name: 'John' },
41
+ * primaryProviderId: 'github',
42
+ * tokenStore: redisTokenStore,
43
+ * providers: {
44
+ * github: { id: 'github', secretRefId: 'vault:github:user123' },
45
+ * },
46
+ * });
47
+ *
48
+ * // Retrieve token securely (never exposed to LLM)
49
+ * const githubToken = await auth.getToken('github');
50
+ * ```
51
+ */
52
+ static create(ctx) {
53
+ const {
54
+ token,
55
+ user,
56
+ scopes = [],
57
+ claims,
58
+ expiresAt,
59
+ primaryProviderId,
60
+ tokenStore,
61
+ onTokenRefresh,
62
+ providers = {},
63
+ authorizedProviderIds,
64
+ ...projections
65
+ } = ctx;
66
+ const id = deriveAuthorizationId(token);
67
+ const providerStates = /* @__PURE__ */ new Map();
68
+ const authorizedProviders = {};
69
+ const providerIdsFromState = [];
70
+ for (const [providerId, state] of Object.entries(providers)) {
71
+ providerStates.set(providerId, state);
72
+ providerIdsFromState.push(providerId);
73
+ authorizedProviders[providerId] = {
74
+ id: providerId,
75
+ exp: state.expiresAt,
76
+ embedMode: state.secretRefId ? "ref" : "store-only",
77
+ secretRefId: state.secretRefId,
78
+ refreshRefId: state.refreshRefId
79
+ };
80
+ }
81
+ const finalAuthorizedProviderIds = authorizedProviderIds ?? (providerIdsFromState.length > 0 ? providerIdsFromState : void 0);
82
+ return new _OrchestratedAuthorization({
83
+ id,
84
+ isAnonymous: false,
85
+ user,
86
+ claims,
87
+ expiresAt,
88
+ scopes,
89
+ token,
90
+ primaryProviderId,
91
+ tokenStore,
92
+ onTokenRefresh,
93
+ providerStates,
94
+ authorizedProviders,
95
+ ...projections,
96
+ authorizedProviderIds: finalAuthorizedProviderIds
97
+ });
98
+ }
99
+ /**
100
+ * Get access token for a provider
101
+ *
102
+ * Retrieves the decrypted token from the secure store.
103
+ * If the token is expired and refresh is available, attempts refresh.
104
+ *
105
+ * @param providerId - Provider ID (defaults to primaryProviderId)
106
+ * @returns The decrypted access token
107
+ * @throws If no token store or no token available
108
+ */
109
+ async getToken(providerId) {
110
+ const targetProviderId = providerId ?? this.primaryProviderId;
111
+ if (!targetProviderId) {
112
+ throw new NoProviderIdError("OrchestratedAuthorization: No provider ID specified and no primary provider set");
113
+ }
114
+ if (!this.#tokenStore) {
115
+ throw new TokenStoreRequiredError("orchestrated token retrieval");
116
+ }
117
+ const hasToken = await this.#tokenStore.hasTokens(this.id, targetProviderId);
118
+ if (!hasToken) {
119
+ throw new TokenNotAvailableError(
120
+ `OrchestratedAuthorization: No tokens available for provider "${targetProviderId}"`
121
+ );
122
+ }
123
+ const accessToken = await this.#tokenStore.getAccessToken(this.id, targetProviderId);
124
+ if (accessToken) {
125
+ const providerState = this.#providerStates.get(targetProviderId);
126
+ if (providerState?.expiresAt && providerState.expiresAt < Date.now()) {
127
+ return this.refreshAndGetToken(targetProviderId);
128
+ }
129
+ return accessToken;
130
+ }
131
+ return this.refreshAndGetToken(targetProviderId);
132
+ }
133
+ /**
134
+ * Refresh token and return new access token
135
+ */
136
+ async refreshAndGetToken(providerId) {
137
+ if (!this.#tokenStore || !this.#onTokenRefresh) {
138
+ throw new TokenNotAvailableError(
139
+ `OrchestratedAuthorization: Token expired for provider "${providerId}" and refresh not available`
140
+ );
141
+ }
142
+ const refreshToken = await this.#tokenStore.getRefreshToken(this.id, providerId);
143
+ if (!refreshToken) {
144
+ throw new TokenNotAvailableError(
145
+ `OrchestratedAuthorization: No refresh token available for provider "${providerId}"`
146
+ );
147
+ }
148
+ const result = await this.#onTokenRefresh(providerId, refreshToken);
149
+ await this.#tokenStore.storeTokens(this.id, providerId, {
150
+ accessToken: result.accessToken,
151
+ refreshToken: result.refreshToken ?? refreshToken,
152
+ expiresAt: result.expiresIn ? Date.now() + result.expiresIn * 1e3 : void 0
153
+ });
154
+ const currentState = this.#providerStates.get(providerId);
155
+ if (currentState) {
156
+ currentState.expiresAt = result.expiresIn ? Date.now() + result.expiresIn * 1e3 : void 0;
157
+ }
158
+ return result.accessToken;
159
+ }
160
+ /**
161
+ * Check if a provider has tokens stored
162
+ */
163
+ hasProvider(providerId) {
164
+ return this.#providerStates.has(providerId);
165
+ }
166
+ /**
167
+ * Get all provider IDs with tokens
168
+ */
169
+ getProviderIds() {
170
+ return Array.from(this.#providerStates.keys());
171
+ }
172
+ /**
173
+ * Add a new provider to this authorization
174
+ * Used when user authorizes additional providers after initial auth
175
+ */
176
+ async addProvider(providerId, tokens) {
177
+ if (!this.#tokenStore) {
178
+ throw new TokenStoreRequiredError("adding providers");
179
+ }
180
+ const expiresAt = tokens.expiresIn ? Date.now() + tokens.expiresIn * 1e3 : void 0;
181
+ await this.#tokenStore.storeTokens(this.id, providerId, {
182
+ accessToken: tokens.accessToken,
183
+ refreshToken: tokens.refreshToken,
184
+ expiresAt
185
+ });
186
+ this.#providerStates.set(providerId, {
187
+ id: providerId,
188
+ expiresAt,
189
+ secretRefId: `${this.id}:${providerId}`
190
+ });
191
+ }
192
+ // ============================================
193
+ // Progressive/Incremental Authorization
194
+ // ============================================
195
+ /**
196
+ * Mutable app authorization state for progressive auth.
197
+ * This allows expanding authorization without reissuing the session token.
198
+ */
199
+ #mutableAuthorizedApps = new Map(
200
+ Object.entries(this.authorizedApps ?? {})
201
+ );
202
+ /**
203
+ * Add app authorization after initial auth (progressive authorization).
204
+ * Stores app tokens server-side and updates authorized apps without JWT reissue.
205
+ *
206
+ * @param appId - App ID to authorize
207
+ * @param toolIds - Tool IDs accessible through this app authorization
208
+ * @param tokens - OAuth tokens from the app's auth provider
209
+ *
210
+ * @example
211
+ * ```typescript
212
+ * // User clicks auth link for Slack app
213
+ * await auth.addAppAuthorization('slack', ['slack:send_message', 'slack:list_channels'], {
214
+ * accessToken: slackAccessToken,
215
+ * refreshToken: slackRefreshToken,
216
+ * expiresIn: 3600,
217
+ * });
218
+ *
219
+ * // Now slack tools will work without re-auth
220
+ * ```
221
+ */
222
+ async addAppAuthorization(appId, toolIds, tokens) {
223
+ if (!this.#tokenStore) {
224
+ throw new TokenStoreRequiredError("progressive authorization");
225
+ }
226
+ const providerId = `app:${appId}`;
227
+ await this.addProvider(providerId, tokens);
228
+ this.#mutableAuthorizedApps.set(appId, { id: appId, toolIds });
229
+ }
230
+ /**
231
+ * Get access token for a specific app (for tool execution).
232
+ * Retrieves the app's OAuth token from server-side storage.
233
+ *
234
+ * @param appId - App ID to get token for
235
+ * @returns The decrypted access token, or null if not authorized
236
+ */
237
+ async getAppToken(appId) {
238
+ if (!this.#mutableAuthorizedApps.has(appId)) {
239
+ return null;
240
+ }
241
+ const providerId = `app:${appId}`;
242
+ try {
243
+ return await this.getToken(providerId);
244
+ } catch {
245
+ return null;
246
+ }
247
+ }
248
+ /**
249
+ * Check if an app is authorized (includes progressively authorized apps).
250
+ * Overrides base class to include mutable app authorization state.
251
+ */
252
+ isAppAuthorized(appId) {
253
+ return this.#mutableAuthorizedApps.has(appId) || super.isAppAuthorized(appId);
254
+ }
255
+ /**
256
+ * Get all authorized app IDs (includes progressively authorized apps).
257
+ */
258
+ getAllAuthorizedAppIds() {
259
+ const baseIds = new Set(this.authorizedAppIds ?? []);
260
+ for (const appId of this.#mutableAuthorizedApps.keys()) {
261
+ baseIds.add(appId);
262
+ }
263
+ return Array.from(baseIds);
264
+ }
265
+ /**
266
+ * Get tool IDs authorized through an app.
267
+ */
268
+ getAppToolIds(appId) {
269
+ return this.#mutableAuthorizedApps.get(appId)?.toolIds ?? this.authorizedApps?.[appId]?.toolIds;
270
+ }
271
+ /**
272
+ * Remove a provider from this authorization
273
+ */
274
+ async removeProvider(providerId) {
275
+ if (this.#tokenStore) {
276
+ await this.#tokenStore.deleteTokens(this.id, providerId);
277
+ }
278
+ this.#providerStates.delete(providerId);
279
+ }
280
+ /**
281
+ * Get the issuer (local orchestrator)
282
+ */
283
+ get issuer() {
284
+ return this.claims?.["iss"];
285
+ }
286
+ };
287
+ export {
288
+ OrchestratedAuthorization
289
+ };
@@ -0,0 +1,124 @@
1
+ // libs/auth/src/authorization/public.authorization.ts
2
+ import { randomUUID } from "@frontmcp/utils";
3
+ import { AuthorizationBase } from "./authorization.class.mjs";
4
+ import { TokenNotAvailableError } from "../errors/auth-internal.errors.mjs";
5
+ var PublicAuthorization = class _PublicAuthorization extends AuthorizationBase {
6
+ mode = "public";
7
+ /**
8
+ * Issuer identifier for the anonymous authorization
9
+ */
10
+ issuer;
11
+ constructor(ctx) {
12
+ super(ctx);
13
+ this.issuer = ctx.issuer;
14
+ }
15
+ /**
16
+ * Create a new PublicAuthorization for anonymous access
17
+ *
18
+ * @param ctx - Creation context with optional configuration
19
+ * @returns A new PublicAuthorization instance
20
+ *
21
+ * @example
22
+ * ```typescript
23
+ * const auth = PublicAuthorization.create({
24
+ * scopes: ['read', 'anonymous'],
25
+ * ttlMs: 3600000,
26
+ * allowedTools: ['search', 'get-docs'],
27
+ * });
28
+ * ```
29
+ */
30
+ static create(ctx = {}) {
31
+ const {
32
+ prefix = "anon",
33
+ scopes = ["anonymous"],
34
+ ttlMs = 36e5,
35
+ // 1 hour default
36
+ issuer,
37
+ allowedTools = "all",
38
+ allowedPrompts = "all"
39
+ } = ctx;
40
+ const uuid = randomUUID();
41
+ const sub = `${prefix}:${uuid}`;
42
+ const user = {
43
+ sub,
44
+ name: "Anonymous",
45
+ anonymous: true
46
+ };
47
+ const expiresAt = ttlMs ? Date.now() + ttlMs : void 0;
48
+ const authorizedTools = {};
49
+ const authorizedToolIds = [];
50
+ if (allowedTools !== "all" && Array.isArray(allowedTools)) {
51
+ for (const toolId of allowedTools) {
52
+ authorizedTools[toolId] = {
53
+ executionPath: ["public", toolId]
54
+ };
55
+ authorizedToolIds.push(toolId);
56
+ }
57
+ }
58
+ const authorizedPrompts = {};
59
+ const authorizedPromptIds = [];
60
+ if (allowedPrompts !== "all" && Array.isArray(allowedPrompts)) {
61
+ for (const promptId of allowedPrompts) {
62
+ authorizedPrompts[promptId] = {
63
+ executionPath: ["public", promptId]
64
+ };
65
+ authorizedPromptIds.push(promptId);
66
+ }
67
+ }
68
+ return new _PublicAuthorization({
69
+ id: sub,
70
+ isAnonymous: true,
71
+ user,
72
+ scopes,
73
+ expiresAt,
74
+ issuer,
75
+ authorizedTools: allowedTools === "all" ? void 0 : authorizedTools,
76
+ authorizedToolIds: allowedTools === "all" ? void 0 : authorizedToolIds,
77
+ authorizedPrompts: allowedPrompts === "all" ? void 0 : authorizedPrompts,
78
+ authorizedPromptIds: allowedPrompts === "all" ? void 0 : authorizedPromptIds
79
+ });
80
+ }
81
+ /**
82
+ * Anonymous users cannot access provider tokens
83
+ *
84
+ * @throws TokenNotAvailableError always - anonymous users do not have provider tokens
85
+ */
86
+ async getToken(_providerId) {
87
+ throw new TokenNotAvailableError(
88
+ "PublicAuthorization: Anonymous users cannot access provider tokens. Use transparent or orchestrated mode for token access."
89
+ );
90
+ }
91
+ /**
92
+ * Check if all tools are allowed (public access)
93
+ */
94
+ get allowsAllTools() {
95
+ return this.authorizedToolIds.length === 0 && Object.keys(this.authorizedTools).length === 0;
96
+ }
97
+ /**
98
+ * Check if all prompts are allowed (public access)
99
+ */
100
+ get allowsAllPrompts() {
101
+ return this.authorizedPromptIds.length === 0 && Object.keys(this.authorizedPrompts).length === 0;
102
+ }
103
+ /**
104
+ * Override canAccessTool to support 'all' mode
105
+ */
106
+ canAccessTool(toolId) {
107
+ if (this.allowsAllTools) {
108
+ return true;
109
+ }
110
+ return super.canAccessTool(toolId);
111
+ }
112
+ /**
113
+ * Override canAccessPrompt to support 'all' mode
114
+ */
115
+ canAccessPrompt(promptId) {
116
+ if (this.allowsAllPrompts) {
117
+ return true;
118
+ }
119
+ return super.canAccessPrompt(promptId);
120
+ }
121
+ };
122
+ export {
123
+ PublicAuthorization
124
+ };
@@ -0,0 +1,130 @@
1
+ // libs/auth/src/authorization/transparent.authorization.ts
2
+ import { sha256Hex } from "@frontmcp/utils";
3
+ import { AuthorizationBase } from "./authorization.class.mjs";
4
+ import { TokenNotAvailableError } from "../errors/auth-internal.errors.mjs";
5
+ var TransparentAuthorization = class _TransparentAuthorization extends AuthorizationBase {
6
+ mode = "transparent";
7
+ /**
8
+ * Provider ID that issued the token
9
+ */
10
+ providerId;
11
+ /**
12
+ * Provider display name
13
+ */
14
+ providerName;
15
+ constructor(ctx) {
16
+ super(ctx);
17
+ this.providerId = ctx.providerId;
18
+ this.providerName = ctx.providerName;
19
+ }
20
+ /**
21
+ * Create a TransparentAuthorization from a verified JWT
22
+ *
23
+ * @param ctx - Creation context with token and verified payload
24
+ * @returns A new TransparentAuthorization instance
25
+ *
26
+ * @example
27
+ * ```typescript
28
+ * const auth = TransparentAuthorization.fromVerifiedToken({
29
+ * token: bearerToken,
30
+ * payload: verifiedClaims,
31
+ * providerId: 'auth0',
32
+ * });
33
+ *
34
+ * // Pass token through to downstream
35
+ * const token = await auth.getToken();
36
+ * ```
37
+ */
38
+ static fromVerifiedToken(ctx) {
39
+ const { token, payload, providerId, providerName, ...projections } = ctx;
40
+ const user = {
41
+ sub: payload.sub,
42
+ name: payload.name,
43
+ email: payload.email,
44
+ picture: payload.picture,
45
+ anonymous: false
46
+ };
47
+ const scopes = _TransparentAuthorization.parseScopes(payload.scope);
48
+ const expiresAt = payload.exp ? payload.exp * 1e3 : void 0;
49
+ const id = _TransparentAuthorization.generateAuthorizationId(token);
50
+ const providerSnapshot = {
51
+ id: providerId,
52
+ exp: expiresAt,
53
+ payload,
54
+ embedMode: "plain",
55
+ // transparent mode keeps token in memory
56
+ token
57
+ // the original token
58
+ };
59
+ return new _TransparentAuthorization({
60
+ id,
61
+ isAnonymous: false,
62
+ user,
63
+ claims: payload,
64
+ expiresAt,
65
+ scopes,
66
+ token,
67
+ providerId,
68
+ providerName,
69
+ authorizedProviders: { [providerId]: providerSnapshot },
70
+ authorizedProviderIds: [providerId],
71
+ ...projections
72
+ });
73
+ }
74
+ /**
75
+ * Get the original bearer token for pass-through
76
+ *
77
+ * In transparent mode, the same token is returned regardless of providerId
78
+ * since only one provider (the upstream) issued the token.
79
+ *
80
+ * @param _providerId - Ignored in transparent mode
81
+ * @returns The original bearer token
82
+ */
83
+ async getToken(_providerId) {
84
+ if (!this.token) {
85
+ throw new TokenNotAvailableError("TransparentAuthorization: Token not available");
86
+ }
87
+ return this.token;
88
+ }
89
+ /**
90
+ * Parse scope claim from JWT payload
91
+ */
92
+ static parseScopes(scope) {
93
+ if (!scope) return [];
94
+ if (Array.isArray(scope)) return scope;
95
+ return scope.split(/\s+/).filter(Boolean);
96
+ }
97
+ /**
98
+ * Generate authorization ID from token signature
99
+ * Uses SHA-256 fingerprint of the token signature for uniqueness
100
+ */
101
+ static generateAuthorizationId(token) {
102
+ const parts = token.split(".");
103
+ const signature = parts[2] || token;
104
+ return sha256Hex(signature).substring(0, 16);
105
+ }
106
+ /**
107
+ * Get the issuer from the token claims
108
+ */
109
+ get issuer() {
110
+ return this.claims?.["iss"];
111
+ }
112
+ /**
113
+ * Get the audience from the token claims
114
+ */
115
+ get audience() {
116
+ return this.claims?.["aud"];
117
+ }
118
+ /**
119
+ * Check if the token was issued for a specific audience
120
+ */
121
+ hasAudience(aud) {
122
+ const tokenAud = this.audience;
123
+ if (!tokenAud) return false;
124
+ if (Array.isArray(tokenAud)) return tokenAud.includes(aud);
125
+ return tokenAud === aud;
126
+ }
127
+ };
128
+ export {
129
+ TransparentAuthorization
130
+ };