@robelest/convex-auth 0.0.4-preview.22 → 0.0.4-preview.24

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 (314) hide show
  1. package/README.md +10 -11
  2. package/dist/authorization/index.d.ts +1 -1
  3. package/dist/authorization/index.js +1 -1
  4. package/dist/authorization/index.js.map +1 -1
  5. package/dist/client/index.d.ts +1 -2
  6. package/dist/client/index.d.ts.map +1 -1
  7. package/dist/client/index.js +36 -39
  8. package/dist/client/index.js.map +1 -1
  9. package/dist/component/client/index.d.ts +1 -2
  10. package/dist/component/index.js +2 -2
  11. package/dist/component/model.d.ts +9 -9
  12. package/dist/component/model.d.ts.map +1 -1
  13. package/dist/component/public/enterprise/audit.d.ts.map +1 -1
  14. package/dist/component/public/enterprise/audit.js.map +1 -1
  15. package/dist/component/public/enterprise/core.d.ts.map +1 -1
  16. package/dist/component/public/enterprise/core.js.map +1 -1
  17. package/dist/component/public/enterprise/domains.d.ts.map +1 -1
  18. package/dist/component/public/enterprise/domains.js.map +1 -1
  19. package/dist/component/public/enterprise/scim.d.ts.map +1 -1
  20. package/dist/component/public/enterprise/scim.js.map +1 -1
  21. package/dist/component/public/enterprise/secrets.d.ts.map +1 -1
  22. package/dist/component/public/enterprise/secrets.js.map +1 -1
  23. package/dist/component/public/enterprise/webhooks.d.ts.map +1 -1
  24. package/dist/component/public/enterprise/webhooks.js.map +1 -1
  25. package/dist/component/public/factors/devices.d.ts.map +1 -1
  26. package/dist/component/public/factors/devices.js.map +1 -1
  27. package/dist/component/public/factors/passkeys.d.ts.map +1 -1
  28. package/dist/component/public/factors/passkeys.js.map +1 -1
  29. package/dist/component/public/factors/totp.d.ts.map +1 -1
  30. package/dist/component/public/factors/totp.js.map +1 -1
  31. package/dist/component/public/groups/core.js.map +1 -1
  32. package/dist/component/public/groups/invites.d.ts.map +1 -1
  33. package/dist/component/public/groups/invites.js.map +1 -1
  34. package/dist/component/public/groups/members.d.ts.map +1 -1
  35. package/dist/component/public/groups/members.js.map +1 -1
  36. package/dist/component/public/identity/accounts.d.ts.map +1 -1
  37. package/dist/component/public/identity/accounts.js.map +1 -1
  38. package/dist/component/public/identity/codes.d.ts.map +1 -1
  39. package/dist/component/public/identity/codes.js.map +1 -1
  40. package/dist/component/public/identity/sessions.d.ts.map +1 -1
  41. package/dist/component/public/identity/sessions.js.map +1 -1
  42. package/dist/component/public/identity/tokens.d.ts.map +1 -1
  43. package/dist/component/public/identity/tokens.js.map +1 -1
  44. package/dist/component/public/identity/users.d.ts.map +1 -1
  45. package/dist/component/public/identity/users.js.map +1 -1
  46. package/dist/component/public/identity/verifiers.d.ts.map +1 -1
  47. package/dist/component/public/identity/verifiers.js.map +1 -1
  48. package/dist/component/public/security/keys.d.ts.map +1 -1
  49. package/dist/component/public/security/keys.js.map +1 -1
  50. package/dist/component/public/security/limits.d.ts.map +1 -1
  51. package/dist/component/public/security/limits.js.map +1 -1
  52. package/dist/component/schema.d.ts +41 -41
  53. package/dist/component/server/auth.d.ts +127 -130
  54. package/dist/component/server/auth.d.ts.map +1 -1
  55. package/dist/component/server/auth.js +100 -64
  56. package/dist/component/server/auth.js.map +1 -1
  57. package/dist/component/server/context.js +53 -0
  58. package/dist/component/server/context.js.map +1 -0
  59. package/dist/component/server/core.js +113 -250
  60. package/dist/component/server/core.js.map +1 -1
  61. package/dist/component/server/crypto.js +25 -7
  62. package/dist/component/server/crypto.js.map +1 -1
  63. package/dist/component/server/device.js +59 -16
  64. package/dist/component/server/device.js.map +1 -1
  65. package/dist/component/server/enterprise/domain.js +148 -59
  66. package/dist/component/server/enterprise/domain.js.map +1 -1
  67. package/dist/component/server/enterprise/http.js +36 -15
  68. package/dist/component/server/enterprise/http.js.map +1 -1
  69. package/dist/component/server/enterprise/oidc.js +1 -1
  70. package/dist/component/server/http.d.ts +85 -0
  71. package/dist/component/server/http.d.ts.map +1 -0
  72. package/dist/component/server/http.js +85 -22
  73. package/dist/component/server/http.js.map +1 -1
  74. package/dist/component/server/identity.js +5 -2
  75. package/dist/component/server/identity.js.map +1 -1
  76. package/dist/component/server/limits.js +21 -30
  77. package/dist/component/server/limits.js.map +1 -1
  78. package/dist/component/server/mutations/account.js +12 -10
  79. package/dist/component/server/mutations/account.js.map +1 -1
  80. package/dist/component/server/mutations/code.js +5 -2
  81. package/dist/component/server/mutations/code.js.map +1 -1
  82. package/dist/component/server/mutations/invalidate.js +1 -1
  83. package/dist/component/server/mutations/invalidate.js.map +1 -1
  84. package/dist/component/server/mutations/oauth.js +10 -4
  85. package/dist/component/server/mutations/oauth.js.map +1 -1
  86. package/dist/component/server/mutations/refresh.js +2 -2
  87. package/dist/component/server/mutations/refresh.js.map +1 -1
  88. package/dist/component/server/mutations/register.js +46 -42
  89. package/dist/component/server/mutations/register.js.map +1 -1
  90. package/dist/component/server/mutations/retrieve.js +21 -25
  91. package/dist/component/server/mutations/retrieve.js.map +1 -1
  92. package/dist/component/server/mutations/signature.js +10 -4
  93. package/dist/component/server/mutations/signature.js.map +1 -1
  94. package/dist/component/server/mutations/signout.js.map +1 -1
  95. package/dist/component/server/mutations/store.js +9 -24
  96. package/dist/component/server/mutations/store.js.map +1 -1
  97. package/dist/component/server/mutations/verifier.js.map +1 -1
  98. package/dist/component/server/mutations/verify.js +1 -1
  99. package/dist/component/server/mutations/verify.js.map +1 -1
  100. package/dist/component/server/oauth.js +53 -16
  101. package/dist/component/server/oauth.js.map +1 -1
  102. package/dist/component/server/passkey.js +115 -31
  103. package/dist/component/server/passkey.js.map +1 -1
  104. package/dist/component/server/redirects.js +9 -3
  105. package/dist/component/server/redirects.js.map +1 -1
  106. package/dist/component/server/refresh.js +10 -7
  107. package/dist/component/server/refresh.js.map +1 -1
  108. package/dist/component/server/runtime.d.ts +5 -5
  109. package/dist/component/server/runtime.js +156 -113
  110. package/dist/component/server/runtime.js.map +1 -1
  111. package/dist/component/server/signin.js +34 -10
  112. package/dist/component/server/signin.js.map +1 -1
  113. package/dist/component/server/totp.js +79 -19
  114. package/dist/component/server/totp.js.map +1 -1
  115. package/dist/component/server/types.d.ts +12 -20
  116. package/dist/component/server/types.d.ts.map +1 -1
  117. package/dist/component/server/types.js.map +1 -1
  118. package/dist/component/server/users.js +6 -3
  119. package/dist/component/server/users.js.map +1 -1
  120. package/dist/component/server/utils.js +10 -4
  121. package/dist/component/server/utils.js.map +1 -1
  122. package/dist/core/types.d.ts +14 -22
  123. package/dist/core/types.d.ts.map +1 -1
  124. package/dist/factors/device.js +8 -9
  125. package/dist/factors/device.js.map +1 -1
  126. package/dist/factors/passkey.js +18 -21
  127. package/dist/factors/passkey.js.map +1 -1
  128. package/dist/providers/password.js +66 -81
  129. package/dist/providers/password.js.map +1 -1
  130. package/dist/runtime/invite.js +2 -8
  131. package/dist/runtime/invite.js.map +1 -1
  132. package/dist/server/auth.d.ts +127 -130
  133. package/dist/server/auth.d.ts.map +1 -1
  134. package/dist/server/auth.js +100 -64
  135. package/dist/server/auth.js.map +1 -1
  136. package/dist/server/context.d.ts +1 -0
  137. package/dist/server/context.js +53 -0
  138. package/dist/server/context.js.map +1 -0
  139. package/dist/server/core.d.ts +74 -195
  140. package/dist/server/core.d.ts.map +1 -1
  141. package/dist/server/core.js +113 -250
  142. package/dist/server/core.js.map +1 -1
  143. package/dist/server/crypto.d.ts.map +1 -1
  144. package/dist/server/crypto.js +25 -7
  145. package/dist/server/crypto.js.map +1 -1
  146. package/dist/server/device.js +59 -16
  147. package/dist/server/device.js.map +1 -1
  148. package/dist/server/enterprise/domain.d.ts +0 -8
  149. package/dist/server/enterprise/domain.d.ts.map +1 -1
  150. package/dist/server/enterprise/domain.js +148 -59
  151. package/dist/server/enterprise/domain.js.map +1 -1
  152. package/dist/server/enterprise/http.d.ts.map +1 -1
  153. package/dist/server/enterprise/http.js +35 -14
  154. package/dist/server/enterprise/http.js.map +1 -1
  155. package/dist/server/http.d.ts +81 -3
  156. package/dist/server/http.d.ts.map +1 -1
  157. package/dist/server/http.js +84 -21
  158. package/dist/server/http.js.map +1 -1
  159. package/dist/server/identity.js +5 -2
  160. package/dist/server/identity.js.map +1 -1
  161. package/dist/server/index.d.ts +3 -2
  162. package/dist/server/index.js +2 -2
  163. package/dist/server/limits.js +21 -30
  164. package/dist/server/limits.js.map +1 -1
  165. package/dist/server/mounts.d.ts +25 -63
  166. package/dist/server/mounts.d.ts.map +1 -1
  167. package/dist/server/mounts.js +46 -107
  168. package/dist/server/mounts.js.map +1 -1
  169. package/dist/server/mutations/account.d.ts +8 -9
  170. package/dist/server/mutations/account.d.ts.map +1 -1
  171. package/dist/server/mutations/account.js +11 -9
  172. package/dist/server/mutations/account.js.map +1 -1
  173. package/dist/server/mutations/code.d.ts +12 -12
  174. package/dist/server/mutations/code.d.ts.map +1 -1
  175. package/dist/server/mutations/code.js +5 -2
  176. package/dist/server/mutations/code.js.map +1 -1
  177. package/dist/server/mutations/invalidate.d.ts +4 -4
  178. package/dist/server/mutations/invalidate.d.ts.map +1 -1
  179. package/dist/server/mutations/invalidate.js.map +1 -1
  180. package/dist/server/mutations/oauth.d.ts +14 -12
  181. package/dist/server/mutations/oauth.d.ts.map +1 -1
  182. package/dist/server/mutations/oauth.js +9 -3
  183. package/dist/server/mutations/oauth.js.map +1 -1
  184. package/dist/server/mutations/refresh.d.ts +3 -3
  185. package/dist/server/mutations/refresh.d.ts.map +1 -1
  186. package/dist/server/mutations/refresh.js +1 -1
  187. package/dist/server/mutations/refresh.js.map +1 -1
  188. package/dist/server/mutations/register.d.ts +11 -11
  189. package/dist/server/mutations/register.d.ts.map +1 -1
  190. package/dist/server/mutations/register.js +45 -41
  191. package/dist/server/mutations/register.js.map +1 -1
  192. package/dist/server/mutations/retrieve.d.ts +6 -6
  193. package/dist/server/mutations/retrieve.d.ts.map +1 -1
  194. package/dist/server/mutations/retrieve.js +20 -24
  195. package/dist/server/mutations/retrieve.js.map +1 -1
  196. package/dist/server/mutations/signature.d.ts +6 -7
  197. package/dist/server/mutations/signature.d.ts.map +1 -1
  198. package/dist/server/mutations/signature.js +9 -3
  199. package/dist/server/mutations/signature.js.map +1 -1
  200. package/dist/server/mutations/signin.d.ts +5 -5
  201. package/dist/server/mutations/signout.js.map +1 -1
  202. package/dist/server/mutations/store.d.ts +83 -83
  203. package/dist/server/mutations/store.js +8 -23
  204. package/dist/server/mutations/store.js.map +1 -1
  205. package/dist/server/mutations/verifier.js.map +1 -1
  206. package/dist/server/mutations/verify.d.ts +7 -7
  207. package/dist/server/mutations/verify.d.ts.map +1 -1
  208. package/dist/server/mutations/verify.js.map +1 -1
  209. package/dist/server/oauth.js +53 -16
  210. package/dist/server/oauth.js.map +1 -1
  211. package/dist/server/passkey.d.ts +2 -2
  212. package/dist/server/passkey.d.ts.map +1 -1
  213. package/dist/server/passkey.js +114 -30
  214. package/dist/server/passkey.js.map +1 -1
  215. package/dist/server/redirects.js +9 -3
  216. package/dist/server/redirects.js.map +1 -1
  217. package/dist/server/refresh.js +10 -7
  218. package/dist/server/refresh.js.map +1 -1
  219. package/dist/server/runtime.d.ts +11 -11
  220. package/dist/server/runtime.js +155 -112
  221. package/dist/server/runtime.js.map +1 -1
  222. package/dist/server/signin.js +34 -10
  223. package/dist/server/signin.js.map +1 -1
  224. package/dist/server/ssr.d.ts.map +1 -1
  225. package/dist/server/ssr.js +175 -184
  226. package/dist/server/ssr.js.map +1 -1
  227. package/dist/server/totp.js +78 -18
  228. package/dist/server/totp.js.map +1 -1
  229. package/dist/server/types.d.ts +13 -21
  230. package/dist/server/types.d.ts.map +1 -1
  231. package/dist/server/types.js.map +1 -1
  232. package/dist/server/users.js +6 -3
  233. package/dist/server/users.js.map +1 -1
  234. package/dist/server/utils.js +10 -4
  235. package/dist/server/utils.js.map +1 -1
  236. package/package.json +1 -5
  237. package/src/authorization/index.ts +1 -1
  238. package/src/client/core/types.ts +14 -14
  239. package/src/client/factors/device.ts +10 -12
  240. package/src/client/factors/passkey.ts +23 -26
  241. package/src/client/index.ts +54 -64
  242. package/src/client/runtime/invite.ts +5 -7
  243. package/src/component/index.ts +9 -3
  244. package/src/component/public/enterprise/audit.ts +6 -1
  245. package/src/component/public/enterprise/core.ts +1 -0
  246. package/src/component/public/enterprise/domains.ts +5 -1
  247. package/src/component/public/enterprise/scim.ts +1 -0
  248. package/src/component/public/enterprise/secrets.ts +1 -0
  249. package/src/component/public/enterprise/webhooks.ts +1 -0
  250. package/src/component/public/factors/devices.ts +1 -0
  251. package/src/component/public/factors/passkeys.ts +1 -0
  252. package/src/component/public/factors/totp.ts +1 -0
  253. package/src/component/public/groups/core.ts +1 -1
  254. package/src/component/public/groups/invites.ts +7 -1
  255. package/src/component/public/groups/members.ts +1 -0
  256. package/src/component/public/identity/accounts.ts +1 -0
  257. package/src/component/public/identity/codes.ts +1 -0
  258. package/src/component/public/identity/sessions.ts +1 -0
  259. package/src/component/public/identity/tokens.ts +1 -0
  260. package/src/component/public/identity/users.ts +1 -0
  261. package/src/component/public/identity/verifiers.ts +1 -0
  262. package/src/component/public/security/keys.ts +1 -0
  263. package/src/component/public/security/limits.ts +1 -0
  264. package/src/providers/password.ts +89 -110
  265. package/src/server/auth.ts +240 -182
  266. package/src/server/context.ts +90 -0
  267. package/src/server/core.ts +195 -286
  268. package/src/server/crypto.ts +31 -29
  269. package/src/server/device.ts +65 -32
  270. package/src/server/enterprise/domain.ts +158 -170
  271. package/src/server/enterprise/http.ts +46 -39
  272. package/src/server/http.ts +289 -30
  273. package/src/server/identity.ts +5 -5
  274. package/src/server/index.ts +9 -3
  275. package/src/server/limits.ts +53 -80
  276. package/src/server/mounts.ts +56 -80
  277. package/src/server/mutations/account.ts +22 -36
  278. package/src/server/mutations/code.ts +6 -6
  279. package/src/server/mutations/invalidate.ts +1 -1
  280. package/src/server/mutations/oauth.ts +14 -8
  281. package/src/server/mutations/refresh.ts +5 -4
  282. package/src/server/mutations/register.ts +87 -132
  283. package/src/server/mutations/retrieve.ts +44 -44
  284. package/src/server/mutations/signature.ts +13 -6
  285. package/src/server/mutations/signout.ts +1 -1
  286. package/src/server/mutations/store.ts +16 -31
  287. package/src/server/mutations/verifier.ts +1 -1
  288. package/src/server/mutations/verify.ts +3 -5
  289. package/src/server/oauth.ts +60 -69
  290. package/src/server/passkey.ts +567 -517
  291. package/src/server/redirects.ts +10 -6
  292. package/src/server/refresh.ts +14 -18
  293. package/src/server/runtime.ts +340 -302
  294. package/src/server/signin.ts +44 -37
  295. package/src/server/ssr.ts +390 -407
  296. package/src/server/totp.ts +85 -35
  297. package/src/server/types.ts +19 -22
  298. package/src/server/users.ts +7 -6
  299. package/src/server/utils.ts +10 -12
  300. package/dist/component/server/authError.js +0 -34
  301. package/dist/component/server/authError.js.map +0 -1
  302. package/dist/component/server/errors.d.ts +0 -1
  303. package/dist/component/server/errors.js +0 -137
  304. package/dist/component/server/errors.js.map +0 -1
  305. package/dist/server/authError.d.ts +0 -46
  306. package/dist/server/authError.d.ts.map +0 -1
  307. package/dist/server/authError.js +0 -34
  308. package/dist/server/authError.js.map +0 -1
  309. package/dist/server/errors.d.ts +0 -177
  310. package/dist/server/errors.d.ts.map +0 -1
  311. package/dist/server/errors.js +0 -212
  312. package/dist/server/errors.js.map +0 -1
  313. package/src/server/authError.ts +0 -44
  314. package/src/server/errors.ts +0 -290
@@ -1,5 +1,6 @@
1
+ import { Fx } from "@robelest/fx";
2
+ import { Cv } from "@robelest/fx/convex";
1
3
  import {
2
- Auth,
3
4
  GenericActionCtx,
4
5
  GenericDataModel,
5
6
  HttpRouter,
@@ -9,10 +10,10 @@ import {
9
10
  import { v } from "convex/values";
10
11
  import { serialize as serializeCookie } from "cookie";
11
12
 
12
- import { createCoreDomains } from "./core";
13
+ import { configDefaults, listAvailableProviders } from "./config";
13
14
  import { redirectToParamCookie, useRedirectToParam } from "./cookies";
14
- import { createEnterpriseDomain } from "./enterprise/domain";
15
- import { addEnterpriseHttpRuntime } from "./enterprise/http";
15
+ import { createCoreDomains } from "./core";
16
+ import { GetProviderOrThrowFunc } from "./crypto";
16
17
  import {
17
18
  getOidcConfig,
18
19
  getPublicOidcConfig,
@@ -20,29 +21,30 @@ import {
20
21
  upsertProtocolConfig,
21
22
  withOidcSecretState,
22
23
  } from "./enterprise/config";
23
- import { normalizeEnterprisePolicy, patchEnterprisePolicy } from "./enterprise/policy";
24
+ import { createEnterpriseDomain } from "./enterprise/domain";
25
+ import { addEnterpriseHttpRuntime } from "./enterprise/http";
26
+ import {
27
+ normalizeEnterprisePolicy,
28
+ patchEnterprisePolicy,
29
+ } from "./enterprise/policy";
24
30
  import {
25
31
  createServiceProviderMetadata,
26
32
  getSamlServiceProviderOptions,
27
33
  parseSamlIdpMetadata,
28
34
  } from "./enterprise/saml";
29
- import {
30
- parseScimPath,
31
- } from "./enterprise/scim";
35
+ import { parseScimPath } from "./enterprise/scim";
32
36
  import {
33
37
  enterpriseOidcProviderId,
34
38
  getEnterpriseOidcUrls,
35
39
  isEnterpriseSamlSourceActive,
36
40
  normalizeDomain,
37
41
  } from "./enterprise/shared";
38
- import { Fx } from "@robelest/fx";
39
-
40
- import { AuthError } from "./authError";
41
42
  import {
42
43
  addAuthRoutes,
43
44
  addOpenIdRoutes,
44
45
  convertErrorsToResponse,
45
46
  createHttpAction,
47
+ createHttpContext,
46
48
  createHttpRoute,
47
49
  getCookies,
48
50
  } from "./http";
@@ -58,8 +60,6 @@ import {
58
60
  storeImpl,
59
61
  } from "./mutations/index";
60
62
  import { createOAuthAuthorizationURL, handleOAuthCallback } from "./oauth";
61
- import { GetProviderOrThrowFunc } from "./crypto";
62
- import { configDefaults, listAvailableProviders } from "./config";
63
63
  import { redirectAbsoluteUrl, setURLSearchParam } from "./redirects";
64
64
  import { signInImpl } from "./signin";
65
65
  import type {
@@ -171,9 +171,11 @@ export function Auth(config_: ConvexAuthConfig) {
171
171
  `Provider \`${id}\` is not configured, ` +
172
172
  `available providers are ${listAvailableProviders(config, allowExtraProviders)}.`;
173
173
  logWithLevel(LOG_LEVELS.ERROR, detail);
174
- throw new AuthError("PROVIDER_NOT_CONFIGURED", detail, {
174
+ throw Cv.error({
175
+ code: "PROVIDER_NOT_CONFIGURED",
176
+ message: detail,
175
177
  provider: id,
176
- }).toConvexError();
178
+ });
177
179
  }
178
180
  return provider;
179
181
  };
@@ -231,10 +233,10 @@ export function Auth(config_: ConvexAuthConfig) {
231
233
  },
232
234
  );
233
235
  if (!enterprise) {
234
- throw new AuthError(
235
- "INVALID_PARAMETERS",
236
- enterpriseNotFoundError,
237
- ).toConvexError();
236
+ throw Cv.error({
237
+ code: "INVALID_PARAMETERS",
238
+ message: enterpriseNotFoundError,
239
+ });
238
240
  }
239
241
  return enterprise;
240
242
  };
@@ -245,10 +247,10 @@ export function Auth(config_: ConvexAuthConfig) {
245
247
  ) => {
246
248
  const enterprise = await loadEnterpriseOrThrow(ctx, enterpriseId);
247
249
  if (enterprise.status !== "active") {
248
- throw new AuthError(
249
- "INVALID_PARAMETERS",
250
- "Enterprise connection is not active.",
251
- ).toConvexError();
250
+ throw Cv.error({
251
+ code: "INVALID_PARAMETERS",
252
+ message: "Enterprise connection is not active.",
253
+ });
252
254
  }
253
255
  return enterprise;
254
256
  };
@@ -268,17 +270,17 @@ export function Auth(config_: ConvexAuthConfig) {
268
270
  enterprise,
269
271
  };
270
272
  if (!isEnterpriseSamlSourceActive(loaded)) {
271
- throw new AuthError(
272
- "INVALID_PARAMETERS",
273
- "Enterprise connection is not active.",
274
- ).toConvexError();
273
+ throw Cv.error({
274
+ code: "INVALID_PARAMETERS",
275
+ message: "Enterprise connection is not active.",
276
+ });
275
277
  }
276
278
  const saml = getSamlConfig(loaded.config);
277
279
  if (!saml.idp?.metadataXml) {
278
- throw new AuthError(
279
- "PROVIDER_NOT_CONFIGURED",
280
- "SAML is not configured for this enterprise.",
281
- ).toConvexError();
280
+ throw Cv.error({
281
+ code: "PROVIDER_NOT_CONFIGURED",
282
+ message: "SAML is not configured for this enterprise.",
283
+ });
282
284
  }
283
285
  return { loaded, enterprise, saml };
284
286
  };
@@ -290,10 +292,10 @@ export function Auth(config_: ConvexAuthConfig) {
290
292
  const enterprise = await loadActiveEnterpriseOrThrow(ctx, enterpriseId);
291
293
  const oidc = await getEnterpriseOidcConfigWithSecret(ctx, enterprise);
292
294
  if (oidc.enabled !== true) {
293
- throw new AuthError(
294
- "PROVIDER_NOT_CONFIGURED",
295
- "OIDC is not configured for this enterprise.",
296
- ).toConvexError();
295
+ throw Cv.error({
296
+ code: "PROVIDER_NOT_CONFIGURED",
297
+ message: "OIDC is not configured for this enterprise.",
298
+ });
297
299
  }
298
300
  return { enterprise, oidc };
299
301
  };
@@ -407,7 +409,10 @@ export function Auth(config_: ConvexAuthConfig) {
407
409
  ) => {
408
410
  const authHeader = request.headers.get("Authorization");
409
411
  if (!authHeader?.startsWith("Bearer ")) {
410
- throw new AuthError("MISSING_BEARER_TOKEN").toConvexError();
412
+ throw Cv.error({
413
+ code: "MISSING_BEARER_TOKEN",
414
+ message: "Missing or malformed Authorization: Bearer header.",
415
+ });
411
416
  }
412
417
  const token = authHeader.slice(7);
413
418
  const scimConfig = await ctx.runQuery(
@@ -415,17 +420,17 @@ export function Auth(config_: ConvexAuthConfig) {
415
420
  { tokenHash: await sha256(token) },
416
421
  );
417
422
  if (!scimConfig || scimConfig.status !== "active") {
418
- throw new AuthError(
419
- "INVALID_API_KEY",
420
- "Invalid SCIM token.",
421
- ).toConvexError();
423
+ throw Cv.error({
424
+ code: "INVALID_API_KEY",
425
+ message: "Invalid SCIM token.",
426
+ });
422
427
  }
423
428
  const parsedPath = parseScimPath(new URL(request.url).pathname);
424
429
  if (parsedPath.enterpriseId !== scimConfig.enterpriseId) {
425
- throw new AuthError(
426
- "INVALID_API_KEY",
427
- "SCIM token/tenant mismatch.",
428
- ).toConvexError();
430
+ throw Cv.error({
431
+ code: "INVALID_API_KEY",
432
+ message: "SCIM token/tenant mismatch.",
433
+ });
429
434
  }
430
435
  const enterprise = await ctx.runQuery(
431
436
  config.component.public.enterpriseGet,
@@ -434,10 +439,10 @@ export function Auth(config_: ConvexAuthConfig) {
434
439
  },
435
440
  );
436
441
  if (enterprise === null) {
437
- throw new AuthError(
438
- "INVALID_PARAMETERS",
439
- "Enterprise not found.",
440
- ).toConvexError();
442
+ throw Cv.error({
443
+ code: "INVALID_PARAMETERS",
444
+ message: "Enterprise not found.",
445
+ });
441
446
  }
442
447
  return { scimConfig, enterprise, parsedPath };
443
448
  };
@@ -488,272 +493,305 @@ export function Auth(config_: ConvexAuthConfig) {
488
493
  getPolicyFromEnterprise,
489
494
  patchEnterprisePolicy,
490
495
  }),
491
- // HTTP wiring stays local to the factory because it still depends on a
492
- // dense mix of OAuth, SAML, SCIM, cookie, and response helpers.
493
- http: {
494
- /**
495
- * Register core HTTP routes for JWT verification and OAuth sign-in.
496
- *
497
- * ```ts
498
- * import { httpRouter } from "convex/server";
499
- * import { auth } from "./auth";
500
- *
501
- * const http = httpRouter();
502
- *
503
- * auth.http.add(http);
504
- *
505
- * export default http;
506
- * ```
507
- *
508
- * The following routes are handled always:
509
- *
510
- * - `/.well-known/openid-configuration`
511
- * - `/.well-known/jwks.json`
512
- *
513
- * The following routes are handled if OAuth is configured:
514
- *
515
- * - `/api/auth/signin/*`
516
- * - `/api/auth/callback/*`
517
- *
518
- * @param http your HTTP router
519
- */
520
- add: (http: HttpRouter) => {
521
- addOpenIdRoutes(http, {
522
- getIssuer: () => requireEnv("CONVEX_SITE_URL"),
523
- getJwks: () => requireEnv("JWKS"),
524
- });
525
-
526
- addEnterpriseHttpRuntime({
527
- http,
528
- hasSSO,
529
- auth,
530
- config,
531
- routeBase: ENTERPRISE_CONTROL_ROUTE_BASE,
532
- requireEnv,
533
- loadActiveEnterpriseSamlOrThrow,
534
- loadEnterpriseOidcOrThrow,
535
- getEnterpriseScimContext,
536
- getPolicyFromEnterprise,
537
- normalizeEnterprisePolicy,
538
- recordEnterpriseAuditEvent,
539
- emitEnterpriseWebhookDeliveries,
540
- generateRandomString,
541
- inviteTokenAlphabet: INVITE_TOKEN_ALPHABET,
542
- callUserOAuth,
543
- callVerifierSignature,
544
- });
496
+ };
545
497
 
546
- if (hasOAuth) {
547
- addAuthRoutes(http, {
548
- handleSignIn: convertErrorsToResponse(400, async (ctx, request) => {
549
- const url = new URL(request.url);
550
- const pathParts = url.pathname.split("/");
551
- const providerId = pathParts.at(-1)!;
552
- if (providerId === null) {
553
- throw new AuthError("OAUTH_MISSING_PROVIDER").toConvexError();
554
- }
555
- const verifier = url.searchParams.get("code");
556
- if (verifier === null) {
557
- throw new AuthError("OAUTH_MISSING_VERIFIER").toConvexError();
558
- }
559
- const provider = getProviderOrThrow(providerId);
560
-
561
- const oauthConfig = provider as OAuthMaterializedConfig;
562
- const { redirect, cookies, signature } =
563
- await createOAuthAuthorizationURL(
564
- providerId,
565
- oauthConfig.provider,
566
- oauthConfig,
567
- );
568
-
569
- await callVerifierSignature(ctx, {
570
- verifier,
571
- signature,
498
+ // HTTP wiring stays local to the factory because it still depends on a
499
+ // dense mix of OAuth, SAML, SCIM, cookie, and response helpers.
500
+ auth.http = {
501
+ /**
502
+ * Register core HTTP routes for JWT verification and OAuth sign-in.
503
+ *
504
+ * ```ts
505
+ * import { httpRouter } from "convex/server";
506
+ * import { auth } from "./auth";
507
+ *
508
+ * const http = httpRouter();
509
+ *
510
+ * auth.http.add(http);
511
+ *
512
+ * export default http;
513
+ * ```
514
+ *
515
+ * The following routes are handled always:
516
+ *
517
+ * - `/.well-known/openid-configuration`
518
+ * - `/.well-known/jwks.json`
519
+ *
520
+ * The following routes are handled if OAuth is configured:
521
+ *
522
+ * - `/api/auth/signin/*`
523
+ * - `/api/auth/callback/*`
524
+ *
525
+ * @param http your HTTP router
526
+ */
527
+ add: (http: HttpRouter) => {
528
+ addOpenIdRoutes(http, {
529
+ getIssuer: () => requireEnv("CONVEX_SITE_URL"),
530
+ getJwks: () => requireEnv("JWKS"),
531
+ });
532
+
533
+ addEnterpriseHttpRuntime({
534
+ http,
535
+ hasSSO,
536
+ auth,
537
+ config,
538
+ routeBase: ENTERPRISE_CONTROL_ROUTE_BASE,
539
+ requireEnv,
540
+ loadActiveEnterpriseSamlOrThrow,
541
+ loadEnterpriseOidcOrThrow,
542
+ getEnterpriseScimContext,
543
+ getPolicyFromEnterprise,
544
+ normalizeEnterprisePolicy,
545
+ recordEnterpriseAuditEvent,
546
+ emitEnterpriseWebhookDeliveries,
547
+ generateRandomString,
548
+ inviteTokenAlphabet: INVITE_TOKEN_ALPHABET,
549
+ callUserOAuth,
550
+ callVerifierSignature,
551
+ });
552
+
553
+ if (hasOAuth) {
554
+ addAuthRoutes(http, {
555
+ handleSignIn: convertErrorsToResponse(400, async (ctx, request) => {
556
+ const url = new URL(request.url);
557
+ const pathParts = url.pathname.split("/");
558
+ const providerId = pathParts[pathParts.length - 1]!;
559
+ if (providerId === null) {
560
+ throw Cv.error({
561
+ code: "OAUTH_MISSING_PROVIDER",
562
+ message: "Missing OAuth provider ID.",
572
563
  });
564
+ }
565
+ const verifier = url.searchParams.get("code");
566
+ if (verifier === null) {
567
+ throw Cv.error({
568
+ code: "OAUTH_MISSING_VERIFIER",
569
+ message: "Missing sign-in verifier.",
570
+ });
571
+ }
572
+ const provider = getProviderOrThrow(providerId);
573
573
 
574
- const redirectTo = url.searchParams.get("redirectTo");
575
- if (redirectTo !== null) {
576
- cookies.push(redirectToParamCookie(providerId, redirectTo));
577
- }
578
-
579
- const headers = new Headers({ Location: redirect });
580
- for (const { name, value, options } of cookies) {
581
- headers.append(
582
- "Set-Cookie",
583
- serializeCookie(name, value, options as any),
584
- );
585
- }
586
-
587
- return new Response(null, { status: 302, headers });
588
- }),
589
- handleCallback: async (ctx, request) => {
590
- const url = new URL(request.url);
591
- const providerId = new URL(request.url).pathname
592
- .split("/")
593
- .at(-1);
594
- if (!providerId) {
595
- throw new AuthError("OAUTH_MISSING_PROVIDER").toConvexError();
596
- }
597
- logWithLevel(
598
- LOG_LEVELS.DEBUG,
599
- "Handling OAuth callback for provider:",
574
+ const oauthConfig = provider as OAuthMaterializedConfig;
575
+ const { redirect, cookies, signature } =
576
+ await createOAuthAuthorizationURL(
600
577
  providerId,
578
+ oauthConfig.provider,
579
+ oauthConfig,
601
580
  );
602
- const provider = getProviderOrThrow(providerId);
603
-
604
- const cookies = getCookies(request);
605
581
 
606
- const maybeRedirectTo = useRedirectToParam(provider.id, cookies);
582
+ await callVerifierSignature(ctx, {
583
+ verifier,
584
+ signature,
585
+ });
586
+
587
+ const redirectTo = url.searchParams.get("redirectTo");
588
+ if (redirectTo !== null) {
589
+ cookies.push(redirectToParamCookie(providerId, redirectTo));
590
+ }
591
+
592
+ const headers = new Headers({ Location: redirect });
593
+ for (const { name, value, options } of cookies) {
594
+ headers.append(
595
+ "Set-Cookie",
596
+ serializeCookie(name, value, options as any),
597
+ );
598
+ }
607
599
 
608
- const destinationUrl = await redirectAbsoluteUrl(config, {
609
- redirectTo: maybeRedirectTo?.redirectTo,
600
+ return new Response(null, { status: 302, headers });
601
+ }),
602
+ handleCallback: async (ctx, request) => {
603
+ const url = new URL(request.url);
604
+ const callbackPathParts = new URL(request.url).pathname.split("/");
605
+ const providerId = callbackPathParts[callbackPathParts.length - 1];
606
+ if (!providerId) {
607
+ throw Cv.error({
608
+ code: "OAUTH_MISSING_PROVIDER",
609
+ message: "Missing OAuth provider ID.",
610
610
  });
611
-
612
- const params = url.searchParams;
613
-
614
- if (
615
- request.headers.get("Content-Type") ===
616
- "application/x-www-form-urlencoded"
617
- ) {
618
- const formData = await request.formData();
619
- formData.forEach((value, key) => {
620
- if (typeof value === "string") {
621
- params.append(key, value);
622
- }
623
- });
624
- }
625
-
626
- return Fx.run(
627
- Fx.from({
628
- ok: async () => {
629
- const oauthConfig = provider as OAuthMaterializedConfig;
630
- const result = await Fx.run(
631
- handleOAuthCallback(
632
- providerId,
633
- oauthConfig.provider,
634
- oauthConfig,
635
- Object.fromEntries(params.entries()),
636
- cookies,
637
- ),
611
+ }
612
+ logWithLevel(
613
+ LOG_LEVELS.DEBUG,
614
+ "Handling OAuth callback for provider:",
615
+ providerId,
616
+ );
617
+ const provider = getProviderOrThrow(providerId);
618
+
619
+ const cookies = getCookies(request);
620
+
621
+ const maybeRedirectTo = useRedirectToParam(provider.id, cookies);
622
+
623
+ const destinationUrl = await redirectAbsoluteUrl(config, {
624
+ redirectTo: maybeRedirectTo?.redirectTo,
625
+ });
626
+
627
+ const params = url.searchParams;
628
+
629
+ if (
630
+ request.headers.get("Content-Type") ===
631
+ "application/x-www-form-urlencoded"
632
+ ) {
633
+ const formData = await request.formData();
634
+ formData.forEach((value, key) => {
635
+ if (typeof value === "string") {
636
+ params.append(key, value);
637
+ }
638
+ });
639
+ }
640
+
641
+ return Fx.run(
642
+ Fx.from({
643
+ ok: async () => {
644
+ const oauthConfig = provider as OAuthMaterializedConfig;
645
+ const result = await Fx.run(
646
+ handleOAuthCallback(
647
+ providerId,
648
+ oauthConfig.provider,
649
+ oauthConfig,
650
+ Object.fromEntries(params.entries()),
651
+ cookies,
652
+ ),
653
+ );
654
+ const oauthCookies = result.cookies;
655
+ const { id: profileId, ...profileData } = result.profile;
656
+ const { signature } = result;
657
+
658
+ const verificationCode = await callUserOAuth(ctx, {
659
+ provider: providerId,
660
+ providerAccountId: profileId,
661
+ profile: profileData,
662
+ signature,
663
+ });
664
+
665
+ const redirUrl = setURLSearchParam(
666
+ destinationUrl,
667
+ "code",
668
+ verificationCode,
669
+ );
670
+ const redirHeaders = new Headers({ Location: redirUrl });
671
+ redirHeaders.set("Cache-Control", "must-revalidate");
672
+ for (const { name, value, options } of [
673
+ ...oauthCookies,
674
+ ...(maybeRedirectTo !== null
675
+ ? [maybeRedirectTo.updatedCookie]
676
+ : []),
677
+ ] as any) {
678
+ redirHeaders.append(
679
+ "Set-Cookie",
680
+ serializeCookie(name, value, options),
638
681
  );
639
- const oauthCookies = result.cookies;
640
- const { id: profileId, ...profileData } = result.profile;
641
- const { signature } = result;
642
-
643
- const verificationCode = await callUserOAuth(ctx, {
644
- provider: providerId,
645
- providerAccountId: profileId,
646
- profile: profileData,
647
- signature,
648
- });
649
-
650
- const redirUrl = setURLSearchParam(
651
- destinationUrl,
652
- "code",
653
- verificationCode,
682
+ }
683
+ return new Response(null, {
684
+ status: 302,
685
+ headers: redirHeaders,
686
+ });
687
+ },
688
+ err: (error) => error,
689
+ }).pipe(
690
+ Fx.recover((error) => {
691
+ logError(error);
692
+ const respHeaders = new Headers({
693
+ Location: destinationUrl,
694
+ });
695
+ for (const { name, value, options } of maybeRedirectTo !== null
696
+ ? [maybeRedirectTo.updatedCookie]
697
+ : []) {
698
+ respHeaders.append(
699
+ "Set-Cookie",
700
+ serializeCookie(name, value, options),
654
701
  );
655
- const redirHeaders = new Headers({ Location: redirUrl });
656
- redirHeaders.set("Cache-Control", "must-revalidate");
657
- for (const { name, value, options } of [
658
- ...oauthCookies,
659
- ...(maybeRedirectTo !== null
660
- ? [maybeRedirectTo.updatedCookie]
661
- : []),
662
- ] as any) {
663
- redirHeaders.append(
664
- "Set-Cookie",
665
- serializeCookie(name, value, options),
666
- );
667
- }
668
- return new Response(null, {
702
+ }
703
+ return Fx.succeed(
704
+ new Response(null, {
669
705
  status: 302,
670
- headers: redirHeaders,
671
- });
672
- },
673
- err: (error) => error,
674
- }).pipe(
675
- Fx.recover((error) => {
676
- logError(error);
677
- const respHeaders = new Headers({
678
- Location: destinationUrl,
679
- });
680
- for (const { name, value, options } of maybeRedirectTo !==
681
- null
682
- ? [maybeRedirectTo.updatedCookie]
683
- : []) {
684
- respHeaders.append(
685
- "Set-Cookie",
686
- serializeCookie(name, value, options),
687
- );
688
- }
689
- return Fx.succeed(
690
- new Response(null, {
691
- status: 302,
692
- headers: respHeaders,
693
- }),
694
- );
695
- }),
696
- ),
697
- );
698
- },
699
- });
700
- }
701
- },
702
-
703
- /**
704
- * Wrap an HTTP action handler with Bearer token authentication.
705
- *
706
- * Extracts the `Authorization: Bearer <key>` header, verifies the
707
- * API key via `auth.key.verify()`, and injects `ctx.key` with the
708
- * verified key info. Returns structured JSON error responses for
709
- * missing/invalid/revoked/expired/rate-limited keys.
710
- *
711
- * If the handler returns a plain object, it is auto-wrapped in a
712
- * `200 JSON` response. If it returns a `Response`, CORS headers
713
- * are merged and the response is passed through.
714
- *
715
- * ```ts
716
- * const handler = auth.http.action(async (ctx, request) => {
717
- * const data = await ctx.runQuery(api.data.get, { userId: ctx.key.userId });
718
- * return { data };
719
- * });
720
- * http.route({ path: "/api/data", method: "GET", handler });
721
- * ```
722
- *
723
- * @param handler - Receives enriched `ctx` (with `ctx.key`) and the raw `Request`.
724
- * @param options.scope - Optional scope check; returns 403 if the key lacks permission.
725
- * @param options.cors - CORS config; defaults to permissive (`*`).
726
- */
727
- action: createHttpAction(auth),
728
-
729
- /**
730
- * Register a Bearer-authenticated route **and** its OPTIONS preflight
731
- * in a single call.
732
- *
733
- * ```ts
734
- * auth.http.route(http, {
735
- * path: "/api/messages",
736
- * method: "POST",
737
- * handler: async (ctx, request) => {
738
- * const { body } = await request.json();
739
- * await ctx.runMutation(internal.messages.sendAsUser, {
740
- * userId: ctx.key.userId,
741
- * body,
742
- * });
743
- * return { success: true };
744
- * },
745
- * });
746
- * ```
747
- *
748
- * @param http - The Convex HTTP router.
749
- * @param routeConfig.path - The URL path to match.
750
- * @param routeConfig.method - HTTP method (GET, POST, PUT, PATCH, DELETE).
751
- * @param routeConfig.handler - Receives enriched `ctx` (with `ctx.key`) and the raw `Request`.
752
- * @param routeConfig.scope - Optional scope check; returns 403 if the key lacks permission.
753
- * @param routeConfig.cors - CORS config; defaults to permissive (`*`).
754
- */
755
- route: createHttpRoute(createHttpAction(auth)),
706
+ headers: respHeaders,
707
+ }),
708
+ );
709
+ }),
710
+ ),
711
+ );
712
+ },
713
+ });
714
+ }
756
715
  },
716
+
717
+ /**
718
+ * Resolve mixed HTTP auth for a raw `httpAction`.
719
+ *
720
+ * Checks session auth first, then falls back to `Authorization: Bearer sk_*`
721
+ * API keys. This is the low-level helper for endpoints that intentionally
722
+ * accept either browser sessions or API keys.
723
+ * Pass `{ optional: true }` to get a null-shaped auth object instead of a
724
+ * `NOT_SIGNED_IN` error.
725
+ *
726
+ * ```ts
727
+ * http.route({
728
+ * path: "/api/data",
729
+ * method: "GET",
730
+ * handler: httpAction(async (ctx, request) => {
731
+ * const authContext = await auth.http.context(ctx, request);
732
+ * return Response.json({
733
+ * userId: authContext.userId,
734
+ * source: authContext.source,
735
+ * });
736
+ * }),
737
+ * });
738
+ * ```
739
+ */
740
+ context: createHttpContext(auth),
741
+
742
+ /**
743
+ * Wrap an HTTP action handler with Bearer token authentication.
744
+ *
745
+ * Extracts the `Authorization: Bearer <key>` header, verifies the
746
+ * API key via `auth.key.verify()`, and injects `ctx.key` with the
747
+ * verified key info. Returns structured JSON error responses for
748
+ * missing/invalid/revoked/expired/rate-limited keys.
749
+ *
750
+ * If the handler returns a plain object, it is auto-wrapped in a
751
+ * `200 JSON` response. If it returns a `Response`, CORS headers
752
+ * are merged and the response is passed through.
753
+ *
754
+ * ```ts
755
+ * const handler = auth.http.action(async (ctx, request) => {
756
+ * const data = await ctx.runQuery(api.data.get, { userId: ctx.key.userId });
757
+ * return { data };
758
+ * });
759
+ * http.route({ path: "/api/data", method: "GET", handler });
760
+ * ```
761
+ *
762
+ * @param handler - Receives enriched `ctx` (with `ctx.key`) and the raw `Request`.
763
+ * @param options.scope - Optional scope check; returns 403 if the key lacks permission.
764
+ * @param options.cors - CORS config; defaults to permissive (`*`).
765
+ */
766
+ action: createHttpAction(auth),
767
+
768
+ /**
769
+ * Register a Bearer-authenticated route **and** its OPTIONS preflight
770
+ * in a single call.
771
+ *
772
+ * ```ts
773
+ * auth.http.route(http, {
774
+ * path: "/api/messages",
775
+ * method: "POST",
776
+ * handler: async (ctx, request) => {
777
+ * const { body } = await request.json();
778
+ * await ctx.runMutation(internal.messages.sendAsUser, {
779
+ * userId: ctx.key.userId,
780
+ * body,
781
+ * });
782
+ * return { success: true };
783
+ * },
784
+ * });
785
+ * ```
786
+ *
787
+ * @param http - The Convex HTTP router.
788
+ * @param routeConfig.path - The URL path to match.
789
+ * @param routeConfig.method - HTTP method (GET, POST, PUT, PATCH, DELETE).
790
+ * @param routeConfig.handler - Receives enriched `ctx` (with `ctx.key`) and the raw `Request`.
791
+ * @param routeConfig.scope - Optional scope check; returns 403 if the key lacks permission.
792
+ * @param routeConfig.cors - CORS config; defaults to permissive (`*`).
793
+ */
794
+ route: createHttpRoute(createHttpAction(auth)),
757
795
  };
758
796
 
759
797
  const enrichCtx = <DataModel extends GenericDataModel>(