@kaiz11/stack-client 0.0.14

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 (263) hide show
  1. package/LICENSE +32 -0
  2. package/README.md +586 -0
  3. package/dist/accounts/accounts-client.d.ts +188 -0
  4. package/dist/accounts/accounts-client.d.ts.map +1 -0
  5. package/dist/accounts/accounts-client.js +264 -0
  6. package/dist/accounts/accounts-client.js.map +1 -0
  7. package/dist/accounts/index.d.ts +8 -0
  8. package/dist/accounts/index.d.ts.map +1 -0
  9. package/dist/accounts/index.js +8 -0
  10. package/dist/accounts/index.js.map +1 -0
  11. package/dist/accounts/mock-accounts.d.ts +90 -0
  12. package/dist/accounts/mock-accounts.d.ts.map +1 -0
  13. package/dist/accounts/mock-accounts.js +434 -0
  14. package/dist/accounts/mock-accounts.js.map +1 -0
  15. package/dist/accounts/types.d.ts +180 -0
  16. package/dist/accounts/types.d.ts.map +1 -0
  17. package/dist/accounts/types.js +59 -0
  18. package/dist/accounts/types.js.map +1 -0
  19. package/dist/auth/auth-client.d.ts +224 -0
  20. package/dist/auth/auth-client.d.ts.map +1 -0
  21. package/dist/auth/auth-client.js +230 -0
  22. package/dist/auth/auth-client.js.map +1 -0
  23. package/dist/auth/base-auth.d.ts +44 -0
  24. package/dist/auth/base-auth.d.ts.map +1 -0
  25. package/dist/auth/base-auth.js +55 -0
  26. package/dist/auth/base-auth.js.map +1 -0
  27. package/dist/auth/index.d.ts +11 -0
  28. package/dist/auth/index.d.ts.map +1 -0
  29. package/dist/auth/index.js +11 -0
  30. package/dist/auth/index.js.map +1 -0
  31. package/dist/auth/methods/admin.d.ts +59 -0
  32. package/dist/auth/methods/admin.d.ts.map +1 -0
  33. package/dist/auth/methods/admin.js +55 -0
  34. package/dist/auth/methods/admin.js.map +1 -0
  35. package/dist/auth/methods/index.d.ts +9 -0
  36. package/dist/auth/methods/index.d.ts.map +1 -0
  37. package/dist/auth/methods/index.js +8 -0
  38. package/dist/auth/methods/index.js.map +1 -0
  39. package/dist/auth/methods/magic-link.d.ts +27 -0
  40. package/dist/auth/methods/magic-link.d.ts.map +1 -0
  41. package/dist/auth/methods/magic-link.js +37 -0
  42. package/dist/auth/methods/magic-link.js.map +1 -0
  43. package/dist/auth/methods/mfa.d.ts +92 -0
  44. package/dist/auth/methods/mfa.d.ts.map +1 -0
  45. package/dist/auth/methods/mfa.js +153 -0
  46. package/dist/auth/methods/mfa.js.map +1 -0
  47. package/dist/auth/methods/oauth.d.ts +62 -0
  48. package/dist/auth/methods/oauth.d.ts.map +1 -0
  49. package/dist/auth/methods/oauth.js +165 -0
  50. package/dist/auth/methods/oauth.js.map +1 -0
  51. package/dist/auth/methods/otp.d.ts +43 -0
  52. package/dist/auth/methods/otp.d.ts.map +1 -0
  53. package/dist/auth/methods/otp.js +66 -0
  54. package/dist/auth/methods/otp.js.map +1 -0
  55. package/dist/auth/methods/password.d.ts +64 -0
  56. package/dist/auth/methods/password.d.ts.map +1 -0
  57. package/dist/auth/methods/password.js +116 -0
  58. package/dist/auth/methods/password.js.map +1 -0
  59. package/dist/auth/methods/recovery.d.ts +62 -0
  60. package/dist/auth/methods/recovery.d.ts.map +1 -0
  61. package/dist/auth/methods/recovery.js +100 -0
  62. package/dist/auth/methods/recovery.js.map +1 -0
  63. package/dist/auth/mock-auth.d.ts +135 -0
  64. package/dist/auth/mock-auth.d.ts.map +1 -0
  65. package/dist/auth/mock-auth.js +417 -0
  66. package/dist/auth/mock-auth.js.map +1 -0
  67. package/dist/auth/server/helpers.d.ts +215 -0
  68. package/dist/auth/server/helpers.d.ts.map +1 -0
  69. package/dist/auth/server/helpers.js +241 -0
  70. package/dist/auth/server/helpers.js.map +1 -0
  71. package/dist/auth/server/index.d.ts +24 -0
  72. package/dist/auth/server/index.d.ts.map +1 -0
  73. package/dist/auth/server/index.js +40 -0
  74. package/dist/auth/server/index.js.map +1 -0
  75. package/dist/auth/server/middleware.d.ts +305 -0
  76. package/dist/auth/server/middleware.d.ts.map +1 -0
  77. package/dist/auth/server/middleware.js +405 -0
  78. package/dist/auth/server/middleware.js.map +1 -0
  79. package/dist/auth/server/verify.d.ts +184 -0
  80. package/dist/auth/server/verify.d.ts.map +1 -0
  81. package/dist/auth/server/verify.js +222 -0
  82. package/dist/auth/server/verify.js.map +1 -0
  83. package/dist/auth/token-manager.d.ts +94 -0
  84. package/dist/auth/token-manager.d.ts.map +1 -0
  85. package/dist/auth/token-manager.js +231 -0
  86. package/dist/auth/token-manager.js.map +1 -0
  87. package/dist/auth/types.d.ts +412 -0
  88. package/dist/auth/types.d.ts.map +1 -0
  89. package/dist/auth/types.js +66 -0
  90. package/dist/auth/types.js.map +1 -0
  91. package/dist/auth/user/identities.d.ts +62 -0
  92. package/dist/auth/user/identities.d.ts.map +1 -0
  93. package/dist/auth/user/identities.js +88 -0
  94. package/dist/auth/user/identities.js.map +1 -0
  95. package/dist/auth/user/index.d.ts +4 -0
  96. package/dist/auth/user/index.d.ts.map +1 -0
  97. package/dist/auth/user/index.js +4 -0
  98. package/dist/auth/user/index.js.map +1 -0
  99. package/dist/auth/user/user.d.ts +64 -0
  100. package/dist/auth/user/user.d.ts.map +1 -0
  101. package/dist/auth/user/user.js +105 -0
  102. package/dist/auth/user/user.js.map +1 -0
  103. package/dist/auth/user/verification.d.ts +49 -0
  104. package/dist/auth/user/verification.d.ts.map +1 -0
  105. package/dist/auth/user/verification.js +71 -0
  106. package/dist/auth/user/verification.js.map +1 -0
  107. package/dist/cli/browser.d.ts +11 -0
  108. package/dist/cli/browser.d.ts.map +1 -0
  109. package/dist/cli/browser.js +35 -0
  110. package/dist/cli/browser.js.map +1 -0
  111. package/dist/cli/callback-server.d.ts +30 -0
  112. package/dist/cli/callback-server.d.ts.map +1 -0
  113. package/dist/cli/callback-server.js +100 -0
  114. package/dist/cli/callback-server.js.map +1 -0
  115. package/dist/cli/file-token-store.d.ts +79 -0
  116. package/dist/cli/file-token-store.d.ts.map +1 -0
  117. package/dist/cli/file-token-store.js +138 -0
  118. package/dist/cli/file-token-store.js.map +1 -0
  119. package/dist/cli/index.d.ts +33 -0
  120. package/dist/cli/index.d.ts.map +1 -0
  121. package/dist/cli/index.js +38 -0
  122. package/dist/cli/index.js.map +1 -0
  123. package/dist/cli/oauth.d.ts +67 -0
  124. package/dist/cli/oauth.d.ts.map +1 -0
  125. package/dist/cli/oauth.js +101 -0
  126. package/dist/cli/oauth.js.map +1 -0
  127. package/dist/cli/pkce.d.ts +35 -0
  128. package/dist/cli/pkce.d.ts.map +1 -0
  129. package/dist/cli/pkce.js +43 -0
  130. package/dist/cli/pkce.js.map +1 -0
  131. package/dist/client.d.ts +22 -0
  132. package/dist/client.d.ts.map +1 -0
  133. package/dist/client.js +99 -0
  134. package/dist/client.js.map +1 -0
  135. package/dist/db/client.d.ts +9 -0
  136. package/dist/db/client.d.ts.map +1 -0
  137. package/dist/db/client.js +19 -0
  138. package/dist/db/client.js.map +1 -0
  139. package/dist/db/errors.d.ts +19 -0
  140. package/dist/db/errors.d.ts.map +1 -0
  141. package/dist/db/errors.js +57 -0
  142. package/dist/db/errors.js.map +1 -0
  143. package/dist/db/index.d.ts +7 -0
  144. package/dist/db/index.d.ts.map +1 -0
  145. package/dist/db/index.js +5 -0
  146. package/dist/db/index.js.map +1 -0
  147. package/dist/db/mock.d.ts +28 -0
  148. package/dist/db/mock.d.ts.map +1 -0
  149. package/dist/db/mock.js +459 -0
  150. package/dist/db/mock.js.map +1 -0
  151. package/dist/db/types.d.ts +73 -0
  152. package/dist/db/types.d.ts.map +1 -0
  153. package/dist/db/types.js +2 -0
  154. package/dist/db/types.js.map +1 -0
  155. package/dist/index.d.ts +21 -0
  156. package/dist/index.d.ts.map +1 -0
  157. package/dist/index.js +20 -0
  158. package/dist/index.js.map +1 -0
  159. package/dist/lib/errors.d.ts +33 -0
  160. package/dist/lib/errors.d.ts.map +1 -0
  161. package/dist/lib/errors.js +76 -0
  162. package/dist/lib/errors.js.map +1 -0
  163. package/dist/lib/http.d.ts +81 -0
  164. package/dist/lib/http.d.ts.map +1 -0
  165. package/dist/lib/http.js +163 -0
  166. package/dist/lib/http.js.map +1 -0
  167. package/dist/lib/keys.d.ts +87 -0
  168. package/dist/lib/keys.d.ts.map +1 -0
  169. package/dist/lib/keys.js +147 -0
  170. package/dist/lib/keys.js.map +1 -0
  171. package/dist/lib/paths.d.ts +37 -0
  172. package/dist/lib/paths.d.ts.map +1 -0
  173. package/dist/lib/paths.js +49 -0
  174. package/dist/lib/paths.js.map +1 -0
  175. package/dist/lib/token-store.d.ts +42 -0
  176. package/dist/lib/token-store.d.ts.map +1 -0
  177. package/dist/lib/token-store.js +75 -0
  178. package/dist/lib/token-store.js.map +1 -0
  179. package/dist/mocks/handlers.d.ts +29 -0
  180. package/dist/mocks/handlers.d.ts.map +1 -0
  181. package/dist/mocks/handlers.js +79 -0
  182. package/dist/mocks/handlers.js.map +1 -0
  183. package/dist/mocks/index.d.ts +5 -0
  184. package/dist/mocks/index.d.ts.map +1 -0
  185. package/dist/mocks/index.js +9 -0
  186. package/dist/mocks/index.js.map +1 -0
  187. package/dist/mocks/responses.d.ts +76 -0
  188. package/dist/mocks/responses.d.ts.map +1 -0
  189. package/dist/mocks/responses.js +91 -0
  190. package/dist/mocks/responses.js.map +1 -0
  191. package/dist/mocks/server.d.ts +7 -0
  192. package/dist/mocks/server.d.ts.map +1 -0
  193. package/dist/mocks/server.js +9 -0
  194. package/dist/mocks/server.js.map +1 -0
  195. package/dist/mocks/state.d.ts +86 -0
  196. package/dist/mocks/state.d.ts.map +1 -0
  197. package/dist/mocks/state.js +77 -0
  198. package/dist/mocks/state.js.map +1 -0
  199. package/dist/storage/bucket-ref.d.ts +183 -0
  200. package/dist/storage/bucket-ref.d.ts.map +1 -0
  201. package/dist/storage/bucket-ref.js +529 -0
  202. package/dist/storage/bucket-ref.js.map +1 -0
  203. package/dist/storage/errors.d.ts +27 -0
  204. package/dist/storage/errors.d.ts.map +1 -0
  205. package/dist/storage/errors.js +89 -0
  206. package/dist/storage/errors.js.map +1 -0
  207. package/dist/storage/index.d.ts +13 -0
  208. package/dist/storage/index.d.ts.map +1 -0
  209. package/dist/storage/index.js +11 -0
  210. package/dist/storage/index.js.map +1 -0
  211. package/dist/storage/interface.d.ts +245 -0
  212. package/dist/storage/interface.d.ts.map +1 -0
  213. package/dist/storage/interface.js +2 -0
  214. package/dist/storage/interface.js.map +1 -0
  215. package/dist/storage/mock-storage.d.ts +67 -0
  216. package/dist/storage/mock-storage.d.ts.map +1 -0
  217. package/dist/storage/mock-storage.js +478 -0
  218. package/dist/storage/mock-storage.js.map +1 -0
  219. package/dist/storage/policies-client.d.ts +77 -0
  220. package/dist/storage/policies-client.d.ts.map +1 -0
  221. package/dist/storage/policies-client.js +115 -0
  222. package/dist/storage/policies-client.js.map +1 -0
  223. package/dist/storage/policy-templates.d.ts +6 -0
  224. package/dist/storage/policy-templates.d.ts.map +1 -0
  225. package/dist/storage/policy-templates.js +290 -0
  226. package/dist/storage/policy-templates.js.map +1 -0
  227. package/dist/storage/policy-types.d.ts +98 -0
  228. package/dist/storage/policy-types.d.ts.map +1 -0
  229. package/dist/storage/policy-types.js +20 -0
  230. package/dist/storage/policy-types.js.map +1 -0
  231. package/dist/storage/storage-client.d.ts +32 -0
  232. package/dist/storage/storage-client.d.ts.map +1 -0
  233. package/dist/storage/storage-client.js +94 -0
  234. package/dist/storage/storage-client.js.map +1 -0
  235. package/dist/storage/tus-upload.d.ts +56 -0
  236. package/dist/storage/tus-upload.d.ts.map +1 -0
  237. package/dist/storage/tus-upload.js +236 -0
  238. package/dist/storage/tus-upload.js.map +1 -0
  239. package/dist/storage/types.d.ts +335 -0
  240. package/dist/storage/types.d.ts.map +1 -0
  241. package/dist/storage/types.js +39 -0
  242. package/dist/storage/types.js.map +1 -0
  243. package/dist/test/auth/helpers.d.ts +33 -0
  244. package/dist/test/auth/helpers.d.ts.map +1 -0
  245. package/dist/test/auth/helpers.js +80 -0
  246. package/dist/test/auth/helpers.js.map +1 -0
  247. package/dist/test/helpers/jwt.d.ts +61 -0
  248. package/dist/test/helpers/jwt.d.ts.map +1 -0
  249. package/dist/test/helpers/jwt.js +132 -0
  250. package/dist/test/helpers/jwt.js.map +1 -0
  251. package/dist/test/helpers/mailpit.d.ts +61 -0
  252. package/dist/test/helpers/mailpit.d.ts.map +1 -0
  253. package/dist/test/helpers/mailpit.js +107 -0
  254. package/dist/test/helpers/mailpit.js.map +1 -0
  255. package/dist/test/setup.d.ts +2 -0
  256. package/dist/test/setup.d.ts.map +1 -0
  257. package/dist/test/setup.js +17 -0
  258. package/dist/test/setup.js.map +1 -0
  259. package/dist/types.d.ts +96 -0
  260. package/dist/types.d.ts.map +1 -0
  261. package/dist/types.js +5 -0
  262. package/dist/types.js.map +1 -0
  263. package/package.json +78 -0
@@ -0,0 +1,405 @@
1
+ import { verifyToken, extractBearerToken, createJWKS, VerifyError, } from "./verify.js";
2
+ import { PLATFORM_TENANT_ID } from "../../types.js";
3
+ import { fetchAnonKeyCached } from "../../lib/keys.js";
4
+ /**
5
+ * Create auth middleware for Hono
6
+ *
7
+ * Automatically constructs the JWKS URL from the base URL and optional tenant ID,
8
+ * and verifies JWT tokens signed by the GoTrue instance.
9
+ *
10
+ * ## Token Handling
11
+ *
12
+ * | Token Type | Result |
13
+ * |---------------|-------------------------------------------------|
14
+ * | No token | 401 Unauthorized |
15
+ * | Invalid token | 401 Unauthorized |
16
+ * | Anon JWT | ✅ Passes, `user.role = "anon"` |
17
+ * | Auth JWT | ✅ Passes, `user.role = "authenticated"` |
18
+ * | Service JWT | ✅ Passes, `user.role = "service_role"` |
19
+ *
20
+ * **Note:** This middleware requires a valid JWT. In Supabase's model, even
21
+ * "public" requests use the anon key. If you want to allow requests without
22
+ * any token, use `optionalStackAuthMiddleware` instead.
23
+ *
24
+ * @example
25
+ * ```typescript
26
+ * import { Hono } from "hono";
27
+ * import { createStackAuthMiddleware } from "@kaiz11/stack-client/auth/server";
28
+ *
29
+ * const app = new Hono();
30
+ *
31
+ * // Platform (default)
32
+ * app.use("*", createStackAuthMiddleware({
33
+ * baseUrl: "https://stack.zenku.app",
34
+ * excludePaths: [/^\/health$/],
35
+ * }));
36
+ *
37
+ * // Tenant
38
+ * app.use("*", createStackAuthMiddleware({
39
+ * baseUrl: "https://stack.zenku.app",
40
+ * tenantId: "acme-corp",
41
+ * excludePaths: [/^\/health$/],
42
+ * }));
43
+ *
44
+ * app.get("/api/me", (c) => {
45
+ * const user = c.get("user") as AuthUser;
46
+ * return c.json({ user });
47
+ * });
48
+ * ```
49
+ */
50
+ export function createStackAuthMiddleware(config) {
51
+ const tenantId = config.tenantId ?? PLATFORM_TENANT_ID;
52
+ const keyGetter = createJWKS(config.baseUrl, tenantId);
53
+ return createAuthMiddleware({
54
+ keyGetter,
55
+ options: config.options,
56
+ excludePaths: config.excludePaths,
57
+ onError: config.onError,
58
+ });
59
+ }
60
+ /**
61
+ * Create auth middleware for Hono (advanced)
62
+ *
63
+ * Use this when you need to provide a custom JWKS key getter.
64
+ * For most cases, prefer `createStackAuthMiddleware`.
65
+ *
66
+ * ## Token Handling
67
+ *
68
+ * | Token Type | Result |
69
+ * |---------------|-------------------------------------------------|
70
+ * | No token | 401 Unauthorized |
71
+ * | Invalid token | 401 Unauthorized |
72
+ * | Anon JWT | ✅ Passes, `user.role = "anon"` |
73
+ * | Auth JWT | ✅ Passes, `user.role = "authenticated"` |
74
+ * | Service JWT | ✅ Passes, `user.role = "service_role"` |
75
+ *
76
+ * @example
77
+ * ```typescript
78
+ * import { Hono } from "hono";
79
+ * import { createAuthMiddleware, createLocalJWKS } from "@kaiz11/stack-client/auth/server";
80
+ *
81
+ * const app = new Hono();
82
+ *
83
+ * // For testing with local keys
84
+ * const keyGetter = createLocalJWKS(testJWKS);
85
+ *
86
+ * app.use("*", createAuthMiddleware({
87
+ * keyGetter,
88
+ * excludePaths: [/^\/health$/],
89
+ * }));
90
+ * ```
91
+ */
92
+ export function createAuthMiddleware(config) {
93
+ const { keyGetter, options, excludePaths = [], onError } = config;
94
+ return async (c, next) => {
95
+ // Check if path is excluded
96
+ const path = c.req.path;
97
+ for (const pattern of excludePaths) {
98
+ if (pattern.test(path)) {
99
+ return next();
100
+ }
101
+ }
102
+ // Extract and verify token
103
+ const authHeader = c.req.raw.headers.get("authorization");
104
+ const token = extractBearerToken(authHeader);
105
+ if (!token) {
106
+ const error = VerifyError.missingToken();
107
+ if (onError) {
108
+ return onError(error);
109
+ }
110
+ return c.json({ error: error.message, code: error.code }, 401);
111
+ }
112
+ try {
113
+ const payload = await verifyToken(token, keyGetter, options);
114
+ const user = {
115
+ id: payload.sub,
116
+ email: payload.email ?? null,
117
+ phone: payload.phone ?? null,
118
+ role: payload.role,
119
+ aal: payload.aal || "aal1",
120
+ appMetadata: payload.app_metadata ?? {},
121
+ userMetadata: payload.user_metadata ?? {},
122
+ };
123
+ // Attach to context
124
+ c.set("user", user);
125
+ c.set("tokenPayload", payload);
126
+ c.set("accessToken", token);
127
+ return next();
128
+ }
129
+ catch (error) {
130
+ if (error instanceof VerifyError) {
131
+ if (onError) {
132
+ return onError(error);
133
+ }
134
+ return c.json({ error: error.message, code: error.code }, error.statusCode);
135
+ }
136
+ throw error;
137
+ }
138
+ };
139
+ }
140
+ /**
141
+ * Create role guard middleware for Hono
142
+ *
143
+ * Use after `createStackAuthMiddleware` to require specific roles.
144
+ *
145
+ * ## Token Handling (assuming auth middleware already ran)
146
+ *
147
+ * | Token Type | `requireRoleMiddleware("authenticated")` | `requireRoleMiddleware("service_role")` |
148
+ * |---------------|------------------------------------------|----------------------------------------|
149
+ * | Anon JWT | 403 Forbidden | 403 Forbidden |
150
+ * | Auth JWT | ✅ Passes | 403 Forbidden |
151
+ * | Service JWT | 403 Forbidden | ✅ Passes |
152
+ *
153
+ * **Common patterns:**
154
+ * - `requireRoleMiddleware("authenticated")` — Reject anon, allow logged-in users
155
+ * - `requireRoleMiddleware("service_role")` — Admin/server-only endpoints
156
+ *
157
+ * @example
158
+ * ```typescript
159
+ * import { createStackAuthMiddleware, requireRoleMiddleware } from "@kaiz11/stack-client/auth/server";
160
+ *
161
+ * app.use("*", createStackAuthMiddleware({ baseUrl: "https://stack.zenku.app" }));
162
+ *
163
+ * // Reject anon tokens, require actual login
164
+ * app.use("/api/user/*", requireRoleMiddleware("authenticated"));
165
+ *
166
+ * // Admin routes require service_role
167
+ * app.use("/admin/*", requireRoleMiddleware("service_role"));
168
+ * ```
169
+ */
170
+ export function requireRoleMiddleware(role) {
171
+ return async (c, next) => {
172
+ const user = c.get("user");
173
+ if (!user) {
174
+ return c.json({ error: "Authentication required", code: "missing_auth" }, 401);
175
+ }
176
+ if (user.role !== role) {
177
+ return c.json({
178
+ error: `Insufficient role: required ${role}, got ${user.role}`,
179
+ code: "insufficient_role",
180
+ }, 403);
181
+ }
182
+ return next();
183
+ };
184
+ }
185
+ /**
186
+ * Create MFA guard middleware for Hono
187
+ *
188
+ * Requires AAL2 (two-factor authentication verified in current session).
189
+ *
190
+ * ## Token Handling (assuming auth middleware already ran)
191
+ *
192
+ * | Token Type | AAL Level | Result |
193
+ * |------------------|-----------|-------------------------------------|
194
+ * | Anon JWT | aal1 | 403 MFA required |
195
+ * | Auth JWT | aal1 | 403 MFA required |
196
+ * | Auth JWT + MFA | aal2 | ✅ Passes |
197
+ * | Service JWT | aal1 | 403 MFA required |
198
+ *
199
+ * **Note:** Service role tokens typically have aal1. If you need service role
200
+ * access to MFA-protected routes, check the role explicitly instead.
201
+ *
202
+ * @example
203
+ * ```typescript
204
+ * // Sensitive routes require MFA
205
+ * app.use("/settings/security/*", requireMfaMiddleware());
206
+ *
207
+ * // Or combine with role check for admin bypass
208
+ * app.use("/settings/security/*", async (c, next) => {
209
+ * const user = c.get("user") as AuthUser;
210
+ * if (user.role === "service_role") return next(); // Admin bypass
211
+ * return requireMfaMiddleware()(c, next);
212
+ * });
213
+ * ```
214
+ */
215
+ export function requireMfaMiddleware() {
216
+ return async (c, next) => {
217
+ const user = c.get("user");
218
+ const payload = c.get("tokenPayload");
219
+ if (!user || !payload) {
220
+ return c.json({ error: "Authentication required", code: "missing_auth" }, 401);
221
+ }
222
+ const aal = payload.aal || "aal1";
223
+ if (aal !== "aal2") {
224
+ return c.json({
225
+ error: "MFA verification required",
226
+ code: "mfa_required",
227
+ currentAal: aal,
228
+ requiredAal: "aal2",
229
+ }, 403);
230
+ }
231
+ return next();
232
+ };
233
+ }
234
+ /**
235
+ * Optional auth middleware for Hono
236
+ *
237
+ * Attaches user info if token is present. When no token is provided,
238
+ * automatically fetches the tenant's anon key (default behavior).
239
+ *
240
+ * ## Token Handling (default, autoFetchAnon = true)
241
+ *
242
+ * | Token Type | Result |
243
+ * |---------------|-------------------------------------------------|
244
+ * | No token | ✅ Auto-fetches anon key, `user.role = "anon"` |
245
+ * | Invalid token | ✅ Falls back to anon key, `user.role = "anon"` |
246
+ * | Anon JWT | ✅ Continues, `user.role = "anon"` |
247
+ * | Auth JWT | ✅ Continues, `user.role = "authenticated"` |
248
+ * | Service JWT | ✅ Continues, `user.role = "service_role"` |
249
+ *
250
+ * ## Token Handling (autoFetchAnon = false)
251
+ *
252
+ * | Token Type | Result |
253
+ * |---------------|-------------------------------------------------|
254
+ * | No token | ✅ Continues, `user = undefined` |
255
+ * | Invalid token | ✅ Continues, `user = undefined` |
256
+ * | Anon JWT | ✅ Continues, `user.role = "anon"` |
257
+ * | Auth JWT | ✅ Continues, `user.role = "authenticated"` |
258
+ * | Service JWT | ✅ Continues, `user.role = "service_role"` |
259
+ *
260
+ * **Note:** Unlike `createStackAuthMiddleware`, this never returns 401.
261
+ * Invalid tokens fall back to anon (default) or are silently ignored.
262
+ *
263
+ * @example
264
+ * ```typescript
265
+ * import { optionalStackAuthMiddleware } from "@kaiz11/stack-client/auth/server";
266
+ *
267
+ * // Default: user is always set (auto-fetches anon if no token)
268
+ * app.use("*", optionalStackAuthMiddleware({
269
+ * baseUrl: "https://stack.zenku.app",
270
+ * tenantId: "acme-corp",
271
+ * }));
272
+ *
273
+ * // Disable auto-fetch: user may be undefined if no token
274
+ * app.use("*", optionalStackAuthMiddleware({
275
+ * baseUrl: "https://stack.zenku.app",
276
+ * tenantId: "acme-corp",
277
+ * autoFetchAnon: false,
278
+ * }));
279
+ *
280
+ * app.get("/api/feed", (c) => {
281
+ * const user = c.get("user") as AuthUser;
282
+ * if (user.role === "authenticated") {
283
+ * // Logged in user
284
+ * } else {
285
+ * // Anonymous access (anon token or auto-fetched)
286
+ * }
287
+ * });
288
+ * ```
289
+ */
290
+ export function optionalStackAuthMiddleware(config) {
291
+ const tenantId = config.tenantId ?? PLATFORM_TENANT_ID;
292
+ const keyGetter = createJWKS(config.baseUrl, tenantId);
293
+ const { baseUrl } = config;
294
+ const autoFetchAnon = config.autoFetchAnon ?? true;
295
+ return async (c, next) => {
296
+ const authHeader = c.req.raw.headers.get("authorization");
297
+ let token = extractBearerToken(authHeader);
298
+ // Auto-fetch anon key if no token and autoFetchAnon is enabled
299
+ if (!token && autoFetchAnon) {
300
+ try {
301
+ token = await fetchAnonKeyCached(baseUrl, tenantId);
302
+ }
303
+ catch {
304
+ // Failed to fetch anon key, continue without auth
305
+ }
306
+ }
307
+ if (token) {
308
+ try {
309
+ const payload = await verifyToken(token, keyGetter, config.options);
310
+ const user = {
311
+ id: payload.sub,
312
+ email: payload.email ?? null,
313
+ phone: payload.phone ?? null,
314
+ role: payload.role,
315
+ aal: payload.aal || "aal1",
316
+ appMetadata: payload.app_metadata ?? {},
317
+ userMetadata: payload.user_metadata ?? {},
318
+ };
319
+ c.set("user", user);
320
+ c.set("tokenPayload", payload);
321
+ c.set("accessToken", token);
322
+ }
323
+ catch {
324
+ // Invalid token - try to fall back to anon if autoFetchAnon
325
+ if (autoFetchAnon) {
326
+ try {
327
+ const anonToken = await fetchAnonKeyCached(baseUrl, tenantId);
328
+ const payload = await verifyToken(anonToken, keyGetter, config.options);
329
+ const user = {
330
+ id: payload.sub,
331
+ email: payload.email ?? null,
332
+ phone: payload.phone ?? null,
333
+ role: payload.role,
334
+ aal: payload.aal || "aal1",
335
+ appMetadata: payload.app_metadata ?? {},
336
+ userMetadata: payload.user_metadata ?? {},
337
+ };
338
+ c.set("user", user);
339
+ c.set("tokenPayload", payload);
340
+ c.set("accessToken", anonToken);
341
+ }
342
+ catch {
343
+ // Failed to use anon fallback, continue without auth
344
+ }
345
+ }
346
+ }
347
+ }
348
+ return next();
349
+ };
350
+ }
351
+ /**
352
+ * Optional auth middleware for Hono (advanced)
353
+ *
354
+ * Attaches user info if token is present, but doesn't require it.
355
+ * Use this when you need a custom JWKS key getter.
356
+ *
357
+ * ## Token Handling
358
+ *
359
+ * | Token Type | Result |
360
+ * |---------------|-------------------------------------------------|
361
+ * | No token | ✅ Continues, `user = undefined` |
362
+ * | Invalid token | ✅ Continues, `user = undefined` |
363
+ * | Anon JWT | ✅ Continues, `user.role = "anon"` |
364
+ * | Auth JWT | ✅ Continues, `user.role = "authenticated"` |
365
+ * | Service JWT | ✅ Continues, `user.role = "service_role"` |
366
+ *
367
+ * @example
368
+ * ```typescript
369
+ * import { optionalAuthMiddleware, createLocalJWKS } from "@kaiz11/stack-client/auth/server";
370
+ *
371
+ * // For testing with local keys
372
+ * const keyGetter = createLocalJWKS(testJWKS);
373
+ *
374
+ * app.use("*", optionalAuthMiddleware({ keyGetter }));
375
+ * ```
376
+ */
377
+ export function optionalAuthMiddleware(config) {
378
+ const { keyGetter, options } = config;
379
+ return async (c, next) => {
380
+ const authHeader = c.req.raw.headers.get("authorization");
381
+ const token = extractBearerToken(authHeader);
382
+ if (token) {
383
+ try {
384
+ const payload = await verifyToken(token, keyGetter, options);
385
+ const user = {
386
+ id: payload.sub,
387
+ email: payload.email ?? null,
388
+ phone: payload.phone ?? null,
389
+ role: payload.role,
390
+ aal: payload.aal || "aal1",
391
+ appMetadata: payload.app_metadata ?? {},
392
+ userMetadata: payload.user_metadata ?? {},
393
+ };
394
+ c.set("user", user);
395
+ c.set("tokenPayload", payload);
396
+ c.set("accessToken", token);
397
+ }
398
+ catch {
399
+ // Invalid token, continue without auth
400
+ }
401
+ }
402
+ return next();
403
+ };
404
+ }
405
+ //# sourceMappingURL=middleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../../src/auth/server/middleware.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,184 @@
1
+ import * as jose from "jose";
2
+ /**
3
+ * JWT payload structure from GoTrue
4
+ */
5
+ export interface TokenPayload {
6
+ /** User ID */
7
+ sub: string;
8
+ /** Email address */
9
+ email?: string;
10
+ /** Phone number */
11
+ phone?: string;
12
+ /** User role (authenticated, anon, service_role) */
13
+ role: string;
14
+ /** Audience */
15
+ aud?: string;
16
+ /** Expiration time (Unix timestamp) */
17
+ exp?: number;
18
+ /** Issued at (Unix timestamp) */
19
+ iat?: number;
20
+ /** Authenticator assurance level */
21
+ aal?: "aal1" | "aal2";
22
+ /** App metadata */
23
+ app_metadata?: {
24
+ provider?: string;
25
+ providers?: string[];
26
+ };
27
+ /** User metadata */
28
+ user_metadata?: Record<string, unknown>;
29
+ }
30
+ /**
31
+ * Verification options
32
+ */
33
+ export interface VerifyOptions {
34
+ /** Expected audience (optional) */
35
+ audience?: string;
36
+ /** Clock tolerance in seconds (default: 0) */
37
+ clockTolerance?: number;
38
+ /** Required role (optional) */
39
+ requiredRole?: string;
40
+ /** Required AAL level (optional) */
41
+ requiredAal?: "aal1" | "aal2";
42
+ }
43
+ /**
44
+ * Key getter function type (returned by createRemoteJWKS or createLocalJWKS)
45
+ */
46
+ export type JWKSKeyGetter = ReturnType<typeof jose.createRemoteJWKSet>;
47
+ /**
48
+ * Verification error
49
+ */
50
+ export declare class VerifyError extends Error {
51
+ readonly code: string;
52
+ readonly statusCode: number;
53
+ constructor(message: string, code: string, statusCode?: number);
54
+ static invalidToken(reason?: string): VerifyError;
55
+ static tokenExpired(): VerifyError;
56
+ static insufficientRole(required: string, actual: string): VerifyError;
57
+ static insufficientAal(required: string, actual: string): VerifyError;
58
+ static missingToken(): VerifyError;
59
+ }
60
+ /**
61
+ * Get the JWKS URL for a tenant
62
+ *
63
+ * @param baseUrl - The stack base URL (e.g., "https://stack.zenku.app")
64
+ * @param tenantId - The tenant identifier (default: "_platform")
65
+ * @returns The JWKS URL
66
+ *
67
+ * @example
68
+ * ```typescript
69
+ * getJWKSUrl("https://stack.zenku.app")
70
+ * // → "https://stack.zenku.app/auth/_platform/.well-known/jwks.json"
71
+ *
72
+ * getJWKSUrl("https://stack.zenku.app", "acme-corp")
73
+ * // → "https://stack.zenku.app/auth/acme-corp/.well-known/jwks.json"
74
+ * ```
75
+ */
76
+ export declare function getJWKSUrl(baseUrl: string, tenantId?: string): string;
77
+ /**
78
+ * Create a JWKS key getter
79
+ *
80
+ * Automatically constructs the JWKS URL from the base URL and optional tenant ID.
81
+ *
82
+ * @param baseUrl - The stack base URL (e.g., "https://stack.zenku.app")
83
+ * @param tenantId - The tenant identifier (default: "_platform")
84
+ * @returns A key getter function for use with verifyToken
85
+ *
86
+ * @example
87
+ * ```typescript
88
+ * import { createJWKS, verifyToken } from "@kaiz11/stack-client/auth/server";
89
+ *
90
+ * // Platform (default)
91
+ * const getKey = createJWKS("https://stack.zenku.app");
92
+ *
93
+ * // Tenant
94
+ * const getKey = createJWKS("https://stack.zenku.app", "acme-corp");
95
+ *
96
+ * const payload = await verifyToken(token, getKey);
97
+ * ```
98
+ */
99
+ export declare function createJWKS(baseUrl: string, tenantId?: string): JWKSKeyGetter;
100
+ /**
101
+ * Create a JWKS key getter from a URL
102
+ *
103
+ * Fetches and caches the JWKS from the GoTrue /.well-known/jwks.json endpoint.
104
+ * Uses jose's built-in caching and refresh logic.
105
+ *
106
+ * For most use cases, prefer `createPlatformJWKS` or `createTenantJWKS` which
107
+ * automatically construct the URL.
108
+ *
109
+ * @param jwksUrl - The JWKS endpoint URL
110
+ * @returns A key getter function for use with verifyToken
111
+ *
112
+ * @example
113
+ * ```typescript
114
+ * import { createRemoteJWKS, verifyToken } from "@kaiz11/stack-client/auth/server";
115
+ *
116
+ * const getKey = createRemoteJWKS("https://stack.zenku.app/auth/_platform/.well-known/jwks.json");
117
+ * const payload = await verifyToken(token, getKey);
118
+ * ```
119
+ */
120
+ export declare function createRemoteJWKS(jwksUrl: string): JWKSKeyGetter;
121
+ /**
122
+ * Create a JWKS key getter from a local JWKS object
123
+ *
124
+ * Useful for testing without making network requests.
125
+ *
126
+ * @param jwks - The JWKS object containing keys
127
+ * @returns A key getter function for use with verifyToken
128
+ *
129
+ * @example
130
+ * ```typescript
131
+ * import { createLocalJWKS, verifyToken } from "@kaiz11/stack-client/auth/server";
132
+ *
133
+ * const jwks = { keys: [{ kty: "EC", crv: "P-256", ... }] };
134
+ * const getKey = createLocalJWKS(jwks);
135
+ * const payload = await verifyToken(token, getKey);
136
+ * ```
137
+ */
138
+ export declare function createLocalJWKS(jwks: jose.JSONWebKeySet): JWKSKeyGetter;
139
+ /**
140
+ * Clear the JWKS cache (useful for testing or key rotation)
141
+ */
142
+ export declare function clearJWKSCache(): void;
143
+ /**
144
+ * Verify a JWT and extract the payload using ES256 (ECDSA P-256)
145
+ *
146
+ * @param token - The JWT access token to verify
147
+ * @param keyGetter - JWKS key getter (from createRemoteJWKS or createLocalJWKS)
148
+ * @param options - Optional verification options
149
+ * @returns The token payload if valid
150
+ * @throws VerifyError if the token is invalid or expired
151
+ *
152
+ * @example
153
+ * ```typescript
154
+ * import { createRemoteJWKS, verifyToken } from "@kaiz11/stack-client/auth/server";
155
+ *
156
+ * // Create key getter once (cached)
157
+ * const getKey = createRemoteJWKS(process.env.JWKS_URL!);
158
+ *
159
+ * // Verify tokens
160
+ * const payload = await verifyToken(token, getKey);
161
+ * console.log("User ID:", payload.sub);
162
+ * console.log("Email:", payload.email);
163
+ * console.log("Role:", payload.role);
164
+ * ```
165
+ */
166
+ export declare function verifyToken(token: string, keyGetter: JWKSKeyGetter, options?: VerifyOptions): Promise<TokenPayload>;
167
+ /**
168
+ * Extract bearer token from Authorization header
169
+ *
170
+ * @param authHeader - The Authorization header value
171
+ * @returns The token string or null if not a valid Bearer token
172
+ *
173
+ * @example
174
+ * ```typescript
175
+ * import { extractBearerToken } from "@kaiz11/stack-client/auth/server";
176
+ *
177
+ * const token = extractBearerToken(request.headers.get("Authorization"));
178
+ * if (token) {
179
+ * const payload = await verifyToken(token, secret);
180
+ * }
181
+ * ```
182
+ */
183
+ export declare function extractBearerToken(authHeader: string | null): string | null;
184
+ //# sourceMappingURL=verify.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../../src/auth/server/verify.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAG7B;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,cAAc;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,oBAAoB;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mBAAmB;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oDAAoD;IACpD,IAAI,EAAE,MAAM,CAAC;IACb,eAAe;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,uCAAuC;IACvC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,iCAAiC;IACjC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,oCAAoC;IACpC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,mBAAmB;IACnB,YAAY,CAAC,EAAE;QACb,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;KACtB,CAAC;IACF,oBAAoB;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACzC;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,mCAAmC;IACnC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8CAA8C;IAC9C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,+BAA+B;IAC/B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oCAAoC;IACpC,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CAC/B;AAED;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,UAAU,CAAC,OAAO,IAAI,CAAC,kBAAkB,CAAC,CAAC;AAEvE;;GAEG;AACH,qBAAa,WAAY,SAAQ,KAAK;aAGlB,IAAI,EAAE,MAAM;aACZ,UAAU,EAAE,MAAM;gBAFlC,OAAO,EAAE,MAAM,EACC,IAAI,EAAE,MAAM,EACZ,UAAU,GAAE,MAAY;IAM1C,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,WAAW;IAQjD,MAAM,CAAC,YAAY,IAAI,WAAW;IAIlC,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,WAAW;IAQtE,MAAM,CAAC,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,WAAW;IAQrE,MAAM,CAAC,YAAY,IAAI,WAAW;CAGnC;AAKD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,UAAU,CACxB,OAAO,EAAE,MAAM,EACf,QAAQ,GAAE,MAA2B,GACpC,MAAM,CAER;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,UAAU,CACxB,OAAO,EAAE,MAAM,EACf,QAAQ,GAAE,MAA2B,GACpC,aAAa,CAEf;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,aAAa,CAgB/D;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,IAAI,CAAC,aAAa,GAAG,aAAa,CAEvE;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI,IAAI,CAErC;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAsB,WAAW,CAC/B,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,aAAa,EACxB,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,YAAY,CAAC,CA6CvB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAK3E"}