@parsrun/auth 0.1.0

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 (54) hide show
  1. package/README.md +133 -0
  2. package/dist/adapters/hono.d.ts +9 -0
  3. package/dist/adapters/hono.js +6 -0
  4. package/dist/adapters/hono.js.map +1 -0
  5. package/dist/adapters/index.d.ts +9 -0
  6. package/dist/adapters/index.js +7 -0
  7. package/dist/adapters/index.js.map +1 -0
  8. package/dist/authorization-By1Xp8Za.d.ts +213 -0
  9. package/dist/base-BKyR8rcE.d.ts +646 -0
  10. package/dist/chunk-42MGHABB.js +263 -0
  11. package/dist/chunk-42MGHABB.js.map +1 -0
  12. package/dist/chunk-7GOBAL4G.js +3 -0
  13. package/dist/chunk-7GOBAL4G.js.map +1 -0
  14. package/dist/chunk-G5I3T73A.js +152 -0
  15. package/dist/chunk-G5I3T73A.js.map +1 -0
  16. package/dist/chunk-IB4WUQDZ.js +410 -0
  17. package/dist/chunk-IB4WUQDZ.js.map +1 -0
  18. package/dist/chunk-MOG4Y6I7.js +415 -0
  19. package/dist/chunk-MOG4Y6I7.js.map +1 -0
  20. package/dist/chunk-NK4TJV2W.js +295 -0
  21. package/dist/chunk-NK4TJV2W.js.map +1 -0
  22. package/dist/chunk-RHNVRCF3.js +838 -0
  23. package/dist/chunk-RHNVRCF3.js.map +1 -0
  24. package/dist/chunk-YTCPXJR5.js +570 -0
  25. package/dist/chunk-YTCPXJR5.js.map +1 -0
  26. package/dist/cloudflare-kv-L64CZKDK.js +105 -0
  27. package/dist/cloudflare-kv-L64CZKDK.js.map +1 -0
  28. package/dist/deno-kv-F55HKKP6.js +111 -0
  29. package/dist/deno-kv-F55HKKP6.js.map +1 -0
  30. package/dist/index-C3kz9XqE.d.ts +226 -0
  31. package/dist/index-DOGcetyD.d.ts +1041 -0
  32. package/dist/index.d.ts +1579 -0
  33. package/dist/index.js +4294 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/jwt-manager-CH8H0kmm.d.ts +182 -0
  36. package/dist/providers/index.d.ts +90 -0
  37. package/dist/providers/index.js +3 -0
  38. package/dist/providers/index.js.map +1 -0
  39. package/dist/providers/otp/index.d.ts +3 -0
  40. package/dist/providers/otp/index.js +4 -0
  41. package/dist/providers/otp/index.js.map +1 -0
  42. package/dist/redis-5TIS6XCA.js +121 -0
  43. package/dist/redis-5TIS6XCA.js.map +1 -0
  44. package/dist/security/index.d.ts +301 -0
  45. package/dist/security/index.js +5 -0
  46. package/dist/security/index.js.map +1 -0
  47. package/dist/session/index.d.ts +117 -0
  48. package/dist/session/index.js +4 -0
  49. package/dist/session/index.js.map +1 -0
  50. package/dist/storage/index.d.ts +97 -0
  51. package/dist/storage/index.js +3 -0
  52. package/dist/storage/index.js.map +1 -0
  53. package/dist/types-DSjafxJ4.d.ts +193 -0
  54. package/package.json +102 -0
@@ -0,0 +1,838 @@
1
+ import { createAuthorizationGuard } from './chunk-NK4TJV2W.js';
2
+ import { extractBearerToken } from './chunk-MOG4Y6I7.js';
3
+
4
+ // src/adapters/types.ts
5
+ function createAuthCookies(tokens, config) {
6
+ const prefix = config.prefix ?? "pars";
7
+ return [
8
+ {
9
+ name: `${prefix}.access_token`,
10
+ value: tokens.accessToken,
11
+ expires: tokens.accessExpiresAt,
12
+ path: config.path ?? "/",
13
+ domain: config.domain,
14
+ secure: config.secure ?? true,
15
+ sameSite: config.sameSite ?? "lax",
16
+ httpOnly: false
17
+ // Access token may be needed by JS
18
+ },
19
+ {
20
+ name: `${prefix}.refresh_token`,
21
+ value: tokens.refreshToken,
22
+ expires: tokens.refreshExpiresAt,
23
+ path: config.path ?? "/",
24
+ domain: config.domain,
25
+ secure: config.secure ?? true,
26
+ sameSite: config.sameSite ?? "lax",
27
+ httpOnly: config.httpOnly ?? true
28
+ // Refresh token should be HttpOnly
29
+ }
30
+ ];
31
+ }
32
+ function createLogoutCookies(config) {
33
+ const prefix = config.prefix ?? "pars";
34
+ const past = /* @__PURE__ */ new Date(0);
35
+ return [
36
+ {
37
+ name: `${prefix}.access_token`,
38
+ value: "",
39
+ expires: past,
40
+ path: config.path ?? "/",
41
+ domain: config.domain
42
+ },
43
+ {
44
+ name: `${prefix}.refresh_token`,
45
+ value: "",
46
+ expires: past,
47
+ path: config.path ?? "/",
48
+ domain: config.domain
49
+ }
50
+ ];
51
+ }
52
+
53
+ // src/adapters/hono.ts
54
+ function setCookie(c, cookie) {
55
+ let cookieString = `${cookie.name}=${cookie.value}`;
56
+ if (cookie.expires) {
57
+ cookieString += `; Expires=${cookie.expires.toUTCString()}`;
58
+ }
59
+ if (cookie.maxAge !== void 0) {
60
+ cookieString += `; Max-Age=${cookie.maxAge}`;
61
+ }
62
+ if (cookie.path) {
63
+ cookieString += `; Path=${cookie.path}`;
64
+ }
65
+ if (cookie.domain) {
66
+ cookieString += `; Domain=${cookie.domain}`;
67
+ }
68
+ if (cookie.secure) {
69
+ cookieString += "; Secure";
70
+ }
71
+ if (cookie.httpOnly) {
72
+ cookieString += "; HttpOnly";
73
+ }
74
+ if (cookie.sameSite) {
75
+ cookieString += `; SameSite=${cookie.sameSite.charAt(0).toUpperCase() + cookie.sameSite.slice(1)}`;
76
+ }
77
+ c.header("Set-Cookie", cookieString, { append: true });
78
+ }
79
+ function getCookie(c, name) {
80
+ const cookieHeader = c.req.header("Cookie");
81
+ if (!cookieHeader) return void 0;
82
+ const cookies = cookieHeader.split(";").map((c2) => c2.trim());
83
+ for (const cookie of cookies) {
84
+ const [cookieName, ...valueParts] = cookie.split("=");
85
+ if (cookieName === name) {
86
+ return valueParts.join("=");
87
+ }
88
+ }
89
+ return void 0;
90
+ }
91
+ function createAuthMiddleware(config) {
92
+ const { auth, onUnauthorized } = config;
93
+ return async (c, next) => {
94
+ const authHeader = c.req.header("Authorization");
95
+ let token = extractBearerToken(authHeader);
96
+ if (!token) {
97
+ const cookiePrefix = config.cookies?.prefix ?? "pars";
98
+ token = getCookie(c, `${cookiePrefix}.access_token`) ?? null;
99
+ }
100
+ if (!token) {
101
+ if (onUnauthorized) {
102
+ return onUnauthorized(c, "No token provided");
103
+ }
104
+ return c.json({ error: "Unauthorized", message: "No token provided" }, 401);
105
+ }
106
+ const result = await auth.verifyAccessToken(token);
107
+ if (!result.valid || !result.payload) {
108
+ if (onUnauthorized) {
109
+ return onUnauthorized(c, result.error);
110
+ }
111
+ return c.json({ error: "Unauthorized", message: result.error }, 401);
112
+ }
113
+ const authContext = {
114
+ userId: result.payload.sub,
115
+ payload: result.payload,
116
+ ...result.payload.sid && { sessionId: result.payload.sid },
117
+ ...result.payload.tid && { tenantId: result.payload.tid },
118
+ ...result.payload.roles && { roles: result.payload.roles },
119
+ ...result.payload.permissions && { permissions: result.payload.permissions }
120
+ };
121
+ c.set("auth", authContext);
122
+ await next();
123
+ };
124
+ }
125
+ function createOptionalAuthMiddleware(config) {
126
+ const { auth } = config;
127
+ return async (c, next) => {
128
+ const authHeader = c.req.header("Authorization");
129
+ let token = extractBearerToken(authHeader);
130
+ if (!token) {
131
+ const cookiePrefix = config.cookies?.prefix ?? "pars";
132
+ token = getCookie(c, `${cookiePrefix}.access_token`) ?? null;
133
+ }
134
+ if (token) {
135
+ const result = await auth.verifyAccessToken(token);
136
+ if (result.valid && result.payload) {
137
+ const authContext = {
138
+ userId: result.payload.sub,
139
+ payload: result.payload,
140
+ ...result.payload.sid && { sessionId: result.payload.sid },
141
+ ...result.payload.tid && { tenantId: result.payload.tid },
142
+ ...result.payload.roles && { roles: result.payload.roles },
143
+ ...result.payload.permissions && { permissions: result.payload.permissions }
144
+ };
145
+ c.set("auth", authContext);
146
+ }
147
+ }
148
+ await next();
149
+ };
150
+ }
151
+ function createAuthRoutes(app, config) {
152
+ const { auth, cookies: cookieConfig } = config;
153
+ app.post("/otp/request", async (c) => {
154
+ try {
155
+ const body = await c.req.json();
156
+ if (!body.identifier || !body.type) {
157
+ return c.json({ error: "Bad Request", message: "identifier and type are required" }, 400);
158
+ }
159
+ const result = await auth.requestOTP({
160
+ identifier: body.identifier,
161
+ type: body.type
162
+ });
163
+ if (!result.success) {
164
+ return c.json({
165
+ success: false,
166
+ error: result.error,
167
+ remainingRequests: result.remainingRequests
168
+ }, 429);
169
+ }
170
+ return c.json({
171
+ success: true,
172
+ expiresAt: result.expiresAt,
173
+ remainingRequests: result.remainingRequests
174
+ });
175
+ } catch (error) {
176
+ if (config.onError) {
177
+ return config.onError(error, c);
178
+ }
179
+ return c.json({ error: "Internal Server Error" }, 500);
180
+ }
181
+ });
182
+ app.post("/otp/verify", async (c) => {
183
+ try {
184
+ const body = await c.req.json();
185
+ if (!body.identifier || !body.code) {
186
+ return c.json({ error: "Bad Request", message: "identifier and code are required" }, 400);
187
+ }
188
+ const ipAddress = c.req.header("x-forwarded-for") ?? c.req.header("x-real-ip");
189
+ const userAgent = c.req.header("user-agent");
190
+ const result = await auth.signIn({
191
+ provider: "otp",
192
+ identifier: body.identifier,
193
+ credential: body.code,
194
+ data: { type: body.type ?? "email" },
195
+ metadata: {
196
+ ...ipAddress && { ipAddress },
197
+ ...userAgent && { userAgent }
198
+ }
199
+ });
200
+ if (!result.success) {
201
+ return c.json({
202
+ success: false,
203
+ error: result.error,
204
+ errorCode: result.errorCode
205
+ }, 401);
206
+ }
207
+ if (result.tokens && cookieConfig) {
208
+ const cookies = createAuthCookies(result.tokens, cookieConfig);
209
+ for (const cookie of cookies) {
210
+ setCookie(c, cookie);
211
+ }
212
+ }
213
+ return c.json({
214
+ success: true,
215
+ user: result.user ? {
216
+ id: result.user.id,
217
+ email: result.user.email,
218
+ name: result.user.name
219
+ } : void 0,
220
+ tokens: result.tokens
221
+ });
222
+ } catch (error) {
223
+ if (config.onError) {
224
+ return config.onError(error, c);
225
+ }
226
+ return c.json({ error: "Internal Server Error" }, 500);
227
+ }
228
+ });
229
+ app.post("/sign-in", async (c) => {
230
+ try {
231
+ const body = await c.req.json();
232
+ if (!body.provider || !body.identifier) {
233
+ return c.json({
234
+ error: "Bad Request",
235
+ message: "provider and identifier are required"
236
+ }, 400);
237
+ }
238
+ const ipAddress = c.req.header("x-forwarded-for") ?? c.req.header("x-real-ip");
239
+ const userAgent = c.req.header("user-agent");
240
+ const result = await auth.signIn({
241
+ provider: body.provider,
242
+ identifier: body.identifier,
243
+ ...body.credential && { credential: body.credential },
244
+ ...body.data && { data: body.data },
245
+ metadata: {
246
+ ...ipAddress && { ipAddress },
247
+ ...userAgent && { userAgent }
248
+ }
249
+ });
250
+ if (!result.success) {
251
+ return c.json({
252
+ success: false,
253
+ error: result.error,
254
+ errorCode: result.errorCode,
255
+ requiresTwoFactor: result.requiresTwoFactor
256
+ }, 401);
257
+ }
258
+ if (result.tokens && cookieConfig) {
259
+ const cookies = createAuthCookies(result.tokens, cookieConfig);
260
+ for (const cookie of cookies) {
261
+ setCookie(c, cookie);
262
+ }
263
+ }
264
+ return c.json({
265
+ success: true,
266
+ user: result.user ? {
267
+ id: result.user.id,
268
+ email: result.user.email,
269
+ name: result.user.name
270
+ } : void 0,
271
+ tokens: result.tokens,
272
+ requiresTwoFactor: result.requiresTwoFactor
273
+ });
274
+ } catch (error) {
275
+ if (config.onError) {
276
+ return config.onError(error, c);
277
+ }
278
+ return c.json({ error: "Internal Server Error" }, 500);
279
+ }
280
+ });
281
+ app.post("/sign-out", async (c) => {
282
+ try {
283
+ const authContext = c.get("auth");
284
+ if (authContext?.sessionId) {
285
+ await auth.signOut(authContext.sessionId);
286
+ }
287
+ if (cookieConfig) {
288
+ const cookies = createLogoutCookies(cookieConfig);
289
+ for (const cookie of cookies) {
290
+ setCookie(c, cookie);
291
+ }
292
+ }
293
+ return c.json({ success: true });
294
+ } catch (error) {
295
+ if (config.onError) {
296
+ return config.onError(error, c);
297
+ }
298
+ return c.json({ error: "Internal Server Error" }, 500);
299
+ }
300
+ });
301
+ app.post("/refresh", async (c) => {
302
+ try {
303
+ let refreshToken;
304
+ try {
305
+ const body = await c.req.json();
306
+ refreshToken = body.refreshToken;
307
+ } catch {
308
+ }
309
+ if (!refreshToken) {
310
+ const cookiePrefix = cookieConfig?.prefix ?? "pars";
311
+ refreshToken = getCookie(c, `${cookiePrefix}.refresh_token`);
312
+ }
313
+ if (!refreshToken) {
314
+ return c.json({
315
+ success: false,
316
+ error: "No refresh token provided"
317
+ }, 401);
318
+ }
319
+ const result = await auth.refreshTokens(refreshToken);
320
+ if (!result.success) {
321
+ if (cookieConfig) {
322
+ const cookies = createLogoutCookies(cookieConfig);
323
+ for (const cookie of cookies) {
324
+ setCookie(c, cookie);
325
+ }
326
+ }
327
+ return c.json({
328
+ success: false,
329
+ error: result.error
330
+ }, 401);
331
+ }
332
+ if (result.tokens && cookieConfig) {
333
+ const cookies = createAuthCookies(result.tokens, cookieConfig);
334
+ for (const cookie of cookies) {
335
+ setCookie(c, cookie);
336
+ }
337
+ }
338
+ return c.json({
339
+ success: true,
340
+ tokens: result.tokens
341
+ });
342
+ } catch (error) {
343
+ if (config.onError) {
344
+ return config.onError(error, c);
345
+ }
346
+ return c.json({ error: "Internal Server Error" }, 500);
347
+ }
348
+ });
349
+ app.get("/me", async (c) => {
350
+ const authContext = c.get("auth");
351
+ if (!authContext) {
352
+ return c.json({ error: "Unauthorized" }, 401);
353
+ }
354
+ const user = await auth.getAdapter().findUserById(authContext.userId);
355
+ if (!user) {
356
+ return c.json({ error: "User not found" }, 404);
357
+ }
358
+ return c.json({
359
+ id: user.id,
360
+ email: user.email,
361
+ name: user.name,
362
+ avatar: user.avatar,
363
+ emailVerified: user.emailVerified,
364
+ twoFactorEnabled: user.twoFactorEnabled
365
+ });
366
+ });
367
+ app.get("/sessions", async (c) => {
368
+ const authContext = c.get("auth");
369
+ if (!authContext) {
370
+ return c.json({ error: "Unauthorized" }, 401);
371
+ }
372
+ const sessions = await auth.getSessions(authContext.userId, authContext.sessionId);
373
+ return c.json({ sessions });
374
+ });
375
+ app.delete("/sessions/:id", async (c) => {
376
+ const authContext = c.get("auth");
377
+ if (!authContext) {
378
+ return c.json({ error: "Unauthorized" }, 401);
379
+ }
380
+ const sessionId = c.req.param("id");
381
+ const sessions = await auth.getSessions(authContext.userId);
382
+ const session = sessions.find((s) => s.id === sessionId);
383
+ if (!session) {
384
+ return c.json({ error: "Session not found" }, 404);
385
+ }
386
+ await auth.revokeSession(sessionId);
387
+ return c.json({ success: true });
388
+ });
389
+ app.delete("/sessions", async (c) => {
390
+ const authContext = c.get("auth");
391
+ if (!authContext) {
392
+ return c.json({ error: "Unauthorized" }, 401);
393
+ }
394
+ await auth.revokeAllSessions(authContext.userId);
395
+ if (cookieConfig) {
396
+ const cookies = createLogoutCookies(cookieConfig);
397
+ for (const cookie of cookies) {
398
+ setCookie(c, cookie);
399
+ }
400
+ }
401
+ return c.json({ success: true });
402
+ });
403
+ app.get("/providers", async (c) => {
404
+ const providers = auth.getProviders();
405
+ return c.json({ providers });
406
+ });
407
+ app.get("/tenants", async (c) => {
408
+ const authContext = c.get("auth");
409
+ if (!authContext) {
410
+ return c.json({ error: "Unauthorized" }, 401);
411
+ }
412
+ try {
413
+ const tenants = await auth.getUserTenants(authContext.userId);
414
+ return c.json({
415
+ tenants: tenants.map((t) => ({
416
+ id: t.tenant.id,
417
+ name: t.tenant.name,
418
+ slug: t.tenant.slug,
419
+ role: t.membership.role,
420
+ status: t.tenant.status
421
+ })),
422
+ currentTenantId: authContext.tenantId
423
+ });
424
+ } catch (error) {
425
+ if (config.onError) {
426
+ return config.onError(error, c);
427
+ }
428
+ return c.json({ error: "Internal Server Error" }, 500);
429
+ }
430
+ });
431
+ app.post("/tenants/switch", async (c) => {
432
+ const authContext = c.get("auth");
433
+ if (!authContext?.sessionId) {
434
+ return c.json({ error: "Unauthorized" }, 401);
435
+ }
436
+ try {
437
+ const body = await c.req.json();
438
+ if (!body.tenantId) {
439
+ return c.json({ error: "Bad Request", message: "tenantId is required" }, 400);
440
+ }
441
+ const result = await auth.switchTenant(authContext.sessionId, body.tenantId);
442
+ if (!result.success) {
443
+ return c.json({ success: false, error: result.error }, 403);
444
+ }
445
+ if (result.tokens && cookieConfig) {
446
+ const cookies = createAuthCookies(result.tokens, cookieConfig);
447
+ for (const cookie of cookies) {
448
+ setCookie(c, cookie);
449
+ }
450
+ }
451
+ return c.json({
452
+ success: true,
453
+ tokens: result.tokens
454
+ });
455
+ } catch (error) {
456
+ if (config.onError) {
457
+ return config.onError(error, c);
458
+ }
459
+ return c.json({ error: "Internal Server Error" }, 500);
460
+ }
461
+ });
462
+ app.get("/tenants/current", async (c) => {
463
+ const authContext = c.get("auth");
464
+ if (!authContext) {
465
+ return c.json({ error: "Unauthorized" }, 401);
466
+ }
467
+ if (!authContext.tenantId) {
468
+ return c.json({ tenant: null, membership: null });
469
+ }
470
+ try {
471
+ const membership = await auth.getTenantMembership(
472
+ authContext.userId,
473
+ authContext.tenantId
474
+ );
475
+ if (!membership) {
476
+ return c.json({ tenant: null, membership: null });
477
+ }
478
+ const tenant = await auth.getAdapter().findTenantById?.(authContext.tenantId);
479
+ return c.json({
480
+ tenant: tenant ? {
481
+ id: tenant.id,
482
+ name: tenant.name,
483
+ slug: tenant.slug,
484
+ status: tenant.status
485
+ } : null,
486
+ membership: {
487
+ role: membership.role,
488
+ permissions: membership.permissions,
489
+ status: membership.status
490
+ }
491
+ });
492
+ } catch (error) {
493
+ if (config.onError) {
494
+ return config.onError(error, c);
495
+ }
496
+ return c.json({ error: "Internal Server Error" }, 500);
497
+ }
498
+ });
499
+ app.post("/tenants/:tenantId/invite", async (c) => {
500
+ const authContext = c.get("auth");
501
+ if (!authContext) {
502
+ return c.json({ error: "Unauthorized" }, 401);
503
+ }
504
+ try {
505
+ const tenantId = c.req.param("tenantId");
506
+ const body = await c.req.json();
507
+ if (!body.email || !body.role) {
508
+ return c.json({ error: "Bad Request", message: "email and role are required" }, 400);
509
+ }
510
+ const isAdmin = await auth.hasRoleInTenant(authContext.userId, tenantId, "admin") || await auth.hasRoleInTenant(authContext.userId, tenantId, "owner");
511
+ if (!isAdmin) {
512
+ return c.json({ error: "Forbidden", message: "Admin access required" }, 403);
513
+ }
514
+ const result = await auth.inviteToTenant({
515
+ email: body.email,
516
+ tenantId,
517
+ role: body.role,
518
+ permissions: body.permissions,
519
+ invitedBy: authContext.userId,
520
+ message: body.message
521
+ });
522
+ if (!result.success) {
523
+ return c.json({ success: false, error: result.error }, 400);
524
+ }
525
+ return c.json({
526
+ success: true,
527
+ invitationUrl: result.invitationUrl,
528
+ expiresAt: result.invitation?.expiresAt
529
+ });
530
+ } catch (error) {
531
+ if (config.onError) {
532
+ return config.onError(error, c);
533
+ }
534
+ return c.json({ error: "Internal Server Error" }, 500);
535
+ }
536
+ });
537
+ app.get("/invitation", async (c) => {
538
+ try {
539
+ const token = c.req.query("token");
540
+ if (!token) {
541
+ return c.json({ error: "Bad Request", message: "token is required" }, 400);
542
+ }
543
+ const result = await auth.checkInvitation(token);
544
+ return c.json(result);
545
+ } catch (error) {
546
+ if (config.onError) {
547
+ return config.onError(error, c);
548
+ }
549
+ return c.json({ error: "Internal Server Error" }, 500);
550
+ }
551
+ });
552
+ app.post("/invitation/accept", async (c) => {
553
+ const authContext = c.get("auth");
554
+ if (!authContext) {
555
+ return c.json({ error: "Unauthorized" }, 401);
556
+ }
557
+ try {
558
+ const body = await c.req.json();
559
+ if (!body.token) {
560
+ return c.json({ error: "Bad Request", message: "token is required" }, 400);
561
+ }
562
+ const result = await auth.acceptInvitation(body.token, authContext.userId);
563
+ if (!result.success) {
564
+ return c.json({ success: false, error: result.error }, 400);
565
+ }
566
+ return c.json({
567
+ success: true,
568
+ tenant: result.tenant ? {
569
+ id: result.tenant.id,
570
+ name: result.tenant.name,
571
+ slug: result.tenant.slug
572
+ } : void 0,
573
+ membership: result.membership ? {
574
+ role: result.membership.role,
575
+ status: result.membership.status
576
+ } : void 0
577
+ });
578
+ } catch (error) {
579
+ if (config.onError) {
580
+ return config.onError(error, c);
581
+ }
582
+ return c.json({ error: "Internal Server Error" }, 500);
583
+ }
584
+ });
585
+ app.delete("/tenants/:tenantId/members/:userId", async (c) => {
586
+ const authContext = c.get("auth");
587
+ if (!authContext) {
588
+ return c.json({ error: "Unauthorized" }, 401);
589
+ }
590
+ try {
591
+ const tenantId = c.req.param("tenantId");
592
+ const userId = c.req.param("userId");
593
+ const isAdmin = await auth.hasRoleInTenant(authContext.userId, tenantId, "admin") || await auth.hasRoleInTenant(authContext.userId, tenantId, "owner");
594
+ const isSelf = authContext.userId === userId;
595
+ if (!isAdmin && !isSelf) {
596
+ return c.json({ error: "Forbidden", message: "Admin access required" }, 403);
597
+ }
598
+ await auth.removeTenantMember(userId, tenantId);
599
+ return c.json({ success: true });
600
+ } catch (error) {
601
+ if (config.onError) {
602
+ return config.onError(error, c);
603
+ }
604
+ return c.json({ error: "Internal Server Error" }, 500);
605
+ }
606
+ });
607
+ app.patch("/tenants/:tenantId/members/:userId", async (c) => {
608
+ const authContext = c.get("auth");
609
+ if (!authContext) {
610
+ return c.json({ error: "Unauthorized" }, 401);
611
+ }
612
+ try {
613
+ const tenantId = c.req.param("tenantId");
614
+ const userId = c.req.param("userId");
615
+ const body = await c.req.json();
616
+ const isAdmin = await auth.hasRoleInTenant(authContext.userId, tenantId, "admin") || await auth.hasRoleInTenant(authContext.userId, tenantId, "owner");
617
+ if (!isAdmin) {
618
+ return c.json({ error: "Forbidden", message: "Admin access required" }, 403);
619
+ }
620
+ const membership = await auth.updateTenantMember(userId, tenantId, body);
621
+ return c.json({
622
+ success: true,
623
+ membership: {
624
+ role: membership.role,
625
+ permissions: membership.permissions,
626
+ status: membership.status
627
+ }
628
+ });
629
+ } catch (error) {
630
+ if (config.onError) {
631
+ return config.onError(error, c);
632
+ }
633
+ return c.json({ error: "Internal Server Error" }, 500);
634
+ }
635
+ });
636
+ return app;
637
+ }
638
+ function createHonoAuth(config) {
639
+ return {
640
+ /** Auth middleware (requires authentication) */
641
+ middleware: createAuthMiddleware(config),
642
+ /** Optional auth middleware (attaches auth if present) */
643
+ optionalMiddleware: createOptionalAuthMiddleware(config),
644
+ /** Create auth routes on an app */
645
+ createRoutes: (app) => createAuthRoutes(app, config)
646
+ };
647
+ }
648
+ function toAuthorizationContext(auth) {
649
+ return {
650
+ userId: auth.userId,
651
+ tenantId: auth.tenantId,
652
+ roles: auth.roles,
653
+ permissions: auth.permissions
654
+ };
655
+ }
656
+ function requireRole(...allowedRoles) {
657
+ return async (c, next) => {
658
+ const auth = c.get("auth");
659
+ if (!auth) {
660
+ return c.json({ error: "Unauthorized", message: "Authentication required" }, 401);
661
+ }
662
+ const guard = createAuthorizationGuard(toAuthorizationContext(auth));
663
+ if (!guard.hasAnyRole(allowedRoles)) {
664
+ return c.json(
665
+ {
666
+ error: "Forbidden",
667
+ message: "Insufficient role",
668
+ required: allowedRoles,
669
+ current: auth.roles ?? []
670
+ },
671
+ 403
672
+ );
673
+ }
674
+ await next();
675
+ };
676
+ }
677
+ function requirePermission(...permissions) {
678
+ return async (c, next) => {
679
+ const auth = c.get("auth");
680
+ if (!auth) {
681
+ return c.json({ error: "Unauthorized", message: "Authentication required" }, 401);
682
+ }
683
+ const guard = createAuthorizationGuard(toAuthorizationContext(auth));
684
+ if (!guard.hasAllPermissions(permissions)) {
685
+ return c.json(
686
+ {
687
+ error: "Forbidden",
688
+ message: "Missing required permissions",
689
+ required: permissions,
690
+ current: auth.permissions ?? []
691
+ },
692
+ 403
693
+ );
694
+ }
695
+ await next();
696
+ };
697
+ }
698
+ function requireAnyPermission(...permissions) {
699
+ return async (c, next) => {
700
+ const auth = c.get("auth");
701
+ if (!auth) {
702
+ return c.json({ error: "Unauthorized", message: "Authentication required" }, 401);
703
+ }
704
+ const guard = createAuthorizationGuard(toAuthorizationContext(auth));
705
+ if (!guard.hasAnyPermission(permissions)) {
706
+ return c.json(
707
+ {
708
+ error: "Forbidden",
709
+ message: "Missing required permissions",
710
+ required: permissions,
711
+ current: auth.permissions ?? []
712
+ },
713
+ 403
714
+ );
715
+ }
716
+ await next();
717
+ };
718
+ }
719
+ function requireTenant() {
720
+ return async (c, next) => {
721
+ const auth = c.get("auth");
722
+ if (!auth) {
723
+ return c.json({ error: "Unauthorized", message: "Authentication required" }, 401);
724
+ }
725
+ if (!auth.tenantId) {
726
+ return c.json(
727
+ { error: "Forbidden", message: "Tenant context required" },
728
+ 403
729
+ );
730
+ }
731
+ await next();
732
+ };
733
+ }
734
+ function requireTenantAccess(getTenantId, options) {
735
+ return async (c, next) => {
736
+ const auth = c.get("auth");
737
+ if (!auth) {
738
+ return c.json({ error: "Unauthorized", message: "Authentication required" }, 401);
739
+ }
740
+ const requestedTenantId = getTenantId(c);
741
+ if (!requestedTenantId) {
742
+ await next();
743
+ return;
744
+ }
745
+ const guard = createAuthorizationGuard(toAuthorizationContext(auth));
746
+ if (options?.bypassRoles && guard.hasAnyRole(options.bypassRoles)) {
747
+ await next();
748
+ return;
749
+ }
750
+ if (auth.tenantId !== requestedTenantId) {
751
+ return c.json(
752
+ {
753
+ error: "Forbidden",
754
+ message: "Access denied to this tenant",
755
+ requestedTenant: requestedTenantId
756
+ },
757
+ 403
758
+ );
759
+ }
760
+ await next();
761
+ };
762
+ }
763
+ function requireAdmin() {
764
+ return async (c, next) => {
765
+ const auth = c.get("auth");
766
+ if (!auth) {
767
+ return c.json({ error: "Unauthorized", message: "Authentication required" }, 401);
768
+ }
769
+ const guard = createAuthorizationGuard(toAuthorizationContext(auth));
770
+ const isAdmin = guard.hasRole("admin") || guard.hasRole("owner") || guard.hasRole("superadmin") || guard.hasRole("super_admin") || guard.hasPermission("*");
771
+ if (!isAdmin) {
772
+ return c.json({ error: "Forbidden", message: "Admin access required" }, 403);
773
+ }
774
+ await next();
775
+ };
776
+ }
777
+ function requireOwnerOrPermission(getOwnerId, permission) {
778
+ return async (c, next) => {
779
+ const auth = c.get("auth");
780
+ if (!auth) {
781
+ return c.json({ error: "Unauthorized", message: "Authentication required" }, 401);
782
+ }
783
+ const guard = createAuthorizationGuard(toAuthorizationContext(auth));
784
+ if (guard.hasPermission(permission)) {
785
+ await next();
786
+ return;
787
+ }
788
+ const ownerId = await getOwnerId(c);
789
+ if (auth.userId === ownerId) {
790
+ await next();
791
+ return;
792
+ }
793
+ return c.json(
794
+ {
795
+ error: "Forbidden",
796
+ message: "Resource owner or permission required",
797
+ requiredPermission: permission
798
+ },
799
+ 403
800
+ );
801
+ };
802
+ }
803
+ function requireAll(...middlewares) {
804
+ return async (c, next) => {
805
+ for (const middleware of middlewares) {
806
+ let passed = false;
807
+ await middleware(c, async () => {
808
+ passed = true;
809
+ });
810
+ if (!passed) {
811
+ return;
812
+ }
813
+ }
814
+ await next();
815
+ };
816
+ }
817
+ function requireAny(...middlewares) {
818
+ return async (c, next) => {
819
+ for (const middleware of middlewares) {
820
+ let passed = false;
821
+ await middleware(c, async () => {
822
+ passed = true;
823
+ });
824
+ if (passed) {
825
+ await next();
826
+ return;
827
+ }
828
+ }
829
+ return c.json(
830
+ { error: "Forbidden", message: "None of the authorization requirements were met" },
831
+ 403
832
+ );
833
+ };
834
+ }
835
+
836
+ export { createAuthCookies, createAuthMiddleware, createAuthRoutes, createHonoAuth, createLogoutCookies, createOptionalAuthMiddleware, requireAdmin, requireAll, requireAny, requireAnyPermission, requireOwnerOrPermission, requirePermission, requireRole, requireTenant, requireTenantAccess };
837
+ //# sourceMappingURL=chunk-RHNVRCF3.js.map
838
+ //# sourceMappingURL=chunk-RHNVRCF3.js.map