@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,336 @@
1
+ // libs/auth/src/session/authorization.store.ts
2
+ import { internalZ as z } from "@frontmcp/lazy-zod";
3
+ import { randomUUID, sha256Base64url } from "@frontmcp/utils";
4
+ var pkceChallengeSchema = z.object({
5
+ challenge: z.string().min(43).max(128),
6
+ method: z.literal("S256")
7
+ });
8
+ var authorizationCodeRecordSchema = z.object({
9
+ code: z.string().min(1),
10
+ clientId: z.string().min(1),
11
+ redirectUri: z.string().url(),
12
+ scopes: z.array(z.string()),
13
+ pkce: pkceChallengeSchema,
14
+ userSub: z.string().min(1),
15
+ userEmail: z.string().email().optional(),
16
+ userName: z.string().optional(),
17
+ state: z.string().optional(),
18
+ createdAt: z.number(),
19
+ expiresAt: z.number(),
20
+ used: z.boolean(),
21
+ resource: z.string().url().optional(),
22
+ // Consent and federated login fields
23
+ selectedToolIds: z.array(z.string()).optional(),
24
+ selectedProviderIds: z.array(z.string()).optional(),
25
+ skippedProviderIds: z.array(z.string()).optional(),
26
+ consentEnabled: z.boolean().optional(),
27
+ federatedLoginUsed: z.boolean().optional(),
28
+ pendingAuthId: z.string().optional(),
29
+ // Progressive/Incremental authorization: granted app-id set.
30
+ authorizedAppIds: z.array(z.string()).optional(),
31
+ // Custom claims from a local authenticate() verifier (Checkpoint 3a).
32
+ customClaims: z.record(z.string(), z.unknown()).optional()
33
+ });
34
+ var AUTH_CODE_TTL_MS = 60 * 1e3;
35
+ var PENDING_AUTH_TTL_MS = 10 * 60 * 1e3;
36
+ var REFRESH_TOKEN_TTL_MS = 30 * 24 * 60 * 60 * 1e3;
37
+ function generateAuthorizationCode() {
38
+ return randomUUID().replace(/-/g, "") + randomUUID().replace(/-/g, "");
39
+ }
40
+ function generateRefreshTokenValue() {
41
+ return randomUUID() + "-" + randomUUID();
42
+ }
43
+ function buildCodeRecord(params) {
44
+ const now = Date.now();
45
+ return {
46
+ code: generateAuthorizationCode(),
47
+ clientId: params.clientId,
48
+ redirectUri: params.redirectUri,
49
+ scopes: params.scopes,
50
+ pkce: params.pkce,
51
+ userSub: params.userSub,
52
+ userEmail: params.userEmail,
53
+ userName: params.userName,
54
+ state: params.state,
55
+ resource: params.resource,
56
+ createdAt: now,
57
+ expiresAt: now + AUTH_CODE_TTL_MS,
58
+ used: false,
59
+ selectedToolIds: params.selectedToolIds,
60
+ selectedProviderIds: params.selectedProviderIds,
61
+ skippedProviderIds: params.skippedProviderIds,
62
+ consentEnabled: params.consentEnabled,
63
+ federatedLoginUsed: params.federatedLoginUsed,
64
+ pendingAuthId: params.pendingAuthId,
65
+ authorizedAppIds: params.authorizedAppIds,
66
+ customClaims: params.customClaims
67
+ };
68
+ }
69
+ function buildPendingRecord(params) {
70
+ const now = Date.now();
71
+ return {
72
+ id: randomUUID(),
73
+ clientId: params.clientId,
74
+ redirectUri: params.redirectUri,
75
+ scopes: params.scopes,
76
+ pkce: params.pkce,
77
+ state: params.state,
78
+ resource: params.resource,
79
+ createdAt: now,
80
+ expiresAt: now + PENDING_AUTH_TTL_MS,
81
+ isIncremental: params.isIncremental,
82
+ incrementalSub: params.incrementalSub,
83
+ targetAppId: params.targetAppId,
84
+ targetToolId: params.targetToolId,
85
+ existingSessionId: params.existingSessionId,
86
+ existingAuthorizationId: params.existingAuthorizationId,
87
+ priorAuthorizedAppIds: params.priorAuthorizedAppIds,
88
+ federatedLogin: params.federatedLogin,
89
+ consent: params.consent,
90
+ authUiCsrf: params.authUiCsrf,
91
+ signinBinding: params.signinBinding
92
+ };
93
+ }
94
+ function buildRefreshTokenRecord(params) {
95
+ const now = Date.now();
96
+ return {
97
+ token: generateRefreshTokenValue(),
98
+ clientId: params.clientId,
99
+ userSub: params.userSub,
100
+ scopes: params.scopes,
101
+ resource: params.resource,
102
+ createdAt: now,
103
+ expiresAt: now + REFRESH_TOKEN_TTL_MS,
104
+ revoked: false,
105
+ // Preserve grant metadata so a refreshed access token keeps its
106
+ // consent/authorized_apps/custom claims.
107
+ userEmail: params.userEmail,
108
+ userName: params.userName,
109
+ consentEnabled: params.consentEnabled,
110
+ selectedToolIds: params.selectedToolIds,
111
+ authorizedAppIds: params.authorizedAppIds,
112
+ customClaims: params.customClaims,
113
+ federatedLoginUsed: params.federatedLoginUsed,
114
+ selectedProviderIds: params.selectedProviderIds,
115
+ skippedProviderIds: params.skippedProviderIds,
116
+ providerTokensId: params.providerTokensId
117
+ };
118
+ }
119
+ function verifyPkce(codeVerifier, challenge) {
120
+ if (challenge.method !== "S256") {
121
+ return false;
122
+ }
123
+ const hash = sha256Base64url(codeVerifier);
124
+ return hash === challenge.challenge;
125
+ }
126
+ function generatePkceChallenge(codeVerifier) {
127
+ const challenge = sha256Base64url(codeVerifier);
128
+ return { challenge, method: "S256" };
129
+ }
130
+ var InMemoryAuthorizationStore = class {
131
+ codes = /* @__PURE__ */ new Map();
132
+ pending = /* @__PURE__ */ new Map();
133
+ refreshTokens = /* @__PURE__ */ new Map();
134
+ generateCode() {
135
+ return generateAuthorizationCode();
136
+ }
137
+ generateRefreshToken() {
138
+ return generateRefreshTokenValue();
139
+ }
140
+ async storeAuthorizationCode(record) {
141
+ this.codes.set(record.code, record);
142
+ }
143
+ async getAuthorizationCode(code) {
144
+ const record = this.codes.get(code);
145
+ if (!record) return null;
146
+ if (Date.now() > record.expiresAt) {
147
+ this.codes.delete(code);
148
+ return null;
149
+ }
150
+ return record;
151
+ }
152
+ async markCodeUsed(code, issuedRefreshToken) {
153
+ const record = this.codes.get(code);
154
+ if (record) {
155
+ record.used = true;
156
+ if (issuedRefreshToken) record.issuedRefreshToken = issuedRefreshToken;
157
+ }
158
+ }
159
+ async deleteAuthorizationCode(code) {
160
+ this.codes.delete(code);
161
+ }
162
+ async storePendingAuthorization(record) {
163
+ this.pending.set(record.id, record);
164
+ }
165
+ async getPendingAuthorization(id) {
166
+ const record = this.pending.get(id);
167
+ if (!record) return null;
168
+ if (Date.now() > record.expiresAt) {
169
+ this.pending.delete(id);
170
+ return null;
171
+ }
172
+ return record;
173
+ }
174
+ async deletePendingAuthorization(id) {
175
+ this.pending.delete(id);
176
+ }
177
+ async storeRefreshToken(record) {
178
+ this.refreshTokens.set(record.token, record);
179
+ }
180
+ async getRefreshToken(token) {
181
+ const record = this.refreshTokens.get(token);
182
+ if (!record) return null;
183
+ if (Date.now() > record.expiresAt || record.revoked) {
184
+ return null;
185
+ }
186
+ return record;
187
+ }
188
+ async revokeRefreshToken(token) {
189
+ const record = this.refreshTokens.get(token);
190
+ if (record) {
191
+ record.revoked = true;
192
+ }
193
+ }
194
+ async rotateRefreshToken(oldToken, newRecord) {
195
+ await this.revokeRefreshToken(oldToken);
196
+ newRecord.previousToken = oldToken;
197
+ await this.storeRefreshToken(newRecord);
198
+ }
199
+ async cleanup() {
200
+ const now = Date.now();
201
+ for (const [code, record] of this.codes) {
202
+ if (now > record.expiresAt) {
203
+ this.codes.delete(code);
204
+ }
205
+ }
206
+ for (const [id, record] of this.pending) {
207
+ if (now > record.expiresAt) {
208
+ this.pending.delete(id);
209
+ }
210
+ }
211
+ for (const [token, record] of this.refreshTokens) {
212
+ if (now > record.expiresAt || record.revoked) {
213
+ this.refreshTokens.delete(token);
214
+ }
215
+ }
216
+ }
217
+ /**
218
+ * Create an authorization code record with defaults.
219
+ */
220
+ createCodeRecord(params) {
221
+ return buildCodeRecord(params);
222
+ }
223
+ /**
224
+ * Create a pending authorization record with defaults.
225
+ */
226
+ createPendingRecord(params) {
227
+ return buildPendingRecord(params);
228
+ }
229
+ /**
230
+ * Create a refresh token record with defaults.
231
+ */
232
+ createRefreshTokenRecord(params) {
233
+ return buildRefreshTokenRecord(params);
234
+ }
235
+ };
236
+ var RedisAuthorizationStore = class {
237
+ constructor(redis, namespace = "oauth:") {
238
+ this.redis = redis;
239
+ this.namespace = namespace;
240
+ }
241
+ redis;
242
+ namespace;
243
+ key(type, id) {
244
+ return `${this.namespace}${type}:${id}`;
245
+ }
246
+ generateCode() {
247
+ return generateAuthorizationCode();
248
+ }
249
+ generateRefreshToken() {
250
+ return generateRefreshTokenValue();
251
+ }
252
+ createCodeRecord(params) {
253
+ return buildCodeRecord(params);
254
+ }
255
+ createPendingRecord(params) {
256
+ return buildPendingRecord(params);
257
+ }
258
+ createRefreshTokenRecord(params) {
259
+ return buildRefreshTokenRecord(params);
260
+ }
261
+ async storeAuthorizationCode(record) {
262
+ const ttl = Math.max(Math.ceil((record.expiresAt - Date.now()) / 1e3), 1);
263
+ await this.redis.set(this.key("code", record.code), JSON.stringify(record), "EX", Math.max(ttl, 1));
264
+ }
265
+ async getAuthorizationCode(code) {
266
+ const data = await this.redis.get(this.key("code", code));
267
+ if (!data) return null;
268
+ return JSON.parse(data);
269
+ }
270
+ async markCodeUsed(code, issuedRefreshToken) {
271
+ const record = await this.getAuthorizationCode(code);
272
+ if (record) {
273
+ record.used = true;
274
+ if (issuedRefreshToken) record.issuedRefreshToken = issuedRefreshToken;
275
+ const ttl = Math.ceil((record.expiresAt - Date.now()) / 1e3);
276
+ await this.redis.set(this.key("code", code), JSON.stringify(record), "EX", Math.max(ttl, 1));
277
+ }
278
+ }
279
+ async deleteAuthorizationCode(code) {
280
+ await this.redis.del(this.key("code", code));
281
+ }
282
+ async storePendingAuthorization(record) {
283
+ const ttl = Math.max(Math.ceil((record.expiresAt - Date.now()) / 1e3), 1);
284
+ await this.redis.set(this.key("pending", record.id), JSON.stringify(record), "EX", ttl);
285
+ }
286
+ async getPendingAuthorization(id) {
287
+ const data = await this.redis.get(this.key("pending", id));
288
+ if (!data) return null;
289
+ return JSON.parse(data);
290
+ }
291
+ async deletePendingAuthorization(id) {
292
+ await this.redis.del(this.key("pending", id));
293
+ }
294
+ async storeRefreshToken(record) {
295
+ const ttl = Math.ceil((record.expiresAt - Date.now()) / 1e3);
296
+ await this.redis.set(this.key("refresh", record.token), JSON.stringify(record), "EX", ttl);
297
+ }
298
+ async getRefreshToken(token) {
299
+ const data = await this.redis.get(this.key("refresh", token));
300
+ if (!data) return null;
301
+ const record = JSON.parse(data);
302
+ if (record.revoked) return null;
303
+ return record;
304
+ }
305
+ async revokeRefreshToken(token) {
306
+ const record = await this.getRefreshToken(token);
307
+ if (record) {
308
+ record.revoked = true;
309
+ const ttl = Math.ceil((record.expiresAt - Date.now()) / 1e3);
310
+ await this.redis.set(this.key("refresh", token), JSON.stringify(record), "EX", Math.max(ttl, 1));
311
+ }
312
+ }
313
+ async rotateRefreshToken(oldToken, newRecord) {
314
+ await this.revokeRefreshToken(oldToken);
315
+ newRecord.previousToken = oldToken;
316
+ await this.storeRefreshToken(newRecord);
317
+ }
318
+ async cleanup() {
319
+ }
320
+ };
321
+ export {
322
+ AUTH_CODE_TTL_MS,
323
+ InMemoryAuthorizationStore,
324
+ PENDING_AUTH_TTL_MS,
325
+ REFRESH_TOKEN_TTL_MS,
326
+ RedisAuthorizationStore,
327
+ authorizationCodeRecordSchema,
328
+ buildCodeRecord,
329
+ buildPendingRecord,
330
+ buildRefreshTokenRecord,
331
+ generateAuthorizationCode,
332
+ generatePkceChallenge,
333
+ generateRefreshTokenValue,
334
+ pkceChallengeSchema,
335
+ verifyPkce
336
+ };
@@ -0,0 +1,34 @@
1
+ // libs/auth/src/session/consent.store.ts
2
+ function consentRecordKey(userSub, clientId) {
3
+ return `consent:${userSub}:${clientId}`;
4
+ }
5
+ var InMemoryConsentStore = class {
6
+ records = /* @__PURE__ */ new Map();
7
+ async get(userSub, clientId) {
8
+ const record = this.records.get(consentRecordKey(userSub, clientId));
9
+ if (!record) return null;
10
+ return { ...record, selectedToolIds: [...record.selectedToolIds], seenToolIds: [...record.seenToolIds] };
11
+ }
12
+ async set(record) {
13
+ this.records.set(consentRecordKey(record.userSub, record.clientId), {
14
+ ...record,
15
+ selectedToolIds: [...record.selectedToolIds],
16
+ seenToolIds: [...record.seenToolIds]
17
+ });
18
+ }
19
+ async delete(userSub, clientId) {
20
+ this.records.delete(consentRecordKey(userSub, clientId));
21
+ }
22
+ /** Number of remembered records (for testing/monitoring). */
23
+ get size() {
24
+ return this.records.size;
25
+ }
26
+ /** Clear all remembered records (for testing). */
27
+ clear() {
28
+ this.records.clear();
29
+ }
30
+ };
31
+ export {
32
+ InMemoryConsentStore,
33
+ consentRecordKey
34
+ };
@@ -0,0 +1,43 @@
1
+ // libs/auth/src/session/credential-resume-link.ts
2
+ import { signData, verifyData } from "@frontmcp/utils";
3
+ var DEFAULT_RESUME_TTL_MS = 6e5;
4
+ function signCredentialResumeToken(input, secret) {
5
+ const payload = {
6
+ sub: input.sub,
7
+ key: input.key,
8
+ ...input.context !== void 0 ? { context: input.context } : {},
9
+ exp: Date.now() + (input.ttlMs ?? DEFAULT_RESUME_TTL_MS)
10
+ };
11
+ const signedJson = signData(payload, { secret });
12
+ return Buffer.from(signedJson, "utf8").toString("base64url");
13
+ }
14
+ function verifyCredentialResumeToken(token, secret, now = Date.now()) {
15
+ let signedJson;
16
+ try {
17
+ signedJson = Buffer.from(token, "base64url").toString("utf8");
18
+ } catch {
19
+ return null;
20
+ }
21
+ const payload = verifyData(signedJson, { secret });
22
+ if (!payload) return null;
23
+ if (typeof payload.sub !== "string" || typeof payload.key !== "string" || !Number.isFinite(payload.exp)) {
24
+ return null;
25
+ }
26
+ if (payload.context !== void 0 && typeof payload.context !== "string") {
27
+ return null;
28
+ }
29
+ if (now >= payload.exp) {
30
+ return null;
31
+ }
32
+ return payload;
33
+ }
34
+ function buildCredentialResumeUrl(basePath, token) {
35
+ const trimmed = basePath.endsWith("/") ? basePath.slice(0, -1) : basePath;
36
+ return `${trimmed}/oauth/connect?token=${encodeURIComponent(token)}`;
37
+ }
38
+ export {
39
+ DEFAULT_RESUME_TTL_MS,
40
+ buildCredentialResumeUrl,
41
+ signCredentialResumeToken,
42
+ verifyCredentialResumeToken
43
+ };
@@ -0,0 +1,54 @@
1
+ // libs/auth/src/session/credentials-accessor.impl.ts
2
+ import { noopAuthLogger } from "../common/auth-logger.interface.mjs";
3
+ import { buildCredentialResumeUrl, signCredentialResumeToken } from "./credential-resume-link.mjs";
4
+ var CredentialsAccessorImpl = class {
5
+ vault;
6
+ resolveSub;
7
+ signingSecret;
8
+ basePath;
9
+ resumeTtlMs;
10
+ logger;
11
+ constructor(deps) {
12
+ this.vault = deps.vault;
13
+ this.resolveSub = deps.resolveSub;
14
+ this.signingSecret = deps.signingSecret;
15
+ this.basePath = deps.basePath;
16
+ this.resumeTtlMs = deps.resumeTtlMs;
17
+ this.logger = deps.logger ?? noopAuthLogger;
18
+ }
19
+ async get(key) {
20
+ const sub = this.resolveSub();
21
+ if (!sub) return void 0;
22
+ return this.vault.get(sub, key);
23
+ }
24
+ async list() {
25
+ const sub = this.resolveSub();
26
+ if (!sub) return [];
27
+ return this.vault.list(sub);
28
+ }
29
+ async requireConnect(options) {
30
+ const { key, context } = options;
31
+ const sub = this.resolveSub();
32
+ if (sub) {
33
+ const existing = await this.vault.get(sub, key);
34
+ if (existing) {
35
+ return { connected: true, key, credential: existing };
36
+ }
37
+ }
38
+ const token = signCredentialResumeToken(
39
+ { sub: sub ?? "", key, context, ttlMs: this.resumeTtlMs },
40
+ this.signingSecret
41
+ );
42
+ const resumeUrl = buildCredentialResumeUrl(this.basePath, token);
43
+ this.logger.debug(`CredentialsAccessor: credential "${key}" not connected; issued resume link`);
44
+ return {
45
+ connected: false,
46
+ key,
47
+ resumeUrl,
48
+ message: `Credential "${key}" is not connected. Open the resume URL to connect it.`
49
+ };
50
+ }
51
+ };
52
+ export {
53
+ CredentialsAccessorImpl
54
+ };
@@ -0,0 +1,5 @@
1
+ // libs/auth/src/session/credentials-accessor.ts
2
+ var CREDENTIALS_ACCESSOR = /* @__PURE__ */ Symbol.for("frontmcp:CREDENTIALS_ACCESSOR");
3
+ export {
4
+ CREDENTIALS_ACCESSOR
5
+ };