@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,6 +1,6 @@
1
- import { AuthError } from "./authError.js";
2
- import { LOG_LEVELS, decryptSecret, encryptSecret, generateRandomString, logError, logWithLevel, requireEnv, sha256 } from "./utils.js";
3
1
  import { configDefaults, listAvailableProviders } from "./config.js";
2
+ import { LOG_LEVELS, decryptSecret, encryptSecret, generateRandomString, logError, logWithLevel, requireEnv, sha256 } from "./utils.js";
3
+ import { redirectToParamCookie, useRedirectToParam } from "./cookies.js";
4
4
  import { callModifyAccount } from "./mutations/account.js";
5
5
  import { callInvalidateSessions } from "./mutations/invalidate.js";
6
6
  import { enterpriseOidcProviderId, getEnterpriseOidcUrls, isEnterpriseSamlSourceActive, normalizeDomain } from "./enterprise/shared.js";
@@ -14,15 +14,15 @@ import { storeArgs, storeImpl } from "./mutations/store.js";
14
14
  import { redirectAbsoluteUrl, setURLSearchParam } from "./redirects.js";
15
15
  import { signInImpl } from "./signin.js";
16
16
  import { createCoreDomains } from "./core.js";
17
- import { redirectToParamCookie, useRedirectToParam } from "./cookies.js";
17
+ import { getOidcConfig, getPublicOidcConfig, getSamlConfig, upsertProtocolConfig, withOidcSecretState } from "./enterprise/config.js";
18
18
  import { createEnterpriseDomain } from "./enterprise/domain.js";
19
- import { addAuthRoutes, addOpenIdRoutes, convertErrorsToResponse, createHttpAction, createHttpRoute, getCookies } from "./http.js";
19
+ import { addAuthRoutes, addOpenIdRoutes, convertErrorsToResponse, createHttpAction, createHttpContext, createHttpRoute, getCookies } from "./http.js";
20
20
  import { createOAuthAuthorizationURL, handleOAuthCallback } from "./oauth.js";
21
- import { getOidcConfig, getPublicOidcConfig, getSamlConfig, upsertProtocolConfig, withOidcSecretState } from "./enterprise/config.js";
22
21
  import { createServiceProviderMetadata, getSamlServiceProviderOptions, parseSamlIdpMetadata } from "./enterprise/saml.js";
23
22
  import { parseScimPath } from "./enterprise/scim.js";
24
23
  import { addEnterpriseHttpRuntime } from "./enterprise/http.js";
25
24
  import { Fx } from "@robelest/fx";
25
+ import { Cv } from "@robelest/fx/convex";
26
26
  import { actionGeneric, internalMutationGeneric } from "convex/server";
27
27
  import { v } from "convex/values";
28
28
  import { serialize } from "cookie";
@@ -56,7 +56,11 @@ function Auth(config_) {
56
56
  if (provider === void 0) {
57
57
  const detail = `Provider \`${id}\` is not configured, available providers are ${listAvailableProviders(config, allowExtraProviders)}.`;
58
58
  logWithLevel(LOG_LEVELS.ERROR, detail);
59
- throw new AuthError("PROVIDER_NOT_CONFIGURED", detail, { provider: id }).toConvexError();
59
+ throw Cv.error({
60
+ code: "PROVIDER_NOT_CONFIGURED",
61
+ message: detail,
62
+ provider: id
63
+ });
60
64
  }
61
65
  return provider;
62
66
  };
@@ -81,12 +85,18 @@ function Auth(config_) {
81
85
  const getPolicyFromEnterprise = (enterprise) => normalizeEnterprisePolicy(enterprise.policy);
82
86
  const loadEnterpriseOrThrow = async (ctx, enterpriseId) => {
83
87
  const enterprise = await ctx.runQuery(config.component.public.enterpriseGet, { enterpriseId });
84
- if (!enterprise) throw new AuthError("INVALID_PARAMETERS", enterpriseNotFoundError).toConvexError();
88
+ if (!enterprise) throw Cv.error({
89
+ code: "INVALID_PARAMETERS",
90
+ message: enterpriseNotFoundError
91
+ });
85
92
  return enterprise;
86
93
  };
87
94
  const loadActiveEnterpriseOrThrow = async (ctx, enterpriseId) => {
88
95
  const enterprise = await loadEnterpriseOrThrow(ctx, enterpriseId);
89
- if (enterprise.status !== "active") throw new AuthError("INVALID_PARAMETERS", "Enterprise connection is not active.").toConvexError();
96
+ if (enterprise.status !== "active") throw Cv.error({
97
+ code: "INVALID_PARAMETERS",
98
+ message: "Enterprise connection is not active."
99
+ });
90
100
  return enterprise;
91
101
  };
92
102
  const loadActiveEnterpriseSamlOrThrow = async (ctx, enterpriseId) => {
@@ -100,9 +110,15 @@ function Auth(config_) {
100
110
  status: enterprise.status,
101
111
  enterprise
102
112
  };
103
- if (!isEnterpriseSamlSourceActive(loaded)) throw new AuthError("INVALID_PARAMETERS", "Enterprise connection is not active.").toConvexError();
113
+ if (!isEnterpriseSamlSourceActive(loaded)) throw Cv.error({
114
+ code: "INVALID_PARAMETERS",
115
+ message: "Enterprise connection is not active."
116
+ });
104
117
  const saml = getSamlConfig(loaded.config);
105
- if (!saml.idp?.metadataXml) throw new AuthError("PROVIDER_NOT_CONFIGURED", "SAML is not configured for this enterprise.").toConvexError();
118
+ if (!saml.idp?.metadataXml) throw Cv.error({
119
+ code: "PROVIDER_NOT_CONFIGURED",
120
+ message: "SAML is not configured for this enterprise."
121
+ });
106
122
  return {
107
123
  loaded,
108
124
  enterprise,
@@ -112,7 +128,10 @@ function Auth(config_) {
112
128
  const loadEnterpriseOidcOrThrow = async (ctx, enterpriseId) => {
113
129
  const enterprise = await loadActiveEnterpriseOrThrow(ctx, enterpriseId);
114
130
  const oidc = await getEnterpriseOidcConfigWithSecret(ctx, enterprise);
115
- if (oidc.enabled !== true) throw new AuthError("PROVIDER_NOT_CONFIGURED", "OIDC is not configured for this enterprise.").toConvexError();
131
+ if (oidc.enabled !== true) throw Cv.error({
132
+ code: "PROVIDER_NOT_CONFIGURED",
133
+ message: "OIDC is not configured for this enterprise."
134
+ });
116
135
  return {
117
136
  enterprise,
118
137
  oidc
@@ -164,14 +183,26 @@ function Auth(config_) {
164
183
  };
165
184
  const getEnterpriseScimContext = async (ctx, request) => {
166
185
  const authHeader = request.headers.get("Authorization");
167
- if (!authHeader?.startsWith("Bearer ")) throw new AuthError("MISSING_BEARER_TOKEN").toConvexError();
186
+ if (!authHeader?.startsWith("Bearer ")) throw Cv.error({
187
+ code: "MISSING_BEARER_TOKEN",
188
+ message: "Missing or malformed Authorization: Bearer header."
189
+ });
168
190
  const token = authHeader.slice(7);
169
191
  const scimConfig = await ctx.runQuery(config.component.public.enterpriseScimConfigGetByTokenHash, { tokenHash: await sha256(token) });
170
- if (!scimConfig || scimConfig.status !== "active") throw new AuthError("INVALID_API_KEY", "Invalid SCIM token.").toConvexError();
192
+ if (!scimConfig || scimConfig.status !== "active") throw Cv.error({
193
+ code: "INVALID_API_KEY",
194
+ message: "Invalid SCIM token."
195
+ });
171
196
  const parsedPath = parseScimPath(new URL(request.url).pathname);
172
- if (parsedPath.enterpriseId !== scimConfig.enterpriseId) throw new AuthError("INVALID_API_KEY", "SCIM token/tenant mismatch.").toConvexError();
197
+ if (parsedPath.enterpriseId !== scimConfig.enterpriseId) throw Cv.error({
198
+ code: "INVALID_API_KEY",
199
+ message: "SCIM token/tenant mismatch."
200
+ });
173
201
  const enterprise = await ctx.runQuery(config.component.public.enterpriseGet, { enterpriseId: scimConfig.enterpriseId });
174
- if (enterprise === null) throw new AuthError("INVALID_PARAMETERS", "Enterprise not found.").toConvexError();
202
+ if (enterprise === null) throw Cv.error({
203
+ code: "INVALID_PARAMETERS",
204
+ message: "Enterprise not found."
205
+ });
175
206
  return {
176
207
  scimConfig,
177
208
  enterprise,
@@ -219,104 +250,116 @@ function Auth(config_) {
219
250
  enterpriseOidcProviderId,
220
251
  getPolicyFromEnterprise,
221
252
  patchEnterprisePolicy
222
- }),
223
- http: {
224
- add: (http) => {
225
- addOpenIdRoutes(http, {
226
- getIssuer: () => requireEnv("CONVEX_SITE_URL"),
227
- getJwks: () => requireEnv("JWKS")
228
- });
229
- addEnterpriseHttpRuntime({
230
- http,
231
- hasSSO,
232
- auth,
233
- config,
234
- routeBase: ENTERPRISE_CONTROL_ROUTE_BASE,
235
- requireEnv,
236
- loadActiveEnterpriseSamlOrThrow,
237
- loadEnterpriseOidcOrThrow,
238
- getEnterpriseScimContext,
239
- getPolicyFromEnterprise,
240
- normalizeEnterprisePolicy,
241
- recordEnterpriseAuditEvent,
242
- emitEnterpriseWebhookDeliveries,
243
- generateRandomString,
244
- inviteTokenAlphabet: INVITE_TOKEN_ALPHABET,
245
- callUserOAuth,
246
- callVerifierSignature
247
- });
248
- if (hasOAuth) addAuthRoutes(http, {
249
- handleSignIn: convertErrorsToResponse(400, async (ctx, request) => {
250
- const url = new URL(request.url);
251
- const providerId = url.pathname.split("/").at(-1);
252
- if (providerId === null) throw new AuthError("OAUTH_MISSING_PROVIDER").toConvexError();
253
- const verifier = url.searchParams.get("code");
254
- if (verifier === null) throw new AuthError("OAUTH_MISSING_VERIFIER").toConvexError();
255
- const oauthConfig = getProviderOrThrow(providerId);
256
- const { redirect, cookies, signature } = await createOAuthAuthorizationURL(providerId, oauthConfig.provider, oauthConfig);
257
- await callVerifierSignature(ctx, {
258
- verifier,
259
- signature
260
- });
261
- const redirectTo = url.searchParams.get("redirectTo");
262
- if (redirectTo !== null) cookies.push(redirectToParamCookie(providerId, redirectTo));
263
- const headers = new Headers({ Location: redirect });
264
- for (const { name, value, options } of cookies) headers.append("Set-Cookie", serialize(name, value, options));
265
- return new Response(null, {
266
- status: 302,
267
- headers
268
- });
269
- }),
270
- handleCallback: async (ctx, request) => {
271
- const url = new URL(request.url);
272
- const providerId = new URL(request.url).pathname.split("/").at(-1);
273
- if (!providerId) throw new AuthError("OAUTH_MISSING_PROVIDER").toConvexError();
274
- logWithLevel(LOG_LEVELS.DEBUG, "Handling OAuth callback for provider:", providerId);
275
- const provider = getProviderOrThrow(providerId);
276
- const cookies = getCookies(request);
277
- const maybeRedirectTo = useRedirectToParam(provider.id, cookies);
278
- const destinationUrl = await redirectAbsoluteUrl(config, { redirectTo: maybeRedirectTo?.redirectTo });
279
- const params = url.searchParams;
280
- if (request.headers.get("Content-Type") === "application/x-www-form-urlencoded") (await request.formData()).forEach((value, key) => {
281
- if (typeof value === "string") params.append(key, value);
282
- });
283
- return Fx.run(Fx.from({
284
- ok: async () => {
285
- const oauthConfig = provider;
286
- const result = await Fx.run(handleOAuthCallback(providerId, oauthConfig.provider, oauthConfig, Object.fromEntries(params.entries()), cookies));
287
- const oauthCookies = result.cookies;
288
- const { id: profileId, ...profileData } = result.profile;
289
- const { signature } = result;
290
- const redirUrl = setURLSearchParam(destinationUrl, "code", await callUserOAuth(ctx, {
291
- provider: providerId,
292
- providerAccountId: profileId,
293
- profile: profileData,
294
- signature
295
- }));
296
- const redirHeaders = new Headers({ Location: redirUrl });
297
- redirHeaders.set("Cache-Control", "must-revalidate");
298
- for (const { name, value, options } of [...oauthCookies, ...maybeRedirectTo !== null ? [maybeRedirectTo.updatedCookie] : []]) redirHeaders.append("Set-Cookie", serialize(name, value, options));
299
- return new Response(null, {
300
- status: 302,
301
- headers: redirHeaders
302
- });
303
- },
304
- err: (error) => error
305
- }).pipe(Fx.recover((error) => {
306
- logError(error);
307
- const respHeaders = new Headers({ Location: destinationUrl });
308
- for (const { name, value, options } of maybeRedirectTo !== null ? [maybeRedirectTo.updatedCookie] : []) respHeaders.append("Set-Cookie", serialize(name, value, options));
309
- return Fx.succeed(new Response(null, {
310
- status: 302,
311
- headers: respHeaders
253
+ })
254
+ };
255
+ auth.http = {
256
+ add: (http) => {
257
+ addOpenIdRoutes(http, {
258
+ getIssuer: () => requireEnv("CONVEX_SITE_URL"),
259
+ getJwks: () => requireEnv("JWKS")
260
+ });
261
+ addEnterpriseHttpRuntime({
262
+ http,
263
+ hasSSO,
264
+ auth,
265
+ config,
266
+ routeBase: ENTERPRISE_CONTROL_ROUTE_BASE,
267
+ requireEnv,
268
+ loadActiveEnterpriseSamlOrThrow,
269
+ loadEnterpriseOidcOrThrow,
270
+ getEnterpriseScimContext,
271
+ getPolicyFromEnterprise,
272
+ normalizeEnterprisePolicy,
273
+ recordEnterpriseAuditEvent,
274
+ emitEnterpriseWebhookDeliveries,
275
+ generateRandomString,
276
+ inviteTokenAlphabet: INVITE_TOKEN_ALPHABET,
277
+ callUserOAuth,
278
+ callVerifierSignature
279
+ });
280
+ if (hasOAuth) addAuthRoutes(http, {
281
+ handleSignIn: convertErrorsToResponse(400, async (ctx, request) => {
282
+ const url = new URL(request.url);
283
+ const pathParts = url.pathname.split("/");
284
+ const providerId = pathParts[pathParts.length - 1];
285
+ if (providerId === null) throw Cv.error({
286
+ code: "OAUTH_MISSING_PROVIDER",
287
+ message: "Missing OAuth provider ID."
288
+ });
289
+ const verifier = url.searchParams.get("code");
290
+ if (verifier === null) throw Cv.error({
291
+ code: "OAUTH_MISSING_VERIFIER",
292
+ message: "Missing sign-in verifier."
293
+ });
294
+ const oauthConfig = getProviderOrThrow(providerId);
295
+ const { redirect, cookies, signature } = await createOAuthAuthorizationURL(providerId, oauthConfig.provider, oauthConfig);
296
+ await callVerifierSignature(ctx, {
297
+ verifier,
298
+ signature
299
+ });
300
+ const redirectTo = url.searchParams.get("redirectTo");
301
+ if (redirectTo !== null) cookies.push(redirectToParamCookie(providerId, redirectTo));
302
+ const headers = new Headers({ Location: redirect });
303
+ for (const { name, value, options } of cookies) headers.append("Set-Cookie", serialize(name, value, options));
304
+ return new Response(null, {
305
+ status: 302,
306
+ headers
307
+ });
308
+ }),
309
+ handleCallback: async (ctx, request) => {
310
+ const url = new URL(request.url);
311
+ const callbackPathParts = new URL(request.url).pathname.split("/");
312
+ const providerId = callbackPathParts[callbackPathParts.length - 1];
313
+ if (!providerId) throw Cv.error({
314
+ code: "OAUTH_MISSING_PROVIDER",
315
+ message: "Missing OAuth provider ID."
316
+ });
317
+ logWithLevel(LOG_LEVELS.DEBUG, "Handling OAuth callback for provider:", providerId);
318
+ const provider = getProviderOrThrow(providerId);
319
+ const cookies = getCookies(request);
320
+ const maybeRedirectTo = useRedirectToParam(provider.id, cookies);
321
+ const destinationUrl = await redirectAbsoluteUrl(config, { redirectTo: maybeRedirectTo?.redirectTo });
322
+ const params = url.searchParams;
323
+ if (request.headers.get("Content-Type") === "application/x-www-form-urlencoded") (await request.formData()).forEach((value, key) => {
324
+ if (typeof value === "string") params.append(key, value);
325
+ });
326
+ return Fx.run(Fx.from({
327
+ ok: async () => {
328
+ const oauthConfig = provider;
329
+ const result = await Fx.run(handleOAuthCallback(providerId, oauthConfig.provider, oauthConfig, Object.fromEntries(params.entries()), cookies));
330
+ const oauthCookies = result.cookies;
331
+ const { id: profileId, ...profileData } = result.profile;
332
+ const { signature } = result;
333
+ const redirUrl = setURLSearchParam(destinationUrl, "code", await callUserOAuth(ctx, {
334
+ provider: providerId,
335
+ providerAccountId: profileId,
336
+ profile: profileData,
337
+ signature
312
338
  }));
313
- })));
314
- }
315
- });
316
- },
317
- action: createHttpAction(auth),
318
- route: createHttpRoute(createHttpAction(auth))
319
- }
339
+ const redirHeaders = new Headers({ Location: redirUrl });
340
+ redirHeaders.set("Cache-Control", "must-revalidate");
341
+ for (const { name, value, options } of [...oauthCookies, ...maybeRedirectTo !== null ? [maybeRedirectTo.updatedCookie] : []]) redirHeaders.append("Set-Cookie", serialize(name, value, options));
342
+ return new Response(null, {
343
+ status: 302,
344
+ headers: redirHeaders
345
+ });
346
+ },
347
+ err: (error) => error
348
+ }).pipe(Fx.recover((error) => {
349
+ logError(error);
350
+ const respHeaders = new Headers({ Location: destinationUrl });
351
+ for (const { name, value, options } of maybeRedirectTo !== null ? [maybeRedirectTo.updatedCookie] : []) respHeaders.append("Set-Cookie", serialize(name, value, options));
352
+ return Fx.succeed(new Response(null, {
353
+ status: 302,
354
+ headers: respHeaders
355
+ }));
356
+ })));
357
+ }
358
+ });
359
+ },
360
+ context: createHttpContext(auth),
361
+ action: createHttpAction(auth),
362
+ route: createHttpRoute(createHttpAction(auth))
320
363
  };
321
364
  const enrichCtx = (ctx) => ({
322
365
  ...ctx,
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.js","names":["serializeCookie"],"sources":["../../src/server/runtime.ts"],"sourcesContent":["import {\n Auth,\n GenericActionCtx,\n GenericDataModel,\n HttpRouter,\n actionGeneric,\n internalMutationGeneric,\n} from \"convex/server\";\nimport { v } from \"convex/values\";\nimport { serialize as serializeCookie } from \"cookie\";\n\nimport { createCoreDomains } from \"./core\";\nimport { redirectToParamCookie, useRedirectToParam } from \"./cookies\";\nimport { createEnterpriseDomain } from \"./enterprise/domain\";\nimport { addEnterpriseHttpRuntime } from \"./enterprise/http\";\nimport {\n getOidcConfig,\n getPublicOidcConfig,\n getSamlConfig,\n upsertProtocolConfig,\n withOidcSecretState,\n} from \"./enterprise/config\";\nimport { normalizeEnterprisePolicy, patchEnterprisePolicy } from \"./enterprise/policy\";\nimport {\n createServiceProviderMetadata,\n getSamlServiceProviderOptions,\n parseSamlIdpMetadata,\n} from \"./enterprise/saml\";\nimport {\n parseScimPath,\n} from \"./enterprise/scim\";\nimport {\n enterpriseOidcProviderId,\n getEnterpriseOidcUrls,\n isEnterpriseSamlSourceActive,\n normalizeDomain,\n} from \"./enterprise/shared\";\nimport { Fx } from \"@robelest/fx\";\n\nimport { AuthError } from \"./authError\";\nimport {\n addAuthRoutes,\n addOpenIdRoutes,\n convertErrorsToResponse,\n createHttpAction,\n createHttpRoute,\n getCookies,\n} from \"./http\";\nimport {\n callCreateAccountFromCredentials,\n callInvalidateSessions,\n callModifyAccount,\n callRetrieveAccountWithCredentials,\n callSignOut,\n callUserOAuth,\n callVerifierSignature,\n storeArgs,\n storeImpl,\n} from \"./mutations/index\";\nimport { createOAuthAuthorizationURL, handleOAuthCallback } from \"./oauth\";\nimport { GetProviderOrThrowFunc } from \"./crypto\";\nimport { configDefaults, listAvailableProviders } from \"./config\";\nimport { redirectAbsoluteUrl, setURLSearchParam } from \"./redirects\";\nimport { signInImpl } from \"./signin\";\nimport type {\n ConvexAuthConfig,\n FunctionReferenceFromExport,\n OAuthMaterializedConfig,\n Tokens,\n} from \"./types\";\nimport { MutationCtx } from \"./types\";\nimport {\n decryptSecret,\n encryptSecret,\n generateRandomString,\n LOG_LEVELS,\n logError,\n logWithLevel,\n sha256,\n} from \"./utils\";\nimport { requireEnv } from \"./utils\";\n\nconst ENTERPRISE_OIDC_CLIENT_SECRET_KIND = \"oidc_client_secret\" as const;\n\n/**\n * The type of the signIn Convex Action returned from the auth() helper.\n *\n * This type is exported for implementors of other client integrations.\n * However it is not stable, and may change until this library reaches 1.0.\n *\n * @internal\n */\nexport type SignInAction = FunctionReferenceFromExport<\n ReturnType<typeof Auth>[\"signIn\"]\n>;\n\n/** @internal */\nexport type SignInActionResult =\n | { kind: \"signedIn\"; tokens: Tokens | null }\n | { kind: \"redirect\"; redirect: string; verifier: string }\n | { kind: \"started\" }\n | { kind: \"passkeyOptions\"; options: Record<string, any>; verifier: string }\n | { kind: \"totpRequired\"; verifier: string }\n | {\n kind: \"totpSetup\";\n totpSetup: { uri: string; secret: string; totpId: string };\n verifier: string;\n }\n | {\n kind: \"deviceCode\";\n deviceCode: {\n deviceCode: string;\n userCode: string;\n verificationUri: string;\n verificationUriComplete: string;\n expiresIn: number;\n interval: number;\n };\n };\n/**\n * The type of the signOut Convex Action returned from the auth() helper.\n *\n * This type is exported for implementors of other client integrations.\n * However it is not stable, and may change until this library reaches 1.0.\n *\n * @internal\n */\nexport type SignOutAction = FunctionReferenceFromExport<\n ReturnType<typeof Auth>[\"signOut\"]\n>;\n\n/**\n * Configure the Convex Auth library. Returns an object with\n * functions and `auth` helper. You must export the functions\n * from `convex/auth.ts` to make them callable:\n *\n * ```ts filename=\"convex/auth.ts\"\n * import { createAuth } from \"@robelest/convex-auth/component\";\n * import { components } from \"./_generated/api\";\n *\n * export const auth = createAuth(components.auth, {\n * providers: [],\n * });\n * export const { signIn, signOut, store } = auth;\n * ```\n *\n * @returns An object with fields you should reexport from your\n * `convex/auth.ts` file.\n */\nexport function Auth(config_: ConvexAuthConfig) {\n const config = configDefaults(config_);\n const hasOAuth = config.providers.some(\n (provider) => provider.type === \"oauth\",\n );\n const hasSSO = config.providers.some((provider) => provider.type === \"sso\");\n const getProviderOrThrow: GetProviderOrThrowFunc = (\n id: string,\n allowExtraProviders: boolean = false,\n ) => {\n const provider =\n config.providers.find(\n (configuredProvider) => configuredProvider.id === id,\n ) ??\n (allowExtraProviders\n ? config.extraProviders.find(\n (configuredProvider) => configuredProvider.id === id,\n )\n : undefined);\n if (provider === undefined) {\n const detail =\n `Provider \\`${id}\\` is not configured, ` +\n `available providers are ${listAvailableProviders(config, allowExtraProviders)}.`;\n logWithLevel(LOG_LEVELS.ERROR, detail);\n throw new AuthError(\"PROVIDER_NOT_CONFIGURED\", detail, {\n provider: id,\n }).toConvexError();\n }\n return provider;\n };\n type ComponentCtx = Pick<\n GenericActionCtx<GenericDataModel>,\n \"runQuery\" | \"runMutation\"\n >;\n type ComponentReadCtx = Pick<GenericActionCtx<GenericDataModel>, \"runQuery\">;\n const getEnterpriseSecret = async (\n ctx: ComponentReadCtx | ComponentCtx,\n enterpriseId: string,\n kind: typeof ENTERPRISE_OIDC_CLIENT_SECRET_KIND,\n ) => {\n return await ctx.runQuery(config.component.public.enterpriseSecretGet, {\n enterpriseId,\n kind,\n });\n };\n const getEnterpriseOidcConfigWithSecret = async (\n ctx: ComponentReadCtx | ComponentCtx,\n enterprise: { _id: string; config?: unknown },\n ): Promise<Record<string, any>> => {\n const oidc = getOidcConfig(enterprise.config);\n const secret = await getEnterpriseSecret(\n ctx,\n enterprise._id,\n ENTERPRISE_OIDC_CLIENT_SECRET_KIND,\n );\n return {\n ...oidc,\n ...(secret\n ? { clientSecret: await decryptSecret(secret.ciphertext) }\n : {}),\n };\n };\n const INVITE_TOKEN_ALPHABET =\n \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\";\n const INVITE_TOKEN_LENGTH = 48;\n\n const enterpriseNotFoundError = \"Enterprise not found.\";\n\n const ENTERPRISE_CONTROL_ROUTE_BASE = \"/api/auth/sso\";\n\n const getPolicyFromEnterprise = (enterprise: { policy?: unknown }) =>\n normalizeEnterprisePolicy(enterprise.policy);\n\n const loadEnterpriseOrThrow = async (\n ctx: ComponentReadCtx,\n enterpriseId: string,\n ) => {\n const enterprise = await ctx.runQuery(\n config.component.public.enterpriseGet,\n {\n enterpriseId,\n },\n );\n if (!enterprise) {\n throw new AuthError(\n \"INVALID_PARAMETERS\",\n enterpriseNotFoundError,\n ).toConvexError();\n }\n return enterprise;\n };\n\n const loadActiveEnterpriseOrThrow = async (\n ctx: ComponentReadCtx,\n enterpriseId: string,\n ) => {\n const enterprise = await loadEnterpriseOrThrow(ctx, enterpriseId);\n if (enterprise.status !== \"active\") {\n throw new AuthError(\n \"INVALID_PARAMETERS\",\n \"Enterprise connection is not active.\",\n ).toConvexError();\n }\n return enterprise;\n };\n\n const loadActiveEnterpriseSamlOrThrow = async (\n ctx: ComponentReadCtx,\n enterpriseId: string,\n ) => {\n const enterprise = await loadEnterpriseOrThrow(ctx, enterpriseId);\n const loaded = {\n source: {\n kind: \"enterprise\" as const,\n id: enterpriseId,\n },\n config: enterprise.config,\n status: enterprise.status,\n enterprise,\n };\n if (!isEnterpriseSamlSourceActive(loaded)) {\n throw new AuthError(\n \"INVALID_PARAMETERS\",\n \"Enterprise connection is not active.\",\n ).toConvexError();\n }\n const saml = getSamlConfig(loaded.config);\n if (!saml.idp?.metadataXml) {\n throw new AuthError(\n \"PROVIDER_NOT_CONFIGURED\",\n \"SAML is not configured for this enterprise.\",\n ).toConvexError();\n }\n return { loaded, enterprise, saml };\n };\n\n const loadEnterpriseOidcOrThrow = async (\n ctx: ComponentReadCtx,\n enterpriseId: string,\n ) => {\n const enterprise = await loadActiveEnterpriseOrThrow(ctx, enterpriseId);\n const oidc = await getEnterpriseOidcConfigWithSecret(ctx, enterprise);\n if (oidc.enabled !== true) {\n throw new AuthError(\n \"PROVIDER_NOT_CONFIGURED\",\n \"OIDC is not configured for this enterprise.\",\n ).toConvexError();\n }\n return { enterprise, oidc };\n };\n\n const validateEnterprisePolicy = (\n policy: ReturnType<typeof normalizeEnterprisePolicy>,\n ) => {\n const checks: Array<{\n name: string;\n ok: boolean;\n message?: string;\n }> = [];\n\n checks.push({ name: \"policy_version\", ok: policy.version === 1 });\n checks.push({\n name: \"jit_default_role_ids_present\",\n ok:\n policy.provisioning.jit.mode !== \"createUserAndMembership\" ||\n policy.provisioning.jit.defaultRoleIds.length > 0,\n message:\n policy.provisioning.jit.mode === \"createUserAndMembership\" &&\n policy.provisioning.jit.defaultRoleIds.length === 0\n ? \"At least one default roleId is required when JIT membership provisioning is enabled.\"\n : undefined,\n });\n checks.push({\n name: \"jit_default_role_ids_known\",\n ok: policy.provisioning.jit.defaultRoleIds.every(\n (roleId) => config.authorization.roles[roleId] !== undefined,\n ),\n message: policy.provisioning.jit.defaultRoleIds.every(\n (roleId) => config.authorization.roles[roleId] !== undefined,\n )\n ? undefined\n : \"JIT defaultRoleIds contains unknown roleIds.\",\n });\n checks.push({\n name: \"scim_reuse_supported\",\n ok:\n policy.provisioning.scimReuse.user === \"externalId\" ||\n policy.provisioning.scimReuse.user === \"none\",\n });\n\n return checks;\n };\n\n const recordEnterpriseAuditEvent = async (\n ctx: ComponentCtx,\n data: {\n enterpriseId: string;\n groupId: string;\n eventType: string;\n actorType: \"user\" | \"system\" | \"scim\" | \"api_key\" | \"webhook\";\n actorId?: string;\n subjectType: string;\n subjectId?: string;\n ok: boolean;\n requestId?: string;\n ip?: string;\n metadata?: Record<string, unknown>;\n },\n ) => {\n const { ok, ...rest } = data;\n return (await ctx.runMutation(\n config.component.public.enterpriseAuditEventCreate,\n {\n ...rest,\n status: ok ? \"success\" : \"failure\",\n occurredAt: Date.now(),\n },\n )) as string;\n };\n\n const emitEnterpriseWebhookDeliveries = async (\n ctx: ComponentCtx,\n data: {\n enterpriseId: string;\n eventType: string;\n payload: Record<string, unknown>;\n auditEventId?: string;\n },\n ) => {\n const endpoints = await ctx.runQuery(\n config.component.public.enterpriseWebhookEndpointList,\n { enterpriseId: data.enterpriseId },\n );\n for (const endpoint of endpoints) {\n if (\n endpoint.status !== \"active\" ||\n !endpoint.subscriptions.includes(data.eventType)\n ) {\n continue;\n }\n await ctx.runMutation(\n config.component.public.enterpriseWebhookDeliveryEnqueue,\n {\n enterpriseId: data.enterpriseId,\n endpointId: endpoint._id,\n auditEventId: data.auditEventId,\n eventType: data.eventType,\n payload: data.payload,\n nextAttemptAt: Date.now(),\n },\n );\n }\n };\n\n const getEnterpriseScimContext = async (\n ctx: ComponentReadCtx,\n request: Request,\n ) => {\n const authHeader = request.headers.get(\"Authorization\");\n if (!authHeader?.startsWith(\"Bearer \")) {\n throw new AuthError(\"MISSING_BEARER_TOKEN\").toConvexError();\n }\n const token = authHeader.slice(7);\n const scimConfig = await ctx.runQuery(\n config.component.public.enterpriseScimConfigGetByTokenHash,\n { tokenHash: await sha256(token) },\n );\n if (!scimConfig || scimConfig.status !== \"active\") {\n throw new AuthError(\n \"INVALID_API_KEY\",\n \"Invalid SCIM token.\",\n ).toConvexError();\n }\n const parsedPath = parseScimPath(new URL(request.url).pathname);\n if (parsedPath.enterpriseId !== scimConfig.enterpriseId) {\n throw new AuthError(\n \"INVALID_API_KEY\",\n \"SCIM token/tenant mismatch.\",\n ).toConvexError();\n }\n const enterprise = await ctx.runQuery(\n config.component.public.enterpriseGet,\n {\n enterpriseId: scimConfig.enterpriseId,\n },\n );\n if (enterprise === null) {\n throw new AuthError(\n \"INVALID_PARAMETERS\",\n \"Enterprise not found.\",\n ).toConvexError();\n }\n return { scimConfig, enterprise, parsedPath };\n };\n\n let auth: any;\n auth = {\n ...createCoreDomains({\n config,\n getAuth: () => auth,\n callInvalidateSessions,\n callCreateAccountFromCredentials,\n callRetrieveAccountWithCredentials,\n callModifyAccount,\n getEnrichCtx: () => enrichCtx,\n inviteTokenAlphabet: INVITE_TOKEN_ALPHABET,\n inviteTokenLength: INVITE_TOKEN_LENGTH,\n }),\n /**\n * SSO namespace — enterprise SSO connection management, domain, OIDC,\n * SAML, SCIM, audit, and webhook helpers.\n */\n sso: createEnterpriseDomain({\n config,\n getAuth: () => auth,\n normalizeEnterprisePolicy,\n normalizeDomain,\n getEnterpriseSecret,\n loadEnterpriseOrThrow,\n validateEnterprisePolicy,\n recordEnterpriseAuditEvent,\n emitEnterpriseWebhookDeliveries,\n enterpriseNotFoundError,\n ENTERPRISE_OIDC_CLIENT_SECRET_KIND,\n requireEnv,\n generateRandomString,\n INVITE_TOKEN_ALPHABET,\n sha256,\n encryptSecret,\n upsertProtocolConfig,\n parseSamlIdpMetadata,\n createServiceProviderMetadata,\n getSamlServiceProviderOptions,\n getPublicOidcConfig,\n withOidcSecretState,\n getOidcConfig,\n getEnterpriseOidcUrls,\n enterpriseOidcProviderId,\n getPolicyFromEnterprise,\n patchEnterprisePolicy,\n }),\n // HTTP wiring stays local to the factory because it still depends on a\n // dense mix of OAuth, SAML, SCIM, cookie, and response helpers.\n http: {\n /**\n * Register core HTTP routes for JWT verification and OAuth sign-in.\n *\n * ```ts\n * import { httpRouter } from \"convex/server\";\n * import { auth } from \"./auth\";\n *\n * const http = httpRouter();\n *\n * auth.http.add(http);\n *\n * export default http;\n * ```\n *\n * The following routes are handled always:\n *\n * - `/.well-known/openid-configuration`\n * - `/.well-known/jwks.json`\n *\n * The following routes are handled if OAuth is configured:\n *\n * - `/api/auth/signin/*`\n * - `/api/auth/callback/*`\n *\n * @param http your HTTP router\n */\n add: (http: HttpRouter) => {\n addOpenIdRoutes(http, {\n getIssuer: () => requireEnv(\"CONVEX_SITE_URL\"),\n getJwks: () => requireEnv(\"JWKS\"),\n });\n\n addEnterpriseHttpRuntime({\n http,\n hasSSO,\n auth,\n config,\n routeBase: ENTERPRISE_CONTROL_ROUTE_BASE,\n requireEnv,\n loadActiveEnterpriseSamlOrThrow,\n loadEnterpriseOidcOrThrow,\n getEnterpriseScimContext,\n getPolicyFromEnterprise,\n normalizeEnterprisePolicy,\n recordEnterpriseAuditEvent,\n emitEnterpriseWebhookDeliveries,\n generateRandomString,\n inviteTokenAlphabet: INVITE_TOKEN_ALPHABET,\n callUserOAuth,\n callVerifierSignature,\n });\n\n if (hasOAuth) {\n addAuthRoutes(http, {\n handleSignIn: convertErrorsToResponse(400, async (ctx, request) => {\n const url = new URL(request.url);\n const pathParts = url.pathname.split(\"/\");\n const providerId = pathParts.at(-1)!;\n if (providerId === null) {\n throw new AuthError(\"OAUTH_MISSING_PROVIDER\").toConvexError();\n }\n const verifier = url.searchParams.get(\"code\");\n if (verifier === null) {\n throw new AuthError(\"OAUTH_MISSING_VERIFIER\").toConvexError();\n }\n const provider = getProviderOrThrow(providerId);\n\n const oauthConfig = provider as OAuthMaterializedConfig;\n const { redirect, cookies, signature } =\n await createOAuthAuthorizationURL(\n providerId,\n oauthConfig.provider,\n oauthConfig,\n );\n\n await callVerifierSignature(ctx, {\n verifier,\n signature,\n });\n\n const redirectTo = url.searchParams.get(\"redirectTo\");\n if (redirectTo !== null) {\n cookies.push(redirectToParamCookie(providerId, redirectTo));\n }\n\n const headers = new Headers({ Location: redirect });\n for (const { name, value, options } of cookies) {\n headers.append(\n \"Set-Cookie\",\n serializeCookie(name, value, options as any),\n );\n }\n\n return new Response(null, { status: 302, headers });\n }),\n handleCallback: async (ctx, request) => {\n const url = new URL(request.url);\n const providerId = new URL(request.url).pathname\n .split(\"/\")\n .at(-1);\n if (!providerId) {\n throw new AuthError(\"OAUTH_MISSING_PROVIDER\").toConvexError();\n }\n logWithLevel(\n LOG_LEVELS.DEBUG,\n \"Handling OAuth callback for provider:\",\n providerId,\n );\n const provider = getProviderOrThrow(providerId);\n\n const cookies = getCookies(request);\n\n const maybeRedirectTo = useRedirectToParam(provider.id, cookies);\n\n const destinationUrl = await redirectAbsoluteUrl(config, {\n redirectTo: maybeRedirectTo?.redirectTo,\n });\n\n const params = url.searchParams;\n\n if (\n request.headers.get(\"Content-Type\") ===\n \"application/x-www-form-urlencoded\"\n ) {\n const formData = await request.formData();\n formData.forEach((value, key) => {\n if (typeof value === \"string\") {\n params.append(key, value);\n }\n });\n }\n\n return Fx.run(\n Fx.from({\n ok: async () => {\n const oauthConfig = provider as OAuthMaterializedConfig;\n const result = await Fx.run(\n handleOAuthCallback(\n providerId,\n oauthConfig.provider,\n oauthConfig,\n Object.fromEntries(params.entries()),\n cookies,\n ),\n );\n const oauthCookies = result.cookies;\n const { id: profileId, ...profileData } = result.profile;\n const { signature } = result;\n\n const verificationCode = await callUserOAuth(ctx, {\n provider: providerId,\n providerAccountId: profileId,\n profile: profileData,\n signature,\n });\n\n const redirUrl = setURLSearchParam(\n destinationUrl,\n \"code\",\n verificationCode,\n );\n const redirHeaders = new Headers({ Location: redirUrl });\n redirHeaders.set(\"Cache-Control\", \"must-revalidate\");\n for (const { name, value, options } of [\n ...oauthCookies,\n ...(maybeRedirectTo !== null\n ? [maybeRedirectTo.updatedCookie]\n : []),\n ] as any) {\n redirHeaders.append(\n \"Set-Cookie\",\n serializeCookie(name, value, options),\n );\n }\n return new Response(null, {\n status: 302,\n headers: redirHeaders,\n });\n },\n err: (error) => error,\n }).pipe(\n Fx.recover((error) => {\n logError(error);\n const respHeaders = new Headers({\n Location: destinationUrl,\n });\n for (const { name, value, options } of maybeRedirectTo !==\n null\n ? [maybeRedirectTo.updatedCookie]\n : []) {\n respHeaders.append(\n \"Set-Cookie\",\n serializeCookie(name, value, options),\n );\n }\n return Fx.succeed(\n new Response(null, {\n status: 302,\n headers: respHeaders,\n }),\n );\n }),\n ),\n );\n },\n });\n }\n },\n\n /**\n * Wrap an HTTP action handler with Bearer token authentication.\n *\n * Extracts the `Authorization: Bearer <key>` header, verifies the\n * API key via `auth.key.verify()`, and injects `ctx.key` with the\n * verified key info. Returns structured JSON error responses for\n * missing/invalid/revoked/expired/rate-limited keys.\n *\n * If the handler returns a plain object, it is auto-wrapped in a\n * `200 JSON` response. If it returns a `Response`, CORS headers\n * are merged and the response is passed through.\n *\n * ```ts\n * const handler = auth.http.action(async (ctx, request) => {\n * const data = await ctx.runQuery(api.data.get, { userId: ctx.key.userId });\n * return { data };\n * });\n * http.route({ path: \"/api/data\", method: \"GET\", handler });\n * ```\n *\n * @param handler - Receives enriched `ctx` (with `ctx.key`) and the raw `Request`.\n * @param options.scope - Optional scope check; returns 403 if the key lacks permission.\n * @param options.cors - CORS config; defaults to permissive (`*`).\n */\n action: createHttpAction(auth),\n\n /**\n * Register a Bearer-authenticated route **and** its OPTIONS preflight\n * in a single call.\n *\n * ```ts\n * auth.http.route(http, {\n * path: \"/api/messages\",\n * method: \"POST\",\n * handler: async (ctx, request) => {\n * const { body } = await request.json();\n * await ctx.runMutation(internal.messages.sendAsUser, {\n * userId: ctx.key.userId,\n * body,\n * });\n * return { success: true };\n * },\n * });\n * ```\n *\n * @param http - The Convex HTTP router.\n * @param routeConfig.path - The URL path to match.\n * @param routeConfig.method - HTTP method (GET, POST, PUT, PATCH, DELETE).\n * @param routeConfig.handler - Receives enriched `ctx` (with `ctx.key`) and the raw `Request`.\n * @param routeConfig.scope - Optional scope check; returns 403 if the key lacks permission.\n * @param routeConfig.cors - CORS config; defaults to permissive (`*`).\n */\n route: createHttpRoute(createHttpAction(auth)),\n },\n };\n\n const enrichCtx = <DataModel extends GenericDataModel>(\n ctx: GenericActionCtx<DataModel>,\n ) => ({\n ...ctx,\n auth: {\n ...ctx.auth,\n config,\n account: auth.account,\n session: auth.session,\n member: auth.member,\n provider: auth.provider,\n },\n });\n\n return {\n /**\n * Helper for configuring HTTP actions.\n */\n auth,\n /**\n * Action called by the client to sign the user in.\n *\n * Also used for refreshing the session.\n */\n signIn: actionGeneric({\n args: {\n provider: v.optional(v.string()),\n params: v.optional(v.any()),\n verifier: v.optional(v.string()),\n refreshToken: v.optional(v.string()),\n calledBy: v.optional(v.string()),\n },\n handler: async (ctx, args): Promise<SignInActionResult> => {\n if (args.calledBy !== undefined) {\n logWithLevel(\"INFO\", `\\`auth:signIn\\` called by ${args.calledBy}`);\n }\n const provider =\n args.provider !== undefined\n ? getProviderOrThrow(args.provider)\n : null;\n const result = await signInImpl(enrichCtx(ctx), provider, args, {\n generateTokens: true,\n allowExtraProviders: false,\n });\n return Fx.run(\n Fx.match(result, result.kind, {\n redirect: (r) =>\n Fx.succeed({\n kind: \"redirect\" as const,\n redirect: r.redirect,\n verifier: r.verifier,\n }),\n signedIn: (r) =>\n Fx.succeed({\n kind: \"signedIn\" as const,\n tokens: r.signedIn?.tokens ?? null,\n }),\n refreshTokens: (r) =>\n Fx.succeed({\n kind: \"signedIn\" as const,\n tokens: r.signedIn?.tokens ?? null,\n }),\n started: () => Fx.succeed({ kind: \"started\" as const }),\n passkeyOptions: (r) =>\n Fx.succeed({\n kind: \"passkeyOptions\" as const,\n options: r.options,\n verifier: r.verifier,\n }),\n totpRequired: (r) =>\n Fx.succeed({\n kind: \"totpRequired\" as const,\n verifier: r.verifier,\n }),\n totpSetup: (r) =>\n Fx.succeed({\n kind: \"totpSetup\" as const,\n totpSetup: {\n uri: r.uri,\n secret: r.secret,\n totpId: r.totpId,\n },\n verifier: r.verifier,\n }),\n deviceCode: (r) =>\n Fx.succeed({\n kind: \"deviceCode\" as const,\n deviceCode: {\n deviceCode: r.deviceCode,\n userCode: r.userCode,\n verificationUri: r.verificationUri,\n verificationUriComplete: r.verificationUriComplete,\n expiresIn: r.expiresIn,\n interval: r.interval,\n },\n }),\n }),\n );\n },\n }),\n /**\n * Action called by the client to invalidate the current session.\n */\n signOut: actionGeneric({\n args: {},\n handler: async (ctx) => {\n await callSignOut(ctx);\n },\n }),\n\n /**\n * Internal mutation used by the library to read and write\n * to the database during signin and signout.\n */\n store: internalMutationGeneric({\n args: storeArgs,\n handler: async (ctx: MutationCtx, args) => {\n return storeImpl(ctx, args, getProviderOrThrow, config);\n },\n }),\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"runtime.js","names":["serializeCookie"],"sources":["../../src/server/runtime.ts"],"sourcesContent":["import { Fx } from \"@robelest/fx\";\nimport { Cv } from \"@robelest/fx/convex\";\nimport {\n GenericActionCtx,\n GenericDataModel,\n HttpRouter,\n actionGeneric,\n internalMutationGeneric,\n} from \"convex/server\";\nimport { v } from \"convex/values\";\nimport { serialize as serializeCookie } from \"cookie\";\n\nimport { configDefaults, listAvailableProviders } from \"./config\";\nimport { redirectToParamCookie, useRedirectToParam } from \"./cookies\";\nimport { createCoreDomains } from \"./core\";\nimport { GetProviderOrThrowFunc } from \"./crypto\";\nimport {\n getOidcConfig,\n getPublicOidcConfig,\n getSamlConfig,\n upsertProtocolConfig,\n withOidcSecretState,\n} from \"./enterprise/config\";\nimport { createEnterpriseDomain } from \"./enterprise/domain\";\nimport { addEnterpriseHttpRuntime } from \"./enterprise/http\";\nimport {\n normalizeEnterprisePolicy,\n patchEnterprisePolicy,\n} from \"./enterprise/policy\";\nimport {\n createServiceProviderMetadata,\n getSamlServiceProviderOptions,\n parseSamlIdpMetadata,\n} from \"./enterprise/saml\";\nimport { parseScimPath } from \"./enterprise/scim\";\nimport {\n enterpriseOidcProviderId,\n getEnterpriseOidcUrls,\n isEnterpriseSamlSourceActive,\n normalizeDomain,\n} from \"./enterprise/shared\";\nimport {\n addAuthRoutes,\n addOpenIdRoutes,\n convertErrorsToResponse,\n createHttpAction,\n createHttpContext,\n createHttpRoute,\n getCookies,\n} from \"./http\";\nimport {\n callCreateAccountFromCredentials,\n callInvalidateSessions,\n callModifyAccount,\n callRetrieveAccountWithCredentials,\n callSignOut,\n callUserOAuth,\n callVerifierSignature,\n storeArgs,\n storeImpl,\n} from \"./mutations/index\";\nimport { createOAuthAuthorizationURL, handleOAuthCallback } from \"./oauth\";\nimport { redirectAbsoluteUrl, setURLSearchParam } from \"./redirects\";\nimport { signInImpl } from \"./signin\";\nimport type {\n ConvexAuthConfig,\n FunctionReferenceFromExport,\n OAuthMaterializedConfig,\n Tokens,\n} from \"./types\";\nimport { MutationCtx } from \"./types\";\nimport {\n decryptSecret,\n encryptSecret,\n generateRandomString,\n LOG_LEVELS,\n logError,\n logWithLevel,\n sha256,\n} from \"./utils\";\nimport { requireEnv } from \"./utils\";\n\nconst ENTERPRISE_OIDC_CLIENT_SECRET_KIND = \"oidc_client_secret\" as const;\n\n/**\n * The type of the signIn Convex Action returned from the auth() helper.\n *\n * This type is exported for implementors of other client integrations.\n * However it is not stable, and may change until this library reaches 1.0.\n *\n * @internal\n */\nexport type SignInAction = FunctionReferenceFromExport<\n ReturnType<typeof Auth>[\"signIn\"]\n>;\n\n/** @internal */\nexport type SignInActionResult =\n | { kind: \"signedIn\"; tokens: Tokens | null }\n | { kind: \"redirect\"; redirect: string; verifier: string }\n | { kind: \"started\" }\n | { kind: \"passkeyOptions\"; options: Record<string, any>; verifier: string }\n | { kind: \"totpRequired\"; verifier: string }\n | {\n kind: \"totpSetup\";\n totpSetup: { uri: string; secret: string; totpId: string };\n verifier: string;\n }\n | {\n kind: \"deviceCode\";\n deviceCode: {\n deviceCode: string;\n userCode: string;\n verificationUri: string;\n verificationUriComplete: string;\n expiresIn: number;\n interval: number;\n };\n };\n/**\n * The type of the signOut Convex Action returned from the auth() helper.\n *\n * This type is exported for implementors of other client integrations.\n * However it is not stable, and may change until this library reaches 1.0.\n *\n * @internal\n */\nexport type SignOutAction = FunctionReferenceFromExport<\n ReturnType<typeof Auth>[\"signOut\"]\n>;\n\n/**\n * Configure the Convex Auth library. Returns an object with\n * functions and `auth` helper. You must export the functions\n * from `convex/auth.ts` to make them callable:\n *\n * ```ts filename=\"convex/auth.ts\"\n * import { createAuth } from \"@robelest/convex-auth/component\";\n * import { components } from \"./_generated/api\";\n *\n * export const auth = createAuth(components.auth, {\n * providers: [],\n * });\n * export const { signIn, signOut, store } = auth;\n * ```\n *\n * @returns An object with fields you should reexport from your\n * `convex/auth.ts` file.\n */\nexport function Auth(config_: ConvexAuthConfig) {\n const config = configDefaults(config_);\n const hasOAuth = config.providers.some(\n (provider) => provider.type === \"oauth\",\n );\n const hasSSO = config.providers.some((provider) => provider.type === \"sso\");\n const getProviderOrThrow: GetProviderOrThrowFunc = (\n id: string,\n allowExtraProviders: boolean = false,\n ) => {\n const provider =\n config.providers.find(\n (configuredProvider) => configuredProvider.id === id,\n ) ??\n (allowExtraProviders\n ? config.extraProviders.find(\n (configuredProvider) => configuredProvider.id === id,\n )\n : undefined);\n if (provider === undefined) {\n const detail =\n `Provider \\`${id}\\` is not configured, ` +\n `available providers are ${listAvailableProviders(config, allowExtraProviders)}.`;\n logWithLevel(LOG_LEVELS.ERROR, detail);\n throw Cv.error({\n code: \"PROVIDER_NOT_CONFIGURED\",\n message: detail,\n provider: id,\n });\n }\n return provider;\n };\n type ComponentCtx = Pick<\n GenericActionCtx<GenericDataModel>,\n \"runQuery\" | \"runMutation\"\n >;\n type ComponentReadCtx = Pick<GenericActionCtx<GenericDataModel>, \"runQuery\">;\n const getEnterpriseSecret = async (\n ctx: ComponentReadCtx | ComponentCtx,\n enterpriseId: string,\n kind: typeof ENTERPRISE_OIDC_CLIENT_SECRET_KIND,\n ) => {\n return await ctx.runQuery(config.component.public.enterpriseSecretGet, {\n enterpriseId,\n kind,\n });\n };\n const getEnterpriseOidcConfigWithSecret = async (\n ctx: ComponentReadCtx | ComponentCtx,\n enterprise: { _id: string; config?: unknown },\n ): Promise<Record<string, any>> => {\n const oidc = getOidcConfig(enterprise.config);\n const secret = await getEnterpriseSecret(\n ctx,\n enterprise._id,\n ENTERPRISE_OIDC_CLIENT_SECRET_KIND,\n );\n return {\n ...oidc,\n ...(secret\n ? { clientSecret: await decryptSecret(secret.ciphertext) }\n : {}),\n };\n };\n const INVITE_TOKEN_ALPHABET =\n \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\";\n const INVITE_TOKEN_LENGTH = 48;\n\n const enterpriseNotFoundError = \"Enterprise not found.\";\n\n const ENTERPRISE_CONTROL_ROUTE_BASE = \"/api/auth/sso\";\n\n const getPolicyFromEnterprise = (enterprise: { policy?: unknown }) =>\n normalizeEnterprisePolicy(enterprise.policy);\n\n const loadEnterpriseOrThrow = async (\n ctx: ComponentReadCtx,\n enterpriseId: string,\n ) => {\n const enterprise = await ctx.runQuery(\n config.component.public.enterpriseGet,\n {\n enterpriseId,\n },\n );\n if (!enterprise) {\n throw Cv.error({\n code: \"INVALID_PARAMETERS\",\n message: enterpriseNotFoundError,\n });\n }\n return enterprise;\n };\n\n const loadActiveEnterpriseOrThrow = async (\n ctx: ComponentReadCtx,\n enterpriseId: string,\n ) => {\n const enterprise = await loadEnterpriseOrThrow(ctx, enterpriseId);\n if (enterprise.status !== \"active\") {\n throw Cv.error({\n code: \"INVALID_PARAMETERS\",\n message: \"Enterprise connection is not active.\",\n });\n }\n return enterprise;\n };\n\n const loadActiveEnterpriseSamlOrThrow = async (\n ctx: ComponentReadCtx,\n enterpriseId: string,\n ) => {\n const enterprise = await loadEnterpriseOrThrow(ctx, enterpriseId);\n const loaded = {\n source: {\n kind: \"enterprise\" as const,\n id: enterpriseId,\n },\n config: enterprise.config,\n status: enterprise.status,\n enterprise,\n };\n if (!isEnterpriseSamlSourceActive(loaded)) {\n throw Cv.error({\n code: \"INVALID_PARAMETERS\",\n message: \"Enterprise connection is not active.\",\n });\n }\n const saml = getSamlConfig(loaded.config);\n if (!saml.idp?.metadataXml) {\n throw Cv.error({\n code: \"PROVIDER_NOT_CONFIGURED\",\n message: \"SAML is not configured for this enterprise.\",\n });\n }\n return { loaded, enterprise, saml };\n };\n\n const loadEnterpriseOidcOrThrow = async (\n ctx: ComponentReadCtx,\n enterpriseId: string,\n ) => {\n const enterprise = await loadActiveEnterpriseOrThrow(ctx, enterpriseId);\n const oidc = await getEnterpriseOidcConfigWithSecret(ctx, enterprise);\n if (oidc.enabled !== true) {\n throw Cv.error({\n code: \"PROVIDER_NOT_CONFIGURED\",\n message: \"OIDC is not configured for this enterprise.\",\n });\n }\n return { enterprise, oidc };\n };\n\n const validateEnterprisePolicy = (\n policy: ReturnType<typeof normalizeEnterprisePolicy>,\n ) => {\n const checks: Array<{\n name: string;\n ok: boolean;\n message?: string;\n }> = [];\n\n checks.push({ name: \"policy_version\", ok: policy.version === 1 });\n checks.push({\n name: \"jit_default_role_ids_present\",\n ok:\n policy.provisioning.jit.mode !== \"createUserAndMembership\" ||\n policy.provisioning.jit.defaultRoleIds.length > 0,\n message:\n policy.provisioning.jit.mode === \"createUserAndMembership\" &&\n policy.provisioning.jit.defaultRoleIds.length === 0\n ? \"At least one default roleId is required when JIT membership provisioning is enabled.\"\n : undefined,\n });\n checks.push({\n name: \"jit_default_role_ids_known\",\n ok: policy.provisioning.jit.defaultRoleIds.every(\n (roleId) => config.authorization.roles[roleId] !== undefined,\n ),\n message: policy.provisioning.jit.defaultRoleIds.every(\n (roleId) => config.authorization.roles[roleId] !== undefined,\n )\n ? undefined\n : \"JIT defaultRoleIds contains unknown roleIds.\",\n });\n checks.push({\n name: \"scim_reuse_supported\",\n ok:\n policy.provisioning.scimReuse.user === \"externalId\" ||\n policy.provisioning.scimReuse.user === \"none\",\n });\n\n return checks;\n };\n\n const recordEnterpriseAuditEvent = async (\n ctx: ComponentCtx,\n data: {\n enterpriseId: string;\n groupId: string;\n eventType: string;\n actorType: \"user\" | \"system\" | \"scim\" | \"api_key\" | \"webhook\";\n actorId?: string;\n subjectType: string;\n subjectId?: string;\n ok: boolean;\n requestId?: string;\n ip?: string;\n metadata?: Record<string, unknown>;\n },\n ) => {\n const { ok, ...rest } = data;\n return (await ctx.runMutation(\n config.component.public.enterpriseAuditEventCreate,\n {\n ...rest,\n status: ok ? \"success\" : \"failure\",\n occurredAt: Date.now(),\n },\n )) as string;\n };\n\n const emitEnterpriseWebhookDeliveries = async (\n ctx: ComponentCtx,\n data: {\n enterpriseId: string;\n eventType: string;\n payload: Record<string, unknown>;\n auditEventId?: string;\n },\n ) => {\n const endpoints = await ctx.runQuery(\n config.component.public.enterpriseWebhookEndpointList,\n { enterpriseId: data.enterpriseId },\n );\n for (const endpoint of endpoints) {\n if (\n endpoint.status !== \"active\" ||\n !endpoint.subscriptions.includes(data.eventType)\n ) {\n continue;\n }\n await ctx.runMutation(\n config.component.public.enterpriseWebhookDeliveryEnqueue,\n {\n enterpriseId: data.enterpriseId,\n endpointId: endpoint._id,\n auditEventId: data.auditEventId,\n eventType: data.eventType,\n payload: data.payload,\n nextAttemptAt: Date.now(),\n },\n );\n }\n };\n\n const getEnterpriseScimContext = async (\n ctx: ComponentReadCtx,\n request: Request,\n ) => {\n const authHeader = request.headers.get(\"Authorization\");\n if (!authHeader?.startsWith(\"Bearer \")) {\n throw Cv.error({\n code: \"MISSING_BEARER_TOKEN\",\n message: \"Missing or malformed Authorization: Bearer header.\",\n });\n }\n const token = authHeader.slice(7);\n const scimConfig = await ctx.runQuery(\n config.component.public.enterpriseScimConfigGetByTokenHash,\n { tokenHash: await sha256(token) },\n );\n if (!scimConfig || scimConfig.status !== \"active\") {\n throw Cv.error({\n code: \"INVALID_API_KEY\",\n message: \"Invalid SCIM token.\",\n });\n }\n const parsedPath = parseScimPath(new URL(request.url).pathname);\n if (parsedPath.enterpriseId !== scimConfig.enterpriseId) {\n throw Cv.error({\n code: \"INVALID_API_KEY\",\n message: \"SCIM token/tenant mismatch.\",\n });\n }\n const enterprise = await ctx.runQuery(\n config.component.public.enterpriseGet,\n {\n enterpriseId: scimConfig.enterpriseId,\n },\n );\n if (enterprise === null) {\n throw Cv.error({\n code: \"INVALID_PARAMETERS\",\n message: \"Enterprise not found.\",\n });\n }\n return { scimConfig, enterprise, parsedPath };\n };\n\n let auth: any;\n auth = {\n ...createCoreDomains({\n config,\n getAuth: () => auth,\n callInvalidateSessions,\n callCreateAccountFromCredentials,\n callRetrieveAccountWithCredentials,\n callModifyAccount,\n getEnrichCtx: () => enrichCtx,\n inviteTokenAlphabet: INVITE_TOKEN_ALPHABET,\n inviteTokenLength: INVITE_TOKEN_LENGTH,\n }),\n /**\n * SSO namespace — enterprise SSO connection management, domain, OIDC,\n * SAML, SCIM, audit, and webhook helpers.\n */\n sso: createEnterpriseDomain({\n config,\n getAuth: () => auth,\n normalizeEnterprisePolicy,\n normalizeDomain,\n getEnterpriseSecret,\n loadEnterpriseOrThrow,\n validateEnterprisePolicy,\n recordEnterpriseAuditEvent,\n emitEnterpriseWebhookDeliveries,\n enterpriseNotFoundError,\n ENTERPRISE_OIDC_CLIENT_SECRET_KIND,\n requireEnv,\n generateRandomString,\n INVITE_TOKEN_ALPHABET,\n sha256,\n encryptSecret,\n upsertProtocolConfig,\n parseSamlIdpMetadata,\n createServiceProviderMetadata,\n getSamlServiceProviderOptions,\n getPublicOidcConfig,\n withOidcSecretState,\n getOidcConfig,\n getEnterpriseOidcUrls,\n enterpriseOidcProviderId,\n getPolicyFromEnterprise,\n patchEnterprisePolicy,\n }),\n };\n\n // HTTP wiring stays local to the factory because it still depends on a\n // dense mix of OAuth, SAML, SCIM, cookie, and response helpers.\n auth.http = {\n /**\n * Register core HTTP routes for JWT verification and OAuth sign-in.\n *\n * ```ts\n * import { httpRouter } from \"convex/server\";\n * import { auth } from \"./auth\";\n *\n * const http = httpRouter();\n *\n * auth.http.add(http);\n *\n * export default http;\n * ```\n *\n * The following routes are handled always:\n *\n * - `/.well-known/openid-configuration`\n * - `/.well-known/jwks.json`\n *\n * The following routes are handled if OAuth is configured:\n *\n * - `/api/auth/signin/*`\n * - `/api/auth/callback/*`\n *\n * @param http your HTTP router\n */\n add: (http: HttpRouter) => {\n addOpenIdRoutes(http, {\n getIssuer: () => requireEnv(\"CONVEX_SITE_URL\"),\n getJwks: () => requireEnv(\"JWKS\"),\n });\n\n addEnterpriseHttpRuntime({\n http,\n hasSSO,\n auth,\n config,\n routeBase: ENTERPRISE_CONTROL_ROUTE_BASE,\n requireEnv,\n loadActiveEnterpriseSamlOrThrow,\n loadEnterpriseOidcOrThrow,\n getEnterpriseScimContext,\n getPolicyFromEnterprise,\n normalizeEnterprisePolicy,\n recordEnterpriseAuditEvent,\n emitEnterpriseWebhookDeliveries,\n generateRandomString,\n inviteTokenAlphabet: INVITE_TOKEN_ALPHABET,\n callUserOAuth,\n callVerifierSignature,\n });\n\n if (hasOAuth) {\n addAuthRoutes(http, {\n handleSignIn: convertErrorsToResponse(400, async (ctx, request) => {\n const url = new URL(request.url);\n const pathParts = url.pathname.split(\"/\");\n const providerId = pathParts[pathParts.length - 1]!;\n if (providerId === null) {\n throw Cv.error({\n code: \"OAUTH_MISSING_PROVIDER\",\n message: \"Missing OAuth provider ID.\",\n });\n }\n const verifier = url.searchParams.get(\"code\");\n if (verifier === null) {\n throw Cv.error({\n code: \"OAUTH_MISSING_VERIFIER\",\n message: \"Missing sign-in verifier.\",\n });\n }\n const provider = getProviderOrThrow(providerId);\n\n const oauthConfig = provider as OAuthMaterializedConfig;\n const { redirect, cookies, signature } =\n await createOAuthAuthorizationURL(\n providerId,\n oauthConfig.provider,\n oauthConfig,\n );\n\n await callVerifierSignature(ctx, {\n verifier,\n signature,\n });\n\n const redirectTo = url.searchParams.get(\"redirectTo\");\n if (redirectTo !== null) {\n cookies.push(redirectToParamCookie(providerId, redirectTo));\n }\n\n const headers = new Headers({ Location: redirect });\n for (const { name, value, options } of cookies) {\n headers.append(\n \"Set-Cookie\",\n serializeCookie(name, value, options as any),\n );\n }\n\n return new Response(null, { status: 302, headers });\n }),\n handleCallback: async (ctx, request) => {\n const url = new URL(request.url);\n const callbackPathParts = new URL(request.url).pathname.split(\"/\");\n const providerId = callbackPathParts[callbackPathParts.length - 1];\n if (!providerId) {\n throw Cv.error({\n code: \"OAUTH_MISSING_PROVIDER\",\n message: \"Missing OAuth provider ID.\",\n });\n }\n logWithLevel(\n LOG_LEVELS.DEBUG,\n \"Handling OAuth callback for provider:\",\n providerId,\n );\n const provider = getProviderOrThrow(providerId);\n\n const cookies = getCookies(request);\n\n const maybeRedirectTo = useRedirectToParam(provider.id, cookies);\n\n const destinationUrl = await redirectAbsoluteUrl(config, {\n redirectTo: maybeRedirectTo?.redirectTo,\n });\n\n const params = url.searchParams;\n\n if (\n request.headers.get(\"Content-Type\") ===\n \"application/x-www-form-urlencoded\"\n ) {\n const formData = await request.formData();\n formData.forEach((value, key) => {\n if (typeof value === \"string\") {\n params.append(key, value);\n }\n });\n }\n\n return Fx.run(\n Fx.from({\n ok: async () => {\n const oauthConfig = provider as OAuthMaterializedConfig;\n const result = await Fx.run(\n handleOAuthCallback(\n providerId,\n oauthConfig.provider,\n oauthConfig,\n Object.fromEntries(params.entries()),\n cookies,\n ),\n );\n const oauthCookies = result.cookies;\n const { id: profileId, ...profileData } = result.profile;\n const { signature } = result;\n\n const verificationCode = await callUserOAuth(ctx, {\n provider: providerId,\n providerAccountId: profileId,\n profile: profileData,\n signature,\n });\n\n const redirUrl = setURLSearchParam(\n destinationUrl,\n \"code\",\n verificationCode,\n );\n const redirHeaders = new Headers({ Location: redirUrl });\n redirHeaders.set(\"Cache-Control\", \"must-revalidate\");\n for (const { name, value, options } of [\n ...oauthCookies,\n ...(maybeRedirectTo !== null\n ? [maybeRedirectTo.updatedCookie]\n : []),\n ] as any) {\n redirHeaders.append(\n \"Set-Cookie\",\n serializeCookie(name, value, options),\n );\n }\n return new Response(null, {\n status: 302,\n headers: redirHeaders,\n });\n },\n err: (error) => error,\n }).pipe(\n Fx.recover((error) => {\n logError(error);\n const respHeaders = new Headers({\n Location: destinationUrl,\n });\n for (const { name, value, options } of maybeRedirectTo !== null\n ? [maybeRedirectTo.updatedCookie]\n : []) {\n respHeaders.append(\n \"Set-Cookie\",\n serializeCookie(name, value, options),\n );\n }\n return Fx.succeed(\n new Response(null, {\n status: 302,\n headers: respHeaders,\n }),\n );\n }),\n ),\n );\n },\n });\n }\n },\n\n /**\n * Resolve mixed HTTP auth for a raw `httpAction`.\n *\n * Checks session auth first, then falls back to `Authorization: Bearer sk_*`\n * API keys. This is the low-level helper for endpoints that intentionally\n * accept either browser sessions or API keys.\n * Pass `{ optional: true }` to get a null-shaped auth object instead of a\n * `NOT_SIGNED_IN` error.\n *\n * ```ts\n * http.route({\n * path: \"/api/data\",\n * method: \"GET\",\n * handler: httpAction(async (ctx, request) => {\n * const authContext = await auth.http.context(ctx, request);\n * return Response.json({\n * userId: authContext.userId,\n * source: authContext.source,\n * });\n * }),\n * });\n * ```\n */\n context: createHttpContext(auth),\n\n /**\n * Wrap an HTTP action handler with Bearer token authentication.\n *\n * Extracts the `Authorization: Bearer <key>` header, verifies the\n * API key via `auth.key.verify()`, and injects `ctx.key` with the\n * verified key info. Returns structured JSON error responses for\n * missing/invalid/revoked/expired/rate-limited keys.\n *\n * If the handler returns a plain object, it is auto-wrapped in a\n * `200 JSON` response. If it returns a `Response`, CORS headers\n * are merged and the response is passed through.\n *\n * ```ts\n * const handler = auth.http.action(async (ctx, request) => {\n * const data = await ctx.runQuery(api.data.get, { userId: ctx.key.userId });\n * return { data };\n * });\n * http.route({ path: \"/api/data\", method: \"GET\", handler });\n * ```\n *\n * @param handler - Receives enriched `ctx` (with `ctx.key`) and the raw `Request`.\n * @param options.scope - Optional scope check; returns 403 if the key lacks permission.\n * @param options.cors - CORS config; defaults to permissive (`*`).\n */\n action: createHttpAction(auth),\n\n /**\n * Register a Bearer-authenticated route **and** its OPTIONS preflight\n * in a single call.\n *\n * ```ts\n * auth.http.route(http, {\n * path: \"/api/messages\",\n * method: \"POST\",\n * handler: async (ctx, request) => {\n * const { body } = await request.json();\n * await ctx.runMutation(internal.messages.sendAsUser, {\n * userId: ctx.key.userId,\n * body,\n * });\n * return { success: true };\n * },\n * });\n * ```\n *\n * @param http - The Convex HTTP router.\n * @param routeConfig.path - The URL path to match.\n * @param routeConfig.method - HTTP method (GET, POST, PUT, PATCH, DELETE).\n * @param routeConfig.handler - Receives enriched `ctx` (with `ctx.key`) and the raw `Request`.\n * @param routeConfig.scope - Optional scope check; returns 403 if the key lacks permission.\n * @param routeConfig.cors - CORS config; defaults to permissive (`*`).\n */\n route: createHttpRoute(createHttpAction(auth)),\n };\n\n const enrichCtx = <DataModel extends GenericDataModel>(\n ctx: GenericActionCtx<DataModel>,\n ) => ({\n ...ctx,\n auth: {\n ...ctx.auth,\n config,\n account: auth.account,\n session: auth.session,\n member: auth.member,\n provider: auth.provider,\n },\n });\n\n return {\n /**\n * Helper for configuring HTTP actions.\n */\n auth,\n /**\n * Action called by the client to sign the user in.\n *\n * Also used for refreshing the session.\n */\n signIn: actionGeneric({\n args: {\n provider: v.optional(v.string()),\n params: v.optional(v.any()),\n verifier: v.optional(v.string()),\n refreshToken: v.optional(v.string()),\n calledBy: v.optional(v.string()),\n },\n handler: async (ctx, args): Promise<SignInActionResult> => {\n if (args.calledBy !== undefined) {\n logWithLevel(\"INFO\", `\\`auth:signIn\\` called by ${args.calledBy}`);\n }\n const provider =\n args.provider !== undefined\n ? getProviderOrThrow(args.provider)\n : null;\n const result = await signInImpl(enrichCtx(ctx), provider, args, {\n generateTokens: true,\n allowExtraProviders: false,\n });\n return Fx.run(\n Fx.match(result, result.kind, {\n redirect: (r) =>\n Fx.succeed({\n kind: \"redirect\" as const,\n redirect: r.redirect,\n verifier: r.verifier,\n }),\n signedIn: (r) =>\n Fx.succeed({\n kind: \"signedIn\" as const,\n tokens: r.signedIn?.tokens ?? null,\n }),\n refreshTokens: (r) =>\n Fx.succeed({\n kind: \"signedIn\" as const,\n tokens: r.signedIn?.tokens ?? null,\n }),\n started: () => Fx.succeed({ kind: \"started\" as const }),\n passkeyOptions: (r) =>\n Fx.succeed({\n kind: \"passkeyOptions\" as const,\n options: r.options,\n verifier: r.verifier,\n }),\n totpRequired: (r) =>\n Fx.succeed({\n kind: \"totpRequired\" as const,\n verifier: r.verifier,\n }),\n totpSetup: (r) =>\n Fx.succeed({\n kind: \"totpSetup\" as const,\n totpSetup: {\n uri: r.uri,\n secret: r.secret,\n totpId: r.totpId,\n },\n verifier: r.verifier,\n }),\n deviceCode: (r) =>\n Fx.succeed({\n kind: \"deviceCode\" as const,\n deviceCode: {\n deviceCode: r.deviceCode,\n userCode: r.userCode,\n verificationUri: r.verificationUri,\n verificationUriComplete: r.verificationUriComplete,\n expiresIn: r.expiresIn,\n interval: r.interval,\n },\n }),\n }),\n );\n },\n }),\n /**\n * Action called by the client to invalidate the current session.\n */\n signOut: actionGeneric({\n args: {},\n handler: async (ctx) => {\n await callSignOut(ctx);\n },\n }),\n\n /**\n * Internal mutation used by the library to read and write\n * to the database during signin and signout.\n */\n store: internalMutationGeneric({\n args: storeArgs,\n handler: async (ctx: MutationCtx, args) => {\n return storeImpl(ctx, args, getProviderOrThrow, config);\n },\n }),\n };\n}\n"],"mappings":"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"}
@@ -1,4 +1,3 @@
1
- import { AuthError } from "./authError.js";
2
1
  import { generateRandomString, requireEnv } from "./utils.js";
3
2
  import { callCreateVerificationCode } from "./mutations/code.js";
4
3
  import { callRefreshSession } from "./mutations/refresh.js";
@@ -12,13 +11,14 @@ import { handlePasskeyFx } from "./passkey.js";
12
11
  import { redirectAbsoluteUrl, setURLSearchParam } from "./redirects.js";
13
12
  import { handleTotp } from "./totp.js";
14
13
  import { Fx } from "@robelest/fx";
14
+ import { Cv } from "@robelest/fx/convex";
15
15
 
16
16
  //#region src/server/signin.ts
17
17
  const DEFAULT_EMAIL_VERIFICATION_CODE_DURATION_S = 3600 * 24;
18
18
  /** @internal */
19
19
  async function signInImpl(ctx, provider, args, options) {
20
20
  const fx = signInFx(ctx, provider, args, options);
21
- return Fx.run(fx.pipe(Fx.recover((e) => Fx.fatal(e.toConvexError()))));
21
+ return Fx.run(fx.pipe(Fx.recover((e) => Fx.fatal(e))));
22
22
  }
23
23
  /**
24
24
  * Core sign-in pipeline as an Fx generator.
@@ -48,7 +48,10 @@ function signInFx(ctx, provider, args, options) {
48
48
  allowExtraProviders: options.allowExtraProviders
49
49
  }))
50
50
  };
51
- const resolvedProvider = yield* provider != null ? Fx.succeed(provider) : Fx.fail(new AuthError("SIGN_IN_MISSING_PARAMS"));
51
+ const resolvedProvider = yield* provider != null ? Fx.succeed(provider) : Cv.fail({
52
+ code: "SIGN_IN_MISSING_PARAMS",
53
+ message: "Cannot sign in: missing provider, code, or refresh token."
54
+ });
52
55
  return yield* Fx.match(resolvedProvider).on("type", {
53
56
  email: (p) => handleEmailAndPhoneProviderFx(ctx, p, args, options),
54
57
  phone: (p) => handleEmailAndPhoneProviderFx(ctx, p, args, options),
@@ -72,12 +75,18 @@ function handleEmailAndPhoneProviderFx(ctx, provider, args, options) {
72
75
  }));
73
76
  return {
74
77
  kind: "signedIn",
75
- signedIn: yield* result != null ? Fx.succeed(result) : Fx.fail(new AuthError("INVALID_VERIFICATION_CODE"))
78
+ signedIn: yield* result != null ? Fx.succeed(result) : Cv.fail({
79
+ code: "INVALID_VERIFICATION_CODE",
80
+ message: "Invalid or expired verification code."
81
+ })
76
82
  };
77
83
  }
78
84
  const code = provider.generateVerificationToken ? yield* Fx.from({
79
85
  ok: async () => provider.generateVerificationToken(),
80
- err: () => new AuthError("INTERNAL_ERROR", "Failed to generate verification token")
86
+ err: () => Cv.error({
87
+ code: "INTERNAL_ERROR",
88
+ message: "Failed to generate verification token"
89
+ })
81
90
  }) : generateRandomString(32, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
82
91
  const expirationTime = Date.now() + (provider.maxAge ?? DEFAULT_EMAIL_VERIFICATION_CODE_DURATION_S) * 1e3;
83
92
  const verificationArgs = {
@@ -101,14 +110,20 @@ function handleEmailAndPhoneProviderFx(ctx, provider, args, options) {
101
110
  provider: p,
102
111
  request: new Request("http://localhost")
103
112
  }, ctx),
104
- err: () => new AuthError("INTERNAL_ERROR", "Failed to send email code")
113
+ err: () => Cv.error({
114
+ code: "INTERNAL_ERROR",
115
+ message: "Failed to send email code"
116
+ })
105
117
  }),
106
118
  phone: (p) => Fx.from({
107
119
  ok: async () => p.sendVerificationRequest({
108
120
  ...verificationArgs,
109
121
  provider: p
110
122
  }, ctx),
111
- err: () => new AuthError("INTERNAL_ERROR", "Failed to send phone code")
123
+ err: () => Cv.error({
124
+ code: "INTERNAL_ERROR",
125
+ message: "Failed to send phone code"
126
+ })
112
127
  })
113
128
  });
114
129
  return {
@@ -167,7 +182,10 @@ function handleOAuthProviderFx(ctx, provider, args, options) {
167
182
  const verifier = yield* Fx.promise(() => callVerifier(ctx));
168
183
  redirect.searchParams.set("code", verifier);
169
184
  if (args.params?.redirectTo !== void 0) {
170
- yield* Fx.guard(typeof args.params.redirectTo !== "string", Fx.fail(new AuthError("INVALID_REDIRECT", `Expected \`redirectTo\` to be a string, got ${args.params.redirectTo}`)));
185
+ yield* Fx.guard(typeof args.params.redirectTo !== "string", Cv.fail({
186
+ code: "INVALID_REDIRECT",
187
+ message: `Expected \`redirectTo\` to be a string, got ${args.params.redirectTo}`
188
+ }));
171
189
  redirect.searchParams.set("redirectTo", args.params.redirectTo);
172
190
  }
173
191
  return {
@@ -180,9 +198,15 @@ function handleOAuthProviderFx(ctx, provider, args, options) {
180
198
  function handleSsoProviderFx(ctx, args) {
181
199
  return Fx.gen(function* () {
182
200
  const enterpriseId = args.params?.enterpriseId;
183
- if (!enterpriseId || typeof enterpriseId !== "string") return yield* Fx.fail(new AuthError("SIGN_IN_MISSING_PARAMS", "enterpriseId is required for SSO sign-in."));
201
+ if (!enterpriseId || typeof enterpriseId !== "string") return yield* Cv.fail({
202
+ code: "SIGN_IN_MISSING_PARAMS",
203
+ message: "enterpriseId is required for SSO sign-in."
204
+ });
184
205
  const protocol = args.params?.protocol ?? "oidc";
185
- if (protocol !== "oidc" && protocol !== "saml") return yield* Fx.fail(new AuthError("SIGN_IN_MISSING_PARAMS", `Invalid SSO protocol: ${protocol}. Expected "oidc" or "saml".`));
206
+ if (protocol !== "oidc" && protocol !== "saml") return yield* Cv.fail({
207
+ code: "SIGN_IN_MISSING_PARAMS",
208
+ message: `Invalid SSO protocol: ${protocol}. Expected "oidc" or "saml".`
209
+ });
186
210
  const verifier = yield* Fx.promise(() => callVerifier(ctx));
187
211
  const siteUrl = process.env.CUSTOM_AUTH_SITE_URL ?? requireEnv("CONVEX_SITE_URL");
188
212
  const redirect = new URL(`${siteUrl}/api/auth/sso/${enterpriseId}/${protocol}/signin`);