@robelest/convex-auth 0.0.4-preview.25 → 0.0.4-preview.28

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 (666) hide show
  1. package/README.md +43 -36
  2. package/dist/bin.js +5765 -4880
  3. package/dist/browser/index.d.ts +30 -0
  4. package/dist/browser/index.js +93 -0
  5. package/dist/browser/locks.js +11 -0
  6. package/dist/browser/navigation.js +14 -0
  7. package/dist/{factors → browser}/passkey.js +23 -32
  8. package/dist/browser/runtime.js +92 -0
  9. package/dist/client/core/types.d.ts +452 -5
  10. package/dist/client/core/types.js +17 -0
  11. package/dist/client/errors.js +19 -0
  12. package/dist/client/factors/device.js +94 -0
  13. package/dist/{factors → client/factors}/totp.js +12 -4
  14. package/dist/client/index.d.ts +47 -1
  15. package/dist/client/index.js +269 -232
  16. package/dist/client/runtime/mutex.js +24 -0
  17. package/dist/client/runtime/proxy.js +30 -0
  18. package/dist/client/runtime/storage.js +45 -0
  19. package/dist/client/services/adapters.js +7 -0
  20. package/dist/client/services/http.js +6 -0
  21. package/dist/client/services/resolve.js +13 -0
  22. package/dist/client/services/runtime.js +6 -0
  23. package/dist/component/_generated/component.d.ts +1355 -1399
  24. package/dist/component/convex.config.d.ts +2 -2
  25. package/dist/component/index.d.ts +4 -26
  26. package/dist/component/index.js +1 -1
  27. package/dist/component/model.d.ts +26 -112
  28. package/dist/component/model.js +76 -54
  29. package/dist/component/modules.js +38 -0
  30. package/dist/component/public/factors/devices.js +1 -1
  31. package/dist/component/public/factors/passkeys.js +1 -1
  32. package/dist/component/public/factors/totp.js +1 -1
  33. package/dist/component/public/groups/core.js +2 -2
  34. package/dist/component/public/groups/invites.js +1 -1
  35. package/dist/component/public/groups/members.js +1 -1
  36. package/dist/component/public/identity/accounts.js +1 -1
  37. package/dist/component/public/identity/codes.js +1 -1
  38. package/dist/component/public/identity/sessions.js +39 -2
  39. package/dist/component/public/identity/tokens.js +82 -4
  40. package/dist/component/public/identity/users.js +1 -1
  41. package/dist/component/public/identity/verifiers.js +10 -4
  42. package/dist/component/public/security/keys.js +1 -1
  43. package/dist/component/public/security/limits.js +1 -1
  44. package/dist/component/public/{enterprise → sso}/audit.js +26 -26
  45. package/dist/component/public/sso/core.js +263 -0
  46. package/dist/component/public/sso/domains.js +280 -0
  47. package/dist/component/public/{enterprise → sso}/scim.js +87 -87
  48. package/dist/component/public/sso/secrets.js +125 -0
  49. package/dist/component/public/{enterprise → sso}/webhooks.js +59 -59
  50. package/dist/component/public.js +9 -9
  51. package/dist/component/schema.d.ts +472 -393
  52. package/dist/component/schema.js +36 -35
  53. package/dist/core/index.d.ts +380 -0
  54. package/dist/core/index.js +83 -0
  55. package/dist/otel.d.ts +69 -0
  56. package/dist/otel.js +82 -0
  57. package/dist/providers/anonymous.d.ts +15 -34
  58. package/dist/providers/anonymous.js +27 -35
  59. package/dist/providers/apple.d.ts +59 -0
  60. package/dist/providers/apple.js +58 -0
  61. package/dist/providers/credentials.d.ts +18 -34
  62. package/dist/providers/credentials.js +16 -27
  63. package/dist/providers/custom.d.ts +94 -0
  64. package/dist/providers/custom.js +119 -0
  65. package/dist/providers/device.d.ts +15 -49
  66. package/dist/providers/device.js +17 -34
  67. package/dist/providers/email.d.ts +21 -38
  68. package/dist/providers/email.js +36 -55
  69. package/dist/providers/github.d.ts +54 -0
  70. package/dist/providers/github.js +75 -0
  71. package/dist/providers/google.d.ts +54 -0
  72. package/dist/providers/google.js +61 -0
  73. package/dist/providers/index.d.ts +16 -12
  74. package/dist/providers/index.js +15 -11
  75. package/dist/providers/microsoft.d.ts +57 -0
  76. package/dist/providers/microsoft.js +101 -0
  77. package/dist/providers/passkey.d.ts +19 -35
  78. package/dist/providers/passkey.js +20 -30
  79. package/dist/providers/password.d.ts +17 -18
  80. package/dist/providers/password.js +121 -143
  81. package/dist/providers/phone.d.ts +13 -28
  82. package/dist/providers/phone.js +21 -46
  83. package/dist/providers/sso.d.ts +16 -36
  84. package/dist/providers/sso.js +21 -22
  85. package/dist/providers/totp.d.ts +13 -29
  86. package/dist/providers/totp.js +17 -27
  87. package/dist/server/auth-context.d.ts +204 -0
  88. package/dist/server/auth-context.js +76 -0
  89. package/dist/server/auth.d.ts +99 -244
  90. package/dist/server/auth.js +56 -152
  91. package/dist/server/componentContext.d.ts +12 -0
  92. package/dist/server/componentContext.js +1 -0
  93. package/dist/server/config.js +6 -67
  94. package/dist/server/constants.js +6 -0
  95. package/dist/server/contract.d.ts +105 -0
  96. package/dist/server/contract.js +43 -0
  97. package/dist/server/cookies.js +3 -2
  98. package/dist/server/core.js +31 -36
  99. package/dist/server/crypto.js +34 -44
  100. package/dist/server/db.js +6 -1
  101. package/dist/server/device.js +96 -130
  102. package/dist/server/env.js +48 -0
  103. package/dist/server/errors.js +20 -0
  104. package/dist/server/http.d.ts +15 -59
  105. package/dist/server/http.js +136 -120
  106. package/dist/server/identity.js +2 -2
  107. package/dist/server/index.d.ts +5 -4
  108. package/dist/server/index.js +3 -3
  109. package/dist/server/keys.js +10 -1
  110. package/dist/server/limits.js +26 -26
  111. package/dist/server/log.js +28 -0
  112. package/dist/server/mounts.d.ts +1107 -296
  113. package/dist/server/mounts.js +315 -196
  114. package/dist/server/mutations/account.js +11 -14
  115. package/dist/server/mutations/code.js +6 -5
  116. package/dist/server/mutations/invalidate.js +9 -11
  117. package/dist/server/mutations/oauth.js +112 -73
  118. package/dist/server/mutations/refresh.js +47 -97
  119. package/dist/server/mutations/register.js +37 -35
  120. package/dist/server/mutations/retrieve.js +16 -16
  121. package/dist/server/mutations/signature.js +15 -18
  122. package/dist/server/mutations/signin.js +10 -5
  123. package/dist/server/mutations/signout.js +11 -14
  124. package/dist/server/mutations/store.js +25 -18
  125. package/dist/server/mutations/verifier.js +11 -8
  126. package/dist/server/mutations/verify.js +53 -41
  127. package/dist/server/oauth/factory.js +44 -0
  128. package/dist/server/oauth/index.js +12 -0
  129. package/dist/server/oauth/runtime.js +248 -0
  130. package/dist/server/passkey.js +331 -365
  131. package/dist/server/payloads.d.ts +16 -0
  132. package/dist/server/payloads.js +30 -0
  133. package/dist/server/{ssr.d.ts → prefetch.d.ts} +2 -2
  134. package/dist/server/prefetch.js +635 -0
  135. package/dist/server/random.js +19 -0
  136. package/dist/server/redirects.js +10 -5
  137. package/dist/server/refresh.js +14 -86
  138. package/dist/server/runtime.d.ts +531 -31
  139. package/dist/server/runtime.js +106 -267
  140. package/dist/server/secret.js +44 -0
  141. package/dist/server/services/config.js +10 -0
  142. package/dist/server/services/group.js +211 -0
  143. package/dist/server/services/logger.js +8 -0
  144. package/dist/server/services/providers.js +22 -0
  145. package/dist/server/services/refresh.js +8 -0
  146. package/dist/server/services/resolve.js +27 -0
  147. package/dist/server/services/signin.js +8 -0
  148. package/dist/server/sessions.js +35 -34
  149. package/dist/server/signin.js +229 -140
  150. package/dist/server/{enterprise → sso}/config.js +10 -3
  151. package/dist/server/sso/domain.d.ts +614 -0
  152. package/dist/server/sso/domain.js +1175 -0
  153. package/dist/server/sso/http.js +1060 -0
  154. package/dist/server/sso/oidc.js +324 -0
  155. package/dist/server/sso/policies.js +59 -0
  156. package/dist/server/sso/policy.js +139 -0
  157. package/dist/server/sso/profile.js +22 -0
  158. package/dist/server/sso/provision.js +179 -0
  159. package/dist/{component/server/enterprise → server/sso}/saml.js +142 -56
  160. package/dist/{component/server/enterprise → server/sso}/scim.js +13 -7
  161. package/dist/server/sso/shared.js +74 -0
  162. package/dist/server/sso/validators.js +88 -0
  163. package/dist/server/sso/webhook.js +94 -0
  164. package/dist/server/tokens.js +16 -4
  165. package/dist/server/totp.js +155 -164
  166. package/dist/server/types.d.ts +306 -296
  167. package/dist/server/types.js +1 -30
  168. package/dist/server/url.js +32 -0
  169. package/dist/server/users.js +74 -40
  170. package/dist/server/utils/cache.js +51 -0
  171. package/dist/server/utils/dispatch.js +36 -0
  172. package/dist/server/utils/retry.js +24 -0
  173. package/dist/server/utils/span.js +32 -0
  174. package/dist/shared/errors.js +19 -0
  175. package/dist/shared/log.js +45 -0
  176. package/{src/test.ts → dist/test.d.ts} +21 -22
  177. package/dist/test.js +51 -0
  178. package/package.json +70 -42
  179. package/dist/authorization/index.d.ts.map +0 -1
  180. package/dist/authorization/index.js.map +0 -1
  181. package/dist/client/core/types.d.ts.map +0 -1
  182. package/dist/client/index.d.ts.map +0 -1
  183. package/dist/client/index.js.map +0 -1
  184. package/dist/component/_generated/api.d.ts +0 -75
  185. package/dist/component/_generated/api.d.ts.map +0 -1
  186. package/dist/component/_generated/api.js.map +0 -1
  187. package/dist/component/_generated/component.d.ts.map +0 -1
  188. package/dist/component/_generated/dataModel.d.ts +0 -42
  189. package/dist/component/_generated/dataModel.d.ts.map +0 -1
  190. package/dist/component/_generated/server.d.ts +0 -117
  191. package/dist/component/_generated/server.d.ts.map +0 -1
  192. package/dist/component/_generated/server.js.map +0 -1
  193. package/dist/component/_virtual/rolldown_runtime.js +0 -18
  194. package/dist/component/client/core/types.d.ts +0 -2
  195. package/dist/component/client/index.d.ts +0 -1
  196. package/dist/component/convex.config.d.ts.map +0 -1
  197. package/dist/component/convex.config.js.map +0 -1
  198. package/dist/component/functions.d.ts +0 -25
  199. package/dist/component/functions.d.ts.map +0 -1
  200. package/dist/component/functions.js.map +0 -1
  201. package/dist/component/index.d.ts.map +0 -1
  202. package/dist/component/model.d.ts.map +0 -1
  203. package/dist/component/model.js.map +0 -1
  204. package/dist/component/providers/anonymous.d.ts +0 -54
  205. package/dist/component/providers/anonymous.d.ts.map +0 -1
  206. package/dist/component/providers/credentials.d.ts +0 -38
  207. package/dist/component/providers/credentials.d.ts.map +0 -1
  208. package/dist/component/providers/device.d.ts +0 -67
  209. package/dist/component/providers/device.d.ts.map +0 -1
  210. package/dist/component/providers/email.d.ts +0 -62
  211. package/dist/component/providers/email.d.ts.map +0 -1
  212. package/dist/component/providers/oauth.d.ts +0 -25
  213. package/dist/component/providers/oauth.d.ts.map +0 -1
  214. package/dist/component/providers/oauth.js +0 -13
  215. package/dist/component/providers/oauth.js.map +0 -1
  216. package/dist/component/providers/passkey.d.ts +0 -57
  217. package/dist/component/providers/passkey.d.ts.map +0 -1
  218. package/dist/component/providers/password.d.ts +0 -88
  219. package/dist/component/providers/password.d.ts.map +0 -1
  220. package/dist/component/providers/phone.d.ts +0 -48
  221. package/dist/component/providers/phone.d.ts.map +0 -1
  222. package/dist/component/providers/sso.d.ts +0 -50
  223. package/dist/component/providers/sso.d.ts.map +0 -1
  224. package/dist/component/providers/totp.d.ts +0 -45
  225. package/dist/component/providers/totp.d.ts.map +0 -1
  226. package/dist/component/public/enterprise/audit.d.ts +0 -73
  227. package/dist/component/public/enterprise/audit.d.ts.map +0 -1
  228. package/dist/component/public/enterprise/audit.js.map +0 -1
  229. package/dist/component/public/enterprise/core.d.ts +0 -176
  230. package/dist/component/public/enterprise/core.d.ts.map +0 -1
  231. package/dist/component/public/enterprise/core.js +0 -292
  232. package/dist/component/public/enterprise/core.js.map +0 -1
  233. package/dist/component/public/enterprise/domains.d.ts +0 -174
  234. package/dist/component/public/enterprise/domains.d.ts.map +0 -1
  235. package/dist/component/public/enterprise/domains.js +0 -271
  236. package/dist/component/public/enterprise/domains.js.map +0 -1
  237. package/dist/component/public/enterprise/scim.d.ts +0 -245
  238. package/dist/component/public/enterprise/scim.d.ts.map +0 -1
  239. package/dist/component/public/enterprise/scim.js.map +0 -1
  240. package/dist/component/public/enterprise/secrets.d.ts +0 -78
  241. package/dist/component/public/enterprise/secrets.d.ts.map +0 -1
  242. package/dist/component/public/enterprise/secrets.js +0 -118
  243. package/dist/component/public/enterprise/secrets.js.map +0 -1
  244. package/dist/component/public/enterprise/webhooks.d.ts +0 -211
  245. package/dist/component/public/enterprise/webhooks.d.ts.map +0 -1
  246. package/dist/component/public/enterprise/webhooks.js.map +0 -1
  247. package/dist/component/public/factors/devices.d.ts +0 -157
  248. package/dist/component/public/factors/devices.d.ts.map +0 -1
  249. package/dist/component/public/factors/devices.js.map +0 -1
  250. package/dist/component/public/factors/passkeys.d.ts +0 -175
  251. package/dist/component/public/factors/passkeys.d.ts.map +0 -1
  252. package/dist/component/public/factors/passkeys.js.map +0 -1
  253. package/dist/component/public/factors/totp.d.ts +0 -189
  254. package/dist/component/public/factors/totp.d.ts.map +0 -1
  255. package/dist/component/public/factors/totp.js.map +0 -1
  256. package/dist/component/public/groups/core.d.ts +0 -137
  257. package/dist/component/public/groups/core.d.ts.map +0 -1
  258. package/dist/component/public/groups/core.js.map +0 -1
  259. package/dist/component/public/groups/invites.d.ts +0 -217
  260. package/dist/component/public/groups/invites.d.ts.map +0 -1
  261. package/dist/component/public/groups/invites.js.map +0 -1
  262. package/dist/component/public/groups/members.d.ts +0 -204
  263. package/dist/component/public/groups/members.d.ts.map +0 -1
  264. package/dist/component/public/groups/members.js.map +0 -1
  265. package/dist/component/public/identity/accounts.d.ts +0 -147
  266. package/dist/component/public/identity/accounts.d.ts.map +0 -1
  267. package/dist/component/public/identity/accounts.js.map +0 -1
  268. package/dist/component/public/identity/codes.d.ts +0 -104
  269. package/dist/component/public/identity/codes.d.ts.map +0 -1
  270. package/dist/component/public/identity/codes.js.map +0 -1
  271. package/dist/component/public/identity/sessions.d.ts +0 -128
  272. package/dist/component/public/identity/sessions.d.ts.map +0 -1
  273. package/dist/component/public/identity/sessions.js.map +0 -1
  274. package/dist/component/public/identity/tokens.d.ts +0 -169
  275. package/dist/component/public/identity/tokens.d.ts.map +0 -1
  276. package/dist/component/public/identity/tokens.js.map +0 -1
  277. package/dist/component/public/identity/users.d.ts +0 -212
  278. package/dist/component/public/identity/users.d.ts.map +0 -1
  279. package/dist/component/public/identity/users.js.map +0 -1
  280. package/dist/component/public/identity/verifiers.d.ts +0 -116
  281. package/dist/component/public/identity/verifiers.d.ts.map +0 -1
  282. package/dist/component/public/identity/verifiers.js.map +0 -1
  283. package/dist/component/public/security/keys.d.ts +0 -209
  284. package/dist/component/public/security/keys.d.ts.map +0 -1
  285. package/dist/component/public/security/keys.js.map +0 -1
  286. package/dist/component/public/security/limits.d.ts +0 -114
  287. package/dist/component/public/security/limits.d.ts.map +0 -1
  288. package/dist/component/public/security/limits.js.map +0 -1
  289. package/dist/component/public.d.ts +0 -28
  290. package/dist/component/public.d.ts.map +0 -1
  291. package/dist/component/schema.d.ts.map +0 -1
  292. package/dist/component/schema.js.map +0 -1
  293. package/dist/component/server/auth.d.ts +0 -447
  294. package/dist/component/server/auth.d.ts.map +0 -1
  295. package/dist/component/server/auth.js +0 -254
  296. package/dist/component/server/auth.js.map +0 -1
  297. package/dist/component/server/config.js +0 -121
  298. package/dist/component/server/config.js.map +0 -1
  299. package/dist/component/server/context.js +0 -53
  300. package/dist/component/server/context.js.map +0 -1
  301. package/dist/component/server/cookies.js +0 -47
  302. package/dist/component/server/cookies.js.map +0 -1
  303. package/dist/component/server/core.js +0 -576
  304. package/dist/component/server/core.js.map +0 -1
  305. package/dist/component/server/crypto.js +0 -56
  306. package/dist/component/server/crypto.js.map +0 -1
  307. package/dist/component/server/db.js +0 -87
  308. package/dist/component/server/db.js.map +0 -1
  309. package/dist/component/server/device.js +0 -152
  310. package/dist/component/server/device.js.map +0 -1
  311. package/dist/component/server/enterprise/config.js +0 -46
  312. package/dist/component/server/enterprise/config.js.map +0 -1
  313. package/dist/component/server/enterprise/domain.js +0 -974
  314. package/dist/component/server/enterprise/domain.js.map +0 -1
  315. package/dist/component/server/enterprise/http.js +0 -787
  316. package/dist/component/server/enterprise/http.js.map +0 -1
  317. package/dist/component/server/enterprise/oidc.js +0 -248
  318. package/dist/component/server/enterprise/oidc.js.map +0 -1
  319. package/dist/component/server/enterprise/policy.js +0 -85
  320. package/dist/component/server/enterprise/policy.js.map +0 -1
  321. package/dist/component/server/enterprise/saml.js.map +0 -1
  322. package/dist/component/server/enterprise/scim.js.map +0 -1
  323. package/dist/component/server/enterprise/shared.js +0 -51
  324. package/dist/component/server/enterprise/shared.js.map +0 -1
  325. package/dist/component/server/http.d.ts +0 -85
  326. package/dist/component/server/http.d.ts.map +0 -1
  327. package/dist/component/server/http.js +0 -351
  328. package/dist/component/server/http.js.map +0 -1
  329. package/dist/component/server/identity.js +0 -16
  330. package/dist/component/server/identity.js.map +0 -1
  331. package/dist/component/server/keys.js +0 -96
  332. package/dist/component/server/keys.js.map +0 -1
  333. package/dist/component/server/limits.js +0 -52
  334. package/dist/component/server/limits.js.map +0 -1
  335. package/dist/component/server/mutations/account.js +0 -46
  336. package/dist/component/server/mutations/account.js.map +0 -1
  337. package/dist/component/server/mutations/code.js +0 -68
  338. package/dist/component/server/mutations/code.js.map +0 -1
  339. package/dist/component/server/mutations/invalidate.js +0 -32
  340. package/dist/component/server/mutations/invalidate.js.map +0 -1
  341. package/dist/component/server/mutations/oauth.js +0 -116
  342. package/dist/component/server/mutations/oauth.js.map +0 -1
  343. package/dist/component/server/mutations/refresh.js +0 -119
  344. package/dist/component/server/mutations/refresh.js.map +0 -1
  345. package/dist/component/server/mutations/register.js +0 -87
  346. package/dist/component/server/mutations/register.js.map +0 -1
  347. package/dist/component/server/mutations/retrieve.js +0 -61
  348. package/dist/component/server/mutations/retrieve.js.map +0 -1
  349. package/dist/component/server/mutations/signature.js +0 -38
  350. package/dist/component/server/mutations/signature.js.map +0 -1
  351. package/dist/component/server/mutations/signin.js +0 -27
  352. package/dist/component/server/mutations/signin.js.map +0 -1
  353. package/dist/component/server/mutations/signout.js +0 -27
  354. package/dist/component/server/mutations/signout.js.map +0 -1
  355. package/dist/component/server/mutations/store/refs.js +0 -15
  356. package/dist/component/server/mutations/store/refs.js.map +0 -1
  357. package/dist/component/server/mutations/store.js +0 -70
  358. package/dist/component/server/mutations/store.js.map +0 -1
  359. package/dist/component/server/mutations/verifier.js +0 -18
  360. package/dist/component/server/mutations/verifier.js.map +0 -1
  361. package/dist/component/server/mutations/verify.js +0 -98
  362. package/dist/component/server/mutations/verify.js.map +0 -1
  363. package/dist/component/server/oauth.js +0 -242
  364. package/dist/component/server/oauth.js.map +0 -1
  365. package/dist/component/server/passkey.js +0 -415
  366. package/dist/component/server/passkey.js.map +0 -1
  367. package/dist/component/server/redirects.js +0 -40
  368. package/dist/component/server/redirects.js.map +0 -1
  369. package/dist/component/server/refresh.js +0 -99
  370. package/dist/component/server/refresh.js.map +0 -1
  371. package/dist/component/server/runtime.d.ts +0 -136
  372. package/dist/component/server/runtime.d.ts.map +0 -1
  373. package/dist/component/server/runtime.js +0 -456
  374. package/dist/component/server/runtime.js.map +0 -1
  375. package/dist/component/server/sessions.js +0 -71
  376. package/dist/component/server/sessions.js.map +0 -1
  377. package/dist/component/server/signin.js +0 -225
  378. package/dist/component/server/signin.js.map +0 -1
  379. package/dist/component/server/tokens.js +0 -17
  380. package/dist/component/server/tokens.js.map +0 -1
  381. package/dist/component/server/totp.js +0 -208
  382. package/dist/component/server/totp.js.map +0 -1
  383. package/dist/component/server/types.d.ts +0 -949
  384. package/dist/component/server/types.d.ts.map +0 -1
  385. package/dist/component/server/types.js +0 -79
  386. package/dist/component/server/types.js.map +0 -1
  387. package/dist/component/server/users.js +0 -123
  388. package/dist/component/server/users.js.map +0 -1
  389. package/dist/component/server/utils.js +0 -140
  390. package/dist/component/server/utils.js.map +0 -1
  391. package/dist/core/types.d.ts +0 -361
  392. package/dist/core/types.d.ts.map +0 -1
  393. package/dist/factors/device.js +0 -104
  394. package/dist/factors/device.js.map +0 -1
  395. package/dist/factors/passkey.js.map +0 -1
  396. package/dist/factors/totp.js.map +0 -1
  397. package/dist/providers/anonymous.d.ts.map +0 -1
  398. package/dist/providers/anonymous.js.map +0 -1
  399. package/dist/providers/credentials.d.ts.map +0 -1
  400. package/dist/providers/credentials.js.map +0 -1
  401. package/dist/providers/device.d.ts.map +0 -1
  402. package/dist/providers/device.js.map +0 -1
  403. package/dist/providers/email.d.ts.map +0 -1
  404. package/dist/providers/email.js.map +0 -1
  405. package/dist/providers/oauth.d.ts +0 -69
  406. package/dist/providers/oauth.d.ts.map +0 -1
  407. package/dist/providers/oauth.js +0 -43
  408. package/dist/providers/oauth.js.map +0 -1
  409. package/dist/providers/passkey.d.ts.map +0 -1
  410. package/dist/providers/passkey.js.map +0 -1
  411. package/dist/providers/password.d.ts.map +0 -1
  412. package/dist/providers/password.js.map +0 -1
  413. package/dist/providers/phone.d.ts.map +0 -1
  414. package/dist/providers/phone.js.map +0 -1
  415. package/dist/providers/sso.d.ts.map +0 -1
  416. package/dist/providers/sso.js.map +0 -1
  417. package/dist/providers/totp.d.ts.map +0 -1
  418. package/dist/providers/totp.js.map +0 -1
  419. package/dist/runtime/browser.js +0 -68
  420. package/dist/runtime/browser.js.map +0 -1
  421. package/dist/runtime/invite.js.map +0 -1
  422. package/dist/runtime/proxy.js +0 -70
  423. package/dist/runtime/proxy.js.map +0 -1
  424. package/dist/runtime/storage.js +0 -37
  425. package/dist/runtime/storage.js.map +0 -1
  426. package/dist/server/auth.d.ts.map +0 -1
  427. package/dist/server/auth.js.map +0 -1
  428. package/dist/server/config.d.ts +0 -1
  429. package/dist/server/config.js.map +0 -1
  430. package/dist/server/context.d.ts +0 -1
  431. package/dist/server/context.js.map +0 -1
  432. package/dist/server/cookies.d.ts +0 -1
  433. package/dist/server/cookies.js.map +0 -1
  434. package/dist/server/core.d.ts +0 -1315
  435. package/dist/server/core.d.ts.map +0 -1
  436. package/dist/server/core.js.map +0 -1
  437. package/dist/server/crypto.d.ts +0 -8
  438. package/dist/server/crypto.d.ts.map +0 -1
  439. package/dist/server/crypto.js.map +0 -1
  440. package/dist/server/db.d.ts +0 -1
  441. package/dist/server/db.js.map +0 -1
  442. package/dist/server/device.d.ts +0 -1
  443. package/dist/server/device.js.map +0 -1
  444. package/dist/server/enterprise/config.d.ts +0 -1
  445. package/dist/server/enterprise/config.js.map +0 -1
  446. package/dist/server/enterprise/domain.d.ts +0 -401
  447. package/dist/server/enterprise/domain.d.ts.map +0 -1
  448. package/dist/server/enterprise/domain.js +0 -974
  449. package/dist/server/enterprise/domain.js.map +0 -1
  450. package/dist/server/enterprise/http.d.ts +0 -26
  451. package/dist/server/enterprise/http.d.ts.map +0 -1
  452. package/dist/server/enterprise/http.js +0 -787
  453. package/dist/server/enterprise/http.js.map +0 -1
  454. package/dist/server/enterprise/oidc.d.ts +0 -1
  455. package/dist/server/enterprise/oidc.js +0 -248
  456. package/dist/server/enterprise/oidc.js.map +0 -1
  457. package/dist/server/enterprise/policy.d.ts +0 -1
  458. package/dist/server/enterprise/policy.js +0 -85
  459. package/dist/server/enterprise/policy.js.map +0 -1
  460. package/dist/server/enterprise/saml.d.ts +0 -1
  461. package/dist/server/enterprise/saml.js +0 -338
  462. package/dist/server/enterprise/saml.js.map +0 -1
  463. package/dist/server/enterprise/scim.d.ts +0 -1
  464. package/dist/server/enterprise/scim.js +0 -97
  465. package/dist/server/enterprise/scim.js.map +0 -1
  466. package/dist/server/enterprise/shared.d.ts +0 -5
  467. package/dist/server/enterprise/shared.d.ts.map +0 -1
  468. package/dist/server/enterprise/shared.js +0 -51
  469. package/dist/server/enterprise/shared.js.map +0 -1
  470. package/dist/server/enterprise/validators.d.ts +0 -1
  471. package/dist/server/enterprise/validators.js +0 -60
  472. package/dist/server/enterprise/validators.js.map +0 -1
  473. package/dist/server/http.d.ts.map +0 -1
  474. package/dist/server/http.js.map +0 -1
  475. package/dist/server/identity.d.ts +0 -1
  476. package/dist/server/identity.js.map +0 -1
  477. package/dist/server/keys.d.ts +0 -1
  478. package/dist/server/keys.js.map +0 -1
  479. package/dist/server/limits.d.ts +0 -1
  480. package/dist/server/limits.js.map +0 -1
  481. package/dist/server/mounts.d.ts.map +0 -1
  482. package/dist/server/mounts.js.map +0 -1
  483. package/dist/server/mutations/account.d.ts +0 -29
  484. package/dist/server/mutations/account.d.ts.map +0 -1
  485. package/dist/server/mutations/account.js.map +0 -1
  486. package/dist/server/mutations/code.d.ts +0 -30
  487. package/dist/server/mutations/code.d.ts.map +0 -1
  488. package/dist/server/mutations/code.js.map +0 -1
  489. package/dist/server/mutations/index.d.ts +0 -14
  490. package/dist/server/mutations/invalidate.d.ts +0 -20
  491. package/dist/server/mutations/invalidate.d.ts.map +0 -1
  492. package/dist/server/mutations/invalidate.js.map +0 -1
  493. package/dist/server/mutations/oauth.d.ts +0 -30
  494. package/dist/server/mutations/oauth.d.ts.map +0 -1
  495. package/dist/server/mutations/oauth.js.map +0 -1
  496. package/dist/server/mutations/refresh.d.ts +0 -21
  497. package/dist/server/mutations/refresh.d.ts.map +0 -1
  498. package/dist/server/mutations/refresh.js.map +0 -1
  499. package/dist/server/mutations/register.d.ts +0 -38
  500. package/dist/server/mutations/register.d.ts.map +0 -1
  501. package/dist/server/mutations/register.js.map +0 -1
  502. package/dist/server/mutations/retrieve.d.ts +0 -33
  503. package/dist/server/mutations/retrieve.d.ts.map +0 -1
  504. package/dist/server/mutations/retrieve.js.map +0 -1
  505. package/dist/server/mutations/signature.d.ts +0 -21
  506. package/dist/server/mutations/signature.d.ts.map +0 -1
  507. package/dist/server/mutations/signature.js.map +0 -1
  508. package/dist/server/mutations/signin.d.ts +0 -22
  509. package/dist/server/mutations/signin.d.ts.map +0 -1
  510. package/dist/server/mutations/signin.js.map +0 -1
  511. package/dist/server/mutations/signout.d.ts +0 -16
  512. package/dist/server/mutations/signout.d.ts.map +0 -1
  513. package/dist/server/mutations/signout.js.map +0 -1
  514. package/dist/server/mutations/store/refs.d.ts +0 -12
  515. package/dist/server/mutations/store/refs.d.ts.map +0 -1
  516. package/dist/server/mutations/store/refs.js.map +0 -1
  517. package/dist/server/mutations/store.d.ts +0 -306
  518. package/dist/server/mutations/store.d.ts.map +0 -1
  519. package/dist/server/mutations/store.js.map +0 -1
  520. package/dist/server/mutations/verifier.d.ts +0 -13
  521. package/dist/server/mutations/verifier.d.ts.map +0 -1
  522. package/dist/server/mutations/verifier.js.map +0 -1
  523. package/dist/server/mutations/verify.d.ts +0 -26
  524. package/dist/server/mutations/verify.d.ts.map +0 -1
  525. package/dist/server/mutations/verify.js.map +0 -1
  526. package/dist/server/oauth.d.ts +0 -1
  527. package/dist/server/oauth.js +0 -242
  528. package/dist/server/oauth.js.map +0 -1
  529. package/dist/server/passkey.d.ts +0 -27
  530. package/dist/server/passkey.d.ts.map +0 -1
  531. package/dist/server/passkey.js.map +0 -1
  532. package/dist/server/redirects.d.ts +0 -1
  533. package/dist/server/redirects.js.map +0 -1
  534. package/dist/server/refresh.d.ts +0 -1
  535. package/dist/server/refresh.js.map +0 -1
  536. package/dist/server/runtime.d.ts.map +0 -1
  537. package/dist/server/runtime.js.map +0 -1
  538. package/dist/server/sessions.d.ts +0 -1
  539. package/dist/server/sessions.js.map +0 -1
  540. package/dist/server/signin.d.ts +0 -1
  541. package/dist/server/signin.js.map +0 -1
  542. package/dist/server/ssr.d.ts.map +0 -1
  543. package/dist/server/ssr.js +0 -777
  544. package/dist/server/ssr.js.map +0 -1
  545. package/dist/server/templates.d.ts +0 -1
  546. package/dist/server/templates.js.map +0 -1
  547. package/dist/server/tokens.d.ts +0 -1
  548. package/dist/server/tokens.js.map +0 -1
  549. package/dist/server/totp.d.ts +0 -1
  550. package/dist/server/totp.js.map +0 -1
  551. package/dist/server/types.d.ts.map +0 -1
  552. package/dist/server/types.js.map +0 -1
  553. package/dist/server/users.d.ts +0 -1
  554. package/dist/server/users.js.map +0 -1
  555. package/dist/server/utils.d.ts +0 -1
  556. package/dist/server/utils.js +0 -140
  557. package/dist/server/utils.js.map +0 -1
  558. package/src/authorization/index.ts +0 -83
  559. package/src/cli/bin.ts +0 -5
  560. package/src/cli/command.ts +0 -70
  561. package/src/cli/index.ts +0 -1112
  562. package/src/cli/keys.ts +0 -23
  563. package/src/client/core/types.ts +0 -437
  564. package/src/client/factors/device.ts +0 -158
  565. package/src/client/factors/passkey.ts +0 -279
  566. package/src/client/factors/totp.ts +0 -150
  567. package/src/client/index.ts +0 -1124
  568. package/src/client/runtime/browser.ts +0 -112
  569. package/src/client/runtime/invite.ts +0 -63
  570. package/src/client/runtime/proxy.ts +0 -111
  571. package/src/client/runtime/storage.ts +0 -79
  572. package/src/component/_generated/api.ts +0 -96
  573. package/src/component/_generated/component.ts +0 -3774
  574. package/src/component/_generated/dataModel.ts +0 -60
  575. package/src/component/_generated/server.ts +0 -156
  576. package/src/component/convex.config.ts +0 -5
  577. package/src/component/functions.ts +0 -104
  578. package/src/component/index.ts +0 -42
  579. package/src/component/model.ts +0 -449
  580. package/src/component/public/enterprise/audit.ts +0 -125
  581. package/src/component/public/enterprise/core.ts +0 -355
  582. package/src/component/public/enterprise/domains.ts +0 -327
  583. package/src/component/public/enterprise/scim.ts +0 -397
  584. package/src/component/public/enterprise/secrets.ts +0 -133
  585. package/src/component/public/enterprise/webhooks.ts +0 -307
  586. package/src/component/public/factors/devices.ts +0 -224
  587. package/src/component/public/factors/passkeys.ts +0 -243
  588. package/src/component/public/factors/totp.ts +0 -259
  589. package/src/component/public/groups/core.ts +0 -481
  590. package/src/component/public/groups/invites.ts +0 -608
  591. package/src/component/public/groups/members.ts +0 -410
  592. package/src/component/public/identity/accounts.ts +0 -207
  593. package/src/component/public/identity/codes.ts +0 -149
  594. package/src/component/public/identity/sessions.ts +0 -210
  595. package/src/component/public/identity/tokens.ts +0 -251
  596. package/src/component/public/identity/users.ts +0 -355
  597. package/src/component/public/identity/verifiers.ts +0 -158
  598. package/src/component/public/security/keys.ts +0 -366
  599. package/src/component/public/security/limits.ts +0 -174
  600. package/src/component/public.ts +0 -27
  601. package/src/component/schema.ts +0 -505
  602. package/src/providers/anonymous.ts +0 -99
  603. package/src/providers/credentials.ts +0 -102
  604. package/src/providers/device.ts +0 -87
  605. package/src/providers/email.ts +0 -99
  606. package/src/providers/index.ts +0 -31
  607. package/src/providers/oauth.ts +0 -117
  608. package/src/providers/passkey.ts +0 -77
  609. package/src/providers/password.ts +0 -441
  610. package/src/providers/phone.ts +0 -93
  611. package/src/providers/sso.ts +0 -54
  612. package/src/providers/totp.ts +0 -62
  613. package/src/samlify.d.ts +0 -53
  614. package/src/server/auth.ts +0 -949
  615. package/src/server/config.ts +0 -200
  616. package/src/server/context.ts +0 -90
  617. package/src/server/cookies.ts +0 -49
  618. package/src/server/core.ts +0 -2004
  619. package/src/server/crypto.ts +0 -90
  620. package/src/server/db.ts +0 -203
  621. package/src/server/device.ts +0 -254
  622. package/src/server/enterprise/config.ts +0 -51
  623. package/src/server/enterprise/domain.ts +0 -1739
  624. package/src/server/enterprise/http.ts +0 -1331
  625. package/src/server/enterprise/oidc.ts +0 -500
  626. package/src/server/enterprise/policy.ts +0 -128
  627. package/src/server/enterprise/saml.ts +0 -578
  628. package/src/server/enterprise/scim.ts +0 -135
  629. package/src/server/enterprise/shared.ts +0 -134
  630. package/src/server/enterprise/validators.ts +0 -93
  631. package/src/server/http.ts +0 -790
  632. package/src/server/identity.ts +0 -18
  633. package/src/server/index.ts +0 -40
  634. package/src/server/keys.ts +0 -158
  635. package/src/server/limits.ts +0 -107
  636. package/src/server/mounts.ts +0 -924
  637. package/src/server/mutations/account.ts +0 -62
  638. package/src/server/mutations/code.ts +0 -119
  639. package/src/server/mutations/index.ts +0 -13
  640. package/src/server/mutations/invalidate.ts +0 -50
  641. package/src/server/mutations/oauth.ts +0 -243
  642. package/src/server/mutations/refresh.ts +0 -299
  643. package/src/server/mutations/register.ts +0 -155
  644. package/src/server/mutations/retrieve.ts +0 -109
  645. package/src/server/mutations/signature.ts +0 -57
  646. package/src/server/mutations/signin.ts +0 -54
  647. package/src/server/mutations/signout.ts +0 -43
  648. package/src/server/mutations/store/refs.ts +0 -10
  649. package/src/server/mutations/store.ts +0 -123
  650. package/src/server/mutations/verifier.ts +0 -34
  651. package/src/server/mutations/verify.ts +0 -200
  652. package/src/server/oauth.ts +0 -418
  653. package/src/server/passkey.ts +0 -838
  654. package/src/server/redirects.ts +0 -59
  655. package/src/server/refresh.ts +0 -218
  656. package/src/server/runtime.ts +0 -918
  657. package/src/server/sessions.ts +0 -132
  658. package/src/server/signin.ts +0 -445
  659. package/src/server/ssr.ts +0 -1747
  660. package/src/server/templates.ts +0 -82
  661. package/src/server/tokens.ts +0 -35
  662. package/src/server/totp.ts +0 -399
  663. package/src/server/types.ts +0 -1942
  664. package/src/server/users.ts +0 -291
  665. package/src/server/utils.ts +0 -220
  666. /package/dist/{runtime → client/runtime}/invite.js +0 -0
@@ -0,0 +1,1175 @@
1
+ import { log } from "../log.js";
2
+ import { addConnectionDomain, createGroupConnection, deleteConnectionDomain, deleteConnectionDomainVerification, deleteGroupConnection, getConnectionDomainVerification, getGroupConnection, getGroupConnectionByDomain, getScimConfigByConnection, listAuditEvents, listConnectionDomains, listGroupConnections, updateGroupConnection, upsertConnectionDomainVerification, upsertGroupConnectionSecret, verifyConnectionDomain } from "../contract.js";
3
+ import { retryWithBackoff } from "../utils/retry.js";
4
+ import { getGroupOidcUrls, getGroupSamlUrls, groupOidcProviderId, groupSamlProviderId, normalizeDomain } from "./shared.js";
5
+ import { getOidcConfig, getPublicOidcConfig, getSamlConfig, upsertProtocolConfig, withOidcSecretState } from "./config.js";
6
+ import { createGroupPolicyDomain } from "./policies.js";
7
+ import { createGroupScimDomain } from "./provision.js";
8
+ import { createServiceProviderMetadata, getSamlServiceProviderOptions, parseSamlIdpMetadataChecked } from "./saml.js";
9
+ import { createGroupWebhookDomain } from "./webhook.js";
10
+ import { ConvexError } from "convex/values";
11
+
12
+ //#region src/server/sso/domain.ts
13
+ const convexError = (data) => new ConvexError(data);
14
+ /**
15
+ * Build the connection and SSO management domain.
16
+ */
17
+ function createGroupConnectionDomain(deps) {
18
+ const { config, getGroupConnectionSecret, loadConnectionOrThrow, validateGroupConnectionPolicy, recordGroupAuditEvent, emitGroupWebhookDeliveries, connectionNotFoundError, GROUP_CONNECTION_OIDC_CLIENT_SECRET_KIND, requireEnv, generateRandomString, INVITE_TOKEN_ALPHABET, sha256, encryptSecret, loadGroupPolicyOrThrow } = deps;
19
+ const webhook = createGroupWebhookDomain({
20
+ config,
21
+ sha256,
22
+ loadConnectionOrThrow,
23
+ recordGroupAuditEvent,
24
+ emitGroupWebhookDeliveries
25
+ });
26
+ const scim = createGroupScimDomain({
27
+ config,
28
+ requireEnv,
29
+ generateRandomString,
30
+ INVITE_TOKEN_ALPHABET,
31
+ sha256,
32
+ loadGroupPolicyOrThrow,
33
+ recordGroupAuditEvent,
34
+ emitGroupWebhookDeliveries
35
+ });
36
+ const policy = createGroupPolicyDomain({
37
+ config,
38
+ loadGroupPolicyOrThrow,
39
+ validateGroupConnectionPolicy,
40
+ recordGroupAuditEvent
41
+ });
42
+ const resolveGroupConnectionProtocol = (connection) => {
43
+ if (connection.protocol === "oidc") return "oidc";
44
+ if (connection.protocol === "saml") return "saml";
45
+ throw convexError({
46
+ code: "PROVIDER_NOT_CONFIGURED",
47
+ message: "Group connection protocol is not configured."
48
+ });
49
+ };
50
+ const GROUP_CONNECTION_DOMAIN_VERIFICATION_PREFIX = "_convex-auth-verification";
51
+ const GROUP_CONNECTION_DOMAIN_VERIFICATION_TTL_MS = 1e3 * 60 * 60 * 24 * 7;
52
+ const toDomainSummary = (domain) => ({
53
+ domainId: domain._id,
54
+ domain: domain.domain,
55
+ isPrimary: domain.isPrimary,
56
+ verified: domain.verifiedAt !== void 0,
57
+ verifiedAt: domain.verifiedAt ?? null
58
+ });
59
+ const getDomainVerificationRecordName = (domain) => `${GROUP_CONNECTION_DOMAIN_VERIFICATION_PREFIX}.${normalizeDomain(domain)}`;
60
+ const parseTxtAnswer = (value) => {
61
+ const quoted = [...value.matchAll(/"([^"]*)"/g)].map((match) => match[1]);
62
+ if (quoted.length > 0) return quoted.join("");
63
+ return value.replace(/^"|"$/g, "").trim();
64
+ };
65
+ const resolveTxtValues = async (recordName) => {
66
+ const url = new URL("https://dns.google/resolve");
67
+ url.searchParams.set("name", recordName);
68
+ url.searchParams.set("type", "TXT");
69
+ const response = await fetch(url, { headers: { accept: "application/json" } });
70
+ if (!response.ok) throw new Error(`DNS TXT lookup failed with status ${response.status}.`);
71
+ return ((await response.json()).Answer ?? []).map((answer) => typeof answer.data === "string" ? parseTxtAnswer(answer.data) : null).filter((value) => value !== null && value.length > 0);
72
+ };
73
+ return {
74
+ connection: {
75
+ create: async (ctx, data) => {
76
+ return {
77
+ connectionId: await createGroupConnection(ctx, config.component.public, data),
78
+ groupId: data.groupId
79
+ };
80
+ },
81
+ get: async (ctx, connectionId) => {
82
+ return await getGroupConnection(ctx, config.component.public, connectionId);
83
+ },
84
+ getByDomain: async (ctx, domain) => {
85
+ return await getGroupConnectionByDomain(ctx, config.component.public, normalizeDomain(domain));
86
+ },
87
+ list: async (ctx, opts) => {
88
+ return await listGroupConnections(ctx, config.component.public, {
89
+ where: opts?.where,
90
+ limit: opts?.limit,
91
+ cursor: opts?.cursor,
92
+ orderBy: opts?.orderBy,
93
+ order: opts?.order
94
+ });
95
+ },
96
+ update: async (ctx, connectionId, data) => {
97
+ await updateGroupConnection(ctx, config.component.public, {
98
+ connectionId,
99
+ data
100
+ });
101
+ return { connectionId };
102
+ },
103
+ delete: async (ctx, connectionId) => {
104
+ await deleteGroupConnection(ctx, config.component.public, connectionId);
105
+ return { connectionId };
106
+ },
107
+ status: async (ctx, connectionId) => {
108
+ const connection = await getGroupConnection(ctx, config.component.public, connectionId);
109
+ if (!connection) throw convexError({
110
+ code: "INVALID_PARAMETERS",
111
+ message: connectionNotFoundError
112
+ });
113
+ const policy$1 = await loadGroupPolicyOrThrow(ctx, connection.groupId);
114
+ const oidcConfig = getOidcConfig(connection.config);
115
+ const oidcSecret = await getGroupConnectionSecret(ctx, connection._id, GROUP_CONNECTION_OIDC_CLIENT_SECRET_KIND);
116
+ const samlConfig = getSamlConfig(connection.config);
117
+ const scimConfig = await getScimConfigByConnection(ctx, config.component.public, connectionId);
118
+ const domains = await listConnectionDomains(ctx, config.component.public, connectionId);
119
+ const oidcReady = oidcConfig?.enabled === true && typeof oidcConfig?.client?.id === "string" && oidcConfig.client.id.length > 0 && oidcSecret !== null && (typeof oidcConfig?.discovery?.issuer === "string" || typeof oidcConfig?.discovery?.discoveryUrl === "string");
120
+ const samlReady = samlConfig?.enabled === true && typeof samlConfig?.idp?.entityId === "string";
121
+ const scimReady = scimConfig?.status === "active";
122
+ const ready = connection.status === "active" && (connection.protocol === "oidc" ? oidcReady : samlReady);
123
+ return {
124
+ connectionId: connection._id,
125
+ status: connection.status,
126
+ ready,
127
+ domainCount: domains.length,
128
+ protocols: {
129
+ oidc: {
130
+ configured: connection.protocol === "oidc" ? oidcReady : false,
131
+ ready: connection.protocol === "oidc" ? oidcReady : false,
132
+ clientId: oidcConfig?.client?.id ?? null,
133
+ issuer: oidcConfig?.discovery?.issuer ?? oidcConfig?.discovery?.discoveryUrl ?? null
134
+ },
135
+ saml: {
136
+ configured: connection.protocol === "saml" ? samlReady : false,
137
+ ready: connection.protocol === "saml" ? samlReady : false,
138
+ entityId: samlConfig?.idp?.entityId ?? samlConfig?.idp?.issuer ?? null
139
+ },
140
+ scim: {
141
+ configured: scimReady,
142
+ ready: scimReady,
143
+ basePath: scimConfig?.basePath ?? null,
144
+ deprovisionMode: policy$1.provisioning.deprovision.mode
145
+ }
146
+ }
147
+ };
148
+ }
149
+ },
150
+ domain: {
151
+ add: async (ctx, data) => {
152
+ return await addConnectionDomain(ctx, config.component.public, {
153
+ ...data,
154
+ domain: normalizeDomain(data.domain)
155
+ });
156
+ },
157
+ list: async (ctx, connectionId) => {
158
+ return await listConnectionDomains(ctx, config.component.public, connectionId);
159
+ },
160
+ validate: async (ctx, connectionId) => {
161
+ const connection = await getGroupConnection(ctx, config.component.public, connectionId);
162
+ if (connection === null) throw convexError({
163
+ code: "INVALID_PARAMETERS",
164
+ message: connectionNotFoundError
165
+ });
166
+ const domains = await listConnectionDomains(ctx, config.component.public, connectionId);
167
+ const primaryDomains = domains.filter((domain) => domain.isPrimary);
168
+ const verifiedDomains = domains.filter((domain) => domain.verifiedAt !== void 0);
169
+ const warnings = [];
170
+ if (domains.length === 0) warnings.push("No domains configured.");
171
+ if (primaryDomains.length === 0 && domains.length > 0) warnings.push("No primary domain configured.");
172
+ if (primaryDomains.length > 1) warnings.push("Multiple primary domains configured.");
173
+ if (verifiedDomains.length === 0 && domains.length > 0) warnings.push("No verified domains yet.");
174
+ return {
175
+ connectionId,
176
+ ready: connection.status === "active" && domains.length > 0 && primaryDomains.length === 1 && verifiedDomains.length > 0,
177
+ summary: {
178
+ domainCount: domains.length,
179
+ primaryCount: primaryDomains.length,
180
+ verifiedCount: verifiedDomains.length
181
+ },
182
+ domains: domains.map((domain) => toDomainSummary(domain)),
183
+ warnings
184
+ };
185
+ },
186
+ status: async (ctx, connectionId) => {
187
+ const connection = await getGroupConnection(ctx, config.component.public, connectionId);
188
+ if (connection === null) throw convexError({
189
+ code: "INVALID_PARAMETERS",
190
+ message: connectionNotFoundError
191
+ });
192
+ const domains = await listConnectionDomains(ctx, config.component.public, connectionId);
193
+ const primaryDomain = domains.find((domain) => domain.isPrimary) ?? null;
194
+ const verifiedDomains = domains.filter((domain) => domain.verifiedAt !== void 0);
195
+ const pendingChallenges = (await Promise.all(domains.map(async (domain) => {
196
+ const verification = await getConnectionDomainVerification(ctx, config.component.public, domain._id);
197
+ if (!verification || verification.expiresAt < Date.now()) return null;
198
+ return {
199
+ domain: domain.domain,
200
+ recordName: verification.recordName,
201
+ expiresAt: verification.expiresAt
202
+ };
203
+ }))).filter((challenge) => challenge !== null);
204
+ const warnings = [];
205
+ const nextSteps = [];
206
+ if (domains.length === 0) {
207
+ warnings.push("No domains configured.");
208
+ nextSteps.push("Attach at least one domain to this connection.");
209
+ }
210
+ if (primaryDomain === null && domains.length > 0) {
211
+ warnings.push("No primary domain configured.");
212
+ nextSteps.push("Mark one attached domain as the primary domain.");
213
+ }
214
+ if (verifiedDomains.length === 0 && domains.length > 0) {
215
+ warnings.push("No verified domains yet.");
216
+ nextSteps.push("Request a TXT challenge and confirm verification for at least one domain.");
217
+ }
218
+ if (primaryDomain !== null && primaryDomain.verifiedAt === void 0 && domains.length > 0) nextSteps.push(`Verify the primary domain ${primaryDomain.domain} to establish trusted ownership.`);
219
+ if (pendingChallenges.length > 0) nextSteps.push("If DNS is already updated, confirm the pending TXT challenge to complete verification.");
220
+ const primaryDomainVerified = primaryDomain?.verifiedAt !== void 0;
221
+ return {
222
+ connectionId,
223
+ ready: connection.status === "active" && domains.length > 0 && primaryDomain !== null && verifiedDomains.length > 0,
224
+ primaryDomain: primaryDomain === null ? null : {
225
+ domainId: primaryDomain._id,
226
+ domain: primaryDomain.domain,
227
+ isPrimary: true,
228
+ verified: primaryDomain.verifiedAt !== void 0,
229
+ verifiedAt: primaryDomain.verifiedAt ?? null
230
+ },
231
+ trustedDomains: verifiedDomains.map((domain) => ({
232
+ domainId: domain._id,
233
+ domain: domain.domain,
234
+ isPrimary: Boolean(domain.isPrimary),
235
+ verified: true,
236
+ verifiedAt: domain.verifiedAt ?? null
237
+ })),
238
+ pendingChallenges,
239
+ trust: {
240
+ domainDiscoveryReady: verifiedDomains.length > 0,
241
+ primaryDomainVerified,
242
+ automaticLinkingEligible: primaryDomainVerified && connection.status === "active" && verifiedDomains.length > 0
243
+ },
244
+ warnings,
245
+ nextSteps
246
+ };
247
+ },
248
+ remove: async (ctx, domainId) => {
249
+ await deleteConnectionDomain(ctx, config.component.public, domainId);
250
+ },
251
+ verification: {
252
+ request: async (ctx, args) => {
253
+ const connection = await loadConnectionOrThrow(ctx, args.connectionId);
254
+ const normalizedDomain = normalizeDomain(args.domain);
255
+ const domain = (await listConnectionDomains(ctx, config.component.public, connection._id)).find((entry) => entry.domain === normalizedDomain);
256
+ if (!domain) throw convexError({
257
+ code: "INVALID_PARAMETERS",
258
+ message: "Domain is not attached to this connection."
259
+ });
260
+ const requestedAt = Date.now();
261
+ const expiresAt = requestedAt + GROUP_CONNECTION_DOMAIN_VERIFICATION_TTL_MS;
262
+ const token = generateRandomString(32, INVITE_TOKEN_ALPHABET);
263
+ const tokenHash = await sha256(token);
264
+ const recordName = getDomainVerificationRecordName(normalizedDomain);
265
+ await upsertConnectionDomainVerification(ctx, config.component.public, {
266
+ connectionId: connection._id,
267
+ groupId: connection.groupId,
268
+ domainId: domain._id,
269
+ domain: normalizedDomain,
270
+ recordName,
271
+ token,
272
+ tokenHash,
273
+ requestedAt,
274
+ expiresAt
275
+ });
276
+ await recordGroupAuditEvent(ctx, {
277
+ connectionId: connection._id,
278
+ groupId: connection.groupId,
279
+ eventType: "group.sso.domain.verification_requested",
280
+ actorType: "system",
281
+ subjectType: "group_connection_domain",
282
+ subjectId: domain._id,
283
+ ok: true,
284
+ metadata: {
285
+ domain: normalizedDomain,
286
+ recordName,
287
+ expiresAt
288
+ }
289
+ });
290
+ return {
291
+ connectionId: connection._id,
292
+ domain: normalizedDomain,
293
+ requestedAt,
294
+ expiresAt,
295
+ challenge: {
296
+ recordType: "TXT",
297
+ recordName,
298
+ recordValue: token
299
+ }
300
+ };
301
+ },
302
+ confirm: async (ctx, args) => {
303
+ const connection = await loadConnectionOrThrow(ctx, args.connectionId);
304
+ const normalizedDomain = normalizeDomain(args.domain);
305
+ const domain = (await listConnectionDomains(ctx, config.component.public, connection._id)).find((entry) => entry.domain === normalizedDomain);
306
+ if (!domain) throw convexError({
307
+ code: "INVALID_PARAMETERS",
308
+ message: "Domain is not attached to this connection."
309
+ });
310
+ if (domain.verifiedAt !== void 0) return {
311
+ connectionId: connection._id,
312
+ domain: normalizedDomain,
313
+ verifiedAt: domain.verifiedAt,
314
+ checks: [{
315
+ name: "domain_verified",
316
+ ok: true,
317
+ message: "Domain is already verified."
318
+ }]
319
+ };
320
+ const verification = await getConnectionDomainVerification(ctx, config.component.public, domain._id);
321
+ const checks = [];
322
+ if (!verification) {
323
+ checks.push({
324
+ name: "verification_requested",
325
+ ok: false,
326
+ message: "No active domain verification challenge exists."
327
+ });
328
+ return {
329
+ connectionId: connection._id,
330
+ domain: normalizedDomain,
331
+ checks
332
+ };
333
+ }
334
+ checks.push({
335
+ name: "verification_requested",
336
+ ok: true
337
+ });
338
+ if (verification.expiresAt < Date.now()) {
339
+ await deleteConnectionDomainVerification(ctx, config.component.public, domain._id);
340
+ checks.push({
341
+ name: "challenge_active",
342
+ ok: false,
343
+ message: "The verification challenge expired. Request a new one."
344
+ });
345
+ return {
346
+ connectionId: connection._id,
347
+ domain: normalizedDomain,
348
+ checks
349
+ };
350
+ }
351
+ checks.push({
352
+ name: "challenge_active",
353
+ ok: true
354
+ });
355
+ let txtValues;
356
+ try {
357
+ txtValues = await resolveTxtValues(verification.recordName);
358
+ } catch (error) {
359
+ throw convexError({
360
+ code: "INTERNAL_ERROR",
361
+ message: error instanceof Error ? error.message : "Failed to resolve DNS TXT records."
362
+ });
363
+ }
364
+ checks.push({
365
+ name: "dns_record_present",
366
+ ok: txtValues.length > 0,
367
+ message: txtValues.length > 0 ? void 0 : `No TXT records found at ${verification.recordName}.`
368
+ });
369
+ const matches = txtValues.includes(verification.token);
370
+ checks.push({
371
+ name: "dns_record_matches",
372
+ ok: matches,
373
+ message: matches ? void 0 : `TXT record at ${verification.recordName} does not match the expected value.`
374
+ });
375
+ if (!checks.every((check) => check.ok)) return {
376
+ connectionId: connection._id,
377
+ domain: normalizedDomain,
378
+ checks
379
+ };
380
+ const verifiedAt = Date.now();
381
+ await verifyConnectionDomain(ctx, config.component.public, {
382
+ domainId: domain._id,
383
+ verifiedAt
384
+ });
385
+ await recordGroupAuditEvent(ctx, {
386
+ connectionId: connection._id,
387
+ groupId: connection.groupId,
388
+ eventType: "group.sso.domain.verified",
389
+ actorType: "system",
390
+ subjectType: "group_connection_domain",
391
+ subjectId: domain._id,
392
+ ok: true,
393
+ metadata: {
394
+ domain: normalizedDomain,
395
+ verifiedAt
396
+ }
397
+ });
398
+ return {
399
+ connectionId: connection._id,
400
+ domain: normalizedDomain,
401
+ verifiedAt,
402
+ checks
403
+ };
404
+ }
405
+ }
406
+ },
407
+ saml: {
408
+ configure: async (ctx, data) => {
409
+ let connection;
410
+ try {
411
+ connection = await getGroupConnection(ctx, config.component.public, data.connectionId);
412
+ } catch {
413
+ throw convexError({
414
+ code: "INTERNAL_ERROR",
415
+ message: "Failed to load connection."
416
+ });
417
+ }
418
+ if (connection === null) throw convexError({
419
+ code: "INVALID_PARAMETERS",
420
+ message: connectionNotFoundError
421
+ });
422
+ if (connection.protocol !== "saml") throw convexError({
423
+ code: "INVALID_PARAMETERS",
424
+ message: "This connection is not a SAML connection."
425
+ });
426
+ const metadataUrl = typeof data.metadata.url === "string" && data.metadata.url.length > 0 ? data.metadata.url : void 0;
427
+ let metadataXml;
428
+ if (metadataUrl) try {
429
+ metadataXml = await retryWithBackoff(async () => {
430
+ const response = await fetch(metadataUrl, { signal: AbortSignal.timeout(1e4) });
431
+ if (!response.ok) throw new Error(`Failed to fetch SAML metadata: ${response.status}`);
432
+ return await response.text();
433
+ });
434
+ } catch (error) {
435
+ throw convexError({
436
+ code: "INVALID_PARAMETERS",
437
+ message: error instanceof Error ? error.message : "Failed to fetch SAML metadata"
438
+ });
439
+ }
440
+ else if (data.metadata.xml) metadataXml = data.metadata.xml;
441
+ else throw convexError({
442
+ code: "INVALID_PARAMETERS",
443
+ message: "SAML registration requires metadataXml or metadataUrl."
444
+ });
445
+ let parsed;
446
+ try {
447
+ parsed = parseSamlIdpMetadataChecked({
448
+ metadataXml,
449
+ config: { protocols: { saml: { security: data.security } } }
450
+ });
451
+ } catch (error) {
452
+ throw convexError({
453
+ code: "INVALID_PARAMETERS",
454
+ message: error instanceof Error ? `Failed to parse SAML metadata: ${error.message}` : "Failed to parse SAML metadata."
455
+ });
456
+ }
457
+ log("DEBUG", "[group-sso] saml:configure:parsed", {
458
+ connectionId: data.connectionId,
459
+ metadataUrl,
460
+ entityId: parsed.entityId,
461
+ issuer: parsed.issuer
462
+ });
463
+ const baseConfig = upsertProtocolConfig(connection.config, "saml", {
464
+ enabled: true,
465
+ idp: {
466
+ metadataUrl,
467
+ metadataXml,
468
+ ...parsed
469
+ },
470
+ serviceProvider: data.serviceProvider,
471
+ request: {
472
+ signAuthnRequests: data.request?.signAuthnRequests ?? parsed.wantsSignedAuthnRequests,
473
+ nameIdFormat: data.request?.nameIdFormat,
474
+ forceAuthn: data.request?.forceAuthn,
475
+ authnContextClassRefs: data.request?.authnContextClassRefs
476
+ },
477
+ profile: {
478
+ mapping: data.profile?.mapping,
479
+ extraFields: data.profile?.extraFields
480
+ },
481
+ security: data.security
482
+ });
483
+ const normalizedDomains = data.domains?.map(normalizeDomain);
484
+ const nextConfig = normalizedDomains ? {
485
+ ...baseConfig,
486
+ domains: normalizedDomains
487
+ } : baseConfig;
488
+ const nextSamlConfig = nextConfig.protocols?.saml ?? void 0;
489
+ log("DEBUG", "[group-sso] saml:configure:nextConfig", {
490
+ connectionId: data.connectionId,
491
+ entityId: nextSamlConfig?.idp?.entityId ?? null,
492
+ issuer: nextSamlConfig?.idp?.issuer ?? null,
493
+ metadataUrl: nextSamlConfig?.idp?.metadataUrl ?? null,
494
+ hasMetadataXml: typeof nextSamlConfig?.idp?.metadataXml === "string"
495
+ });
496
+ try {
497
+ await updateGroupConnection(ctx, config.component.public, {
498
+ connectionId: connection._id,
499
+ data: {
500
+ status: "active",
501
+ config: nextConfig
502
+ }
503
+ });
504
+ } catch {
505
+ throw convexError({
506
+ code: "INTERNAL_ERROR",
507
+ message: "Failed to persist SAML registration."
508
+ });
509
+ }
510
+ if (normalizedDomains) for (const [index, domain] of normalizedDomains.entries()) try {
511
+ await addConnectionDomain(ctx, config.component.public, {
512
+ connectionId: connection._id,
513
+ groupId: connection.groupId,
514
+ domain,
515
+ isPrimary: index === 0
516
+ });
517
+ } catch {
518
+ throw convexError({
519
+ code: "INTERNAL_ERROR",
520
+ message: "Failed to persist connection domain."
521
+ });
522
+ }
523
+ try {
524
+ await recordGroupAuditEvent(ctx, {
525
+ connectionId: connection._id,
526
+ groupId: connection.groupId,
527
+ eventType: "group.sso.saml.registered",
528
+ actorType: "system",
529
+ subjectType: "group_connection_saml",
530
+ subjectId: connection._id,
531
+ ok: true,
532
+ metadata: {
533
+ metadataUrl,
534
+ domains: normalizedDomains
535
+ }
536
+ });
537
+ } catch {
538
+ throw convexError({
539
+ code: "INTERNAL_ERROR",
540
+ message: "Failed to record SAML registration audit event."
541
+ });
542
+ }
543
+ return {
544
+ connectionId: connection._id,
545
+ groupId: connection.groupId
546
+ };
547
+ },
548
+ refresh: async (ctx, data) => {
549
+ let connection;
550
+ try {
551
+ connection = await getGroupConnection(ctx, config.component.public, data.connectionId);
552
+ } catch {
553
+ throw convexError({
554
+ code: "INTERNAL_ERROR",
555
+ message: "Failed to load connection."
556
+ });
557
+ }
558
+ if (connection === null) throw convexError({
559
+ code: "INVALID_PARAMETERS",
560
+ message: connectionNotFoundError
561
+ });
562
+ const samlConfig = connection.config?.protocols?.saml;
563
+ if (connection.protocol !== "saml") throw convexError({
564
+ code: "INVALID_PARAMETERS",
565
+ message: "This connection is not a SAML connection."
566
+ });
567
+ if (typeof samlConfig?.idp?.metadataUrl !== "string") throw convexError({
568
+ code: "INVALID_PARAMETERS",
569
+ message: "SAML metadataUrl is not configured."
570
+ });
571
+ const metadataUrl = samlConfig.idp.metadataUrl;
572
+ let metadataXml;
573
+ try {
574
+ metadataXml = await retryWithBackoff(async () => {
575
+ const response = await fetch(metadataUrl, { signal: AbortSignal.timeout(1e4) });
576
+ if (!response.ok) throw new Error(`Failed to fetch SAML metadata: ${response.status}`);
577
+ return await response.text();
578
+ });
579
+ } catch (error) {
580
+ throw convexError({
581
+ code: "INVALID_PARAMETERS",
582
+ message: error instanceof Error ? error.message : "Failed to fetch SAML metadata"
583
+ });
584
+ }
585
+ let parsed;
586
+ try {
587
+ parsed = parseSamlIdpMetadataChecked({
588
+ metadataXml,
589
+ config: connection.config
590
+ });
591
+ } catch (error) {
592
+ throw convexError({
593
+ code: "INVALID_PARAMETERS",
594
+ message: error instanceof Error ? `Failed to parse SAML metadata: ${error.message}` : "Failed to parse SAML metadata."
595
+ });
596
+ }
597
+ const nextConfig = upsertProtocolConfig(connection.config, "saml", {
598
+ enabled: true,
599
+ idp: {
600
+ metadataUrl,
601
+ metadataXml,
602
+ ...parsed
603
+ },
604
+ serviceProvider: samlConfig.serviceProvider,
605
+ request: samlConfig.request,
606
+ profile: samlConfig.profile,
607
+ security: samlConfig.security
608
+ });
609
+ try {
610
+ await updateGroupConnection(ctx, config.component.public, {
611
+ connectionId: connection._id,
612
+ data: {
613
+ status: connection.status,
614
+ config: nextConfig
615
+ }
616
+ });
617
+ } catch {
618
+ throw convexError({
619
+ code: "INTERNAL_ERROR",
620
+ message: "Failed to persist refreshed SAML metadata."
621
+ });
622
+ }
623
+ try {
624
+ await recordGroupAuditEvent(ctx, {
625
+ connectionId: connection._id,
626
+ groupId: connection.groupId,
627
+ eventType: "group.sso.saml.refreshed",
628
+ actorType: "system",
629
+ subjectType: "group_connection_saml",
630
+ subjectId: connection._id,
631
+ ok: true,
632
+ metadata: { metadataUrl }
633
+ });
634
+ } catch {
635
+ throw convexError({
636
+ code: "INTERNAL_ERROR",
637
+ message: "Failed to record SAML refresh audit event."
638
+ });
639
+ }
640
+ return {
641
+ connectionId: connection._id,
642
+ groupId: connection.groupId
643
+ };
644
+ },
645
+ get: async (ctx, connectionId) => {
646
+ let connection;
647
+ try {
648
+ connection = await getGroupConnection(ctx, config.component.public, connectionId);
649
+ } catch {
650
+ throw convexError({
651
+ code: "INTERNAL_ERROR",
652
+ message: "Failed to load connection."
653
+ });
654
+ }
655
+ if (connection === null) throw convexError({
656
+ code: "INVALID_PARAMETERS",
657
+ message: connectionNotFoundError
658
+ });
659
+ return getSamlConfig(connection.config);
660
+ },
661
+ status: (ctx, connectionId) => {
662
+ return getGroupConnection(ctx, config.component.public, connectionId).then((connection) => {
663
+ if (!connection) throw convexError({
664
+ code: "INVALID_PARAMETERS",
665
+ message: connectionNotFoundError
666
+ });
667
+ const currentConfig = getSamlConfig(connection.config);
668
+ const configured = currentConfig.enabled === true;
669
+ return {
670
+ connectionId,
671
+ configured,
672
+ ready: configured && typeof currentConfig.idp?.entityId === "string",
673
+ config: currentConfig,
674
+ checks: [{
675
+ name: "saml_configured",
676
+ ok: configured,
677
+ message: configured ? void 0 : "SAML is not configured."
678
+ }]
679
+ };
680
+ });
681
+ },
682
+ metadata: async (ctx, opts) => {
683
+ const connection = await getGroupConnection(ctx, config.component.public, opts.connectionId);
684
+ if (!connection) throw convexError({
685
+ code: "INVALID_PARAMETERS",
686
+ message: "Connection not found."
687
+ });
688
+ return createServiceProviderMetadata(getSamlServiceProviderOptions({
689
+ rootUrl: requireEnv("CONVEX_SITE_URL"),
690
+ source: {
691
+ kind: "connection",
692
+ id: connection._id
693
+ },
694
+ config: connection.config,
695
+ overrides: {
696
+ entityId: opts.entityId,
697
+ acsUrl: opts.acsUrl,
698
+ sloUrl: opts.sloUrl
699
+ }
700
+ }));
701
+ },
702
+ validate: async (ctx, connectionId) => {
703
+ const checks = [];
704
+ const connection = await getGroupConnection(ctx, config.component.public, connectionId);
705
+ if (!connection) return {
706
+ ok: false,
707
+ connectionId,
708
+ checks: [{
709
+ name: "group_connection_exists",
710
+ ok: false,
711
+ message: "Connection not found."
712
+ }]
713
+ };
714
+ const samlConfig = connection.config?.protocols?.saml;
715
+ const samlConfigured = samlConfig?.enabled === true && typeof samlConfig?.idp?.metadataXml === "string";
716
+ checks.push({
717
+ name: "saml_configured",
718
+ ok: samlConfigured,
719
+ message: samlConfigured ? void 0 : "SAML is not configured."
720
+ });
721
+ const hasIdpMetadata = typeof samlConfig?.idp?.metadataXml === "string" && samlConfig.idp.metadataXml.length > 0;
722
+ checks.push({
723
+ name: "idp_metadata_present",
724
+ ok: hasIdpMetadata,
725
+ message: hasIdpMetadata ? void 0 : "IdP metadata XML is missing."
726
+ });
727
+ const reparsedIdp = hasIdpMetadata && typeof samlConfig?.idp?.metadataXml === "string" ? (() => {
728
+ try {
729
+ return parseSamlIdpMetadataChecked({
730
+ metadataXml: samlConfig.idp.metadataXml,
731
+ config: connection.config
732
+ });
733
+ } catch {
734
+ return null;
735
+ }
736
+ })() : null;
737
+ log("DEBUG", "[group-sso] saml:validate:idp", {
738
+ connectionId,
739
+ entityId: samlConfig?.idp?.entityId ?? null,
740
+ issuer: samlConfig?.idp?.issuer ?? null,
741
+ metadataUrl: samlConfig?.idp?.metadataUrl ?? null,
742
+ reparsedEntityId: reparsedIdp?.entityId ?? null,
743
+ reparsedIssuer: reparsedIdp?.issuer ?? null
744
+ });
745
+ const hasEntityId = typeof samlConfig?.idp?.entityId === "string" && samlConfig.idp.entityId.length > 0 || typeof samlConfig?.idp?.issuer === "string" && samlConfig.idp.issuer.length > 0 || typeof reparsedIdp?.entityId === "string" && reparsedIdp.entityId.length > 0 || typeof reparsedIdp?.issuer === "string" && reparsedIdp.issuer.length > 0;
746
+ checks.push({
747
+ name: "idp_entity_id",
748
+ ok: hasEntityId,
749
+ message: hasEntityId ? void 0 : "IdP entityId could not be parsed from metadata."
750
+ });
751
+ let spMetadataOk = false;
752
+ let spMetadataMessage;
753
+ if (samlConfigured) try {
754
+ createServiceProviderMetadata(getSamlServiceProviderOptions({
755
+ rootUrl: requireEnv("CONVEX_SITE_URL"),
756
+ source: {
757
+ kind: "connection",
758
+ id: connection._id
759
+ },
760
+ config: connection.config,
761
+ overrides: {}
762
+ }));
763
+ spMetadataOk = true;
764
+ } catch (e) {
765
+ spMetadataMessage = e instanceof Error ? e.message : "SP metadata generation failed.";
766
+ }
767
+ else spMetadataMessage = "Skipped — SAML not configured.";
768
+ checks.push({
769
+ name: "sp_metadata_generates",
770
+ ok: spMetadataOk,
771
+ message: spMetadataMessage
772
+ });
773
+ const requiresSignedAssertions = samlConfig?.security?.requireSignedAssertions === true;
774
+ const hasSigningCert = reparsedIdp?.signingCert !== null;
775
+ checks.push({
776
+ name: "signed_assertions_compatible",
777
+ ok: !requiresSignedAssertions || hasSigningCert,
778
+ message: !requiresSignedAssertions || hasSigningCert ? void 0 : "Signed assertions are required but the IdP metadata has no signing certificate."
779
+ });
780
+ const signAuthnRequests = samlConfig?.request?.signAuthnRequests === true;
781
+ const hasSpPrivateKey = typeof samlConfig?.serviceProvider?.privateKey === "string";
782
+ checks.push({
783
+ name: "authn_request_signing_compatible",
784
+ ok: !signAuthnRequests || hasSpPrivateKey,
785
+ message: !signAuthnRequests || hasSpPrivateKey ? void 0 : "signAuthnRequests is enabled but no SP privateKey is configured."
786
+ });
787
+ checks.push({
788
+ name: "timestamp_validation_configured",
789
+ ok: true,
790
+ message: samlConfig?.security?.requireTimestamps === true ? `Timestamp validation enabled with clock skew ${samlConfig.security.clockSkewSeconds ?? 300} seconds.` : "Timestamp validation uses compatibility defaults."
791
+ });
792
+ return {
793
+ ok: checks.every((c) => c.ok),
794
+ connectionId: connection._id,
795
+ checks
796
+ };
797
+ }
798
+ },
799
+ policy,
800
+ oidc: {
801
+ configure: async (ctx, data) => {
802
+ if (data.discovery.issuer === void 0 && data.discovery.discoveryUrl === void 0) throw convexError({
803
+ code: "INVALID_PARAMETERS",
804
+ message: "OIDC registration requires issuer or discoveryUrl."
805
+ });
806
+ let connection;
807
+ try {
808
+ connection = await getGroupConnection(ctx, config.component.public, data.connectionId);
809
+ } catch {
810
+ throw convexError({
811
+ code: "INTERNAL_ERROR",
812
+ message: "Failed to load connection."
813
+ });
814
+ }
815
+ if (connection === null) throw convexError({
816
+ code: "INVALID_PARAMETERS",
817
+ message: connectionNotFoundError
818
+ });
819
+ if (connection.protocol !== "oidc") throw convexError({
820
+ code: "INVALID_PARAMETERS",
821
+ message: "This connection is not an OIDC connection."
822
+ });
823
+ const nextConfig = upsertProtocolConfig(connection.config, "oidc", {
824
+ enabled: true,
825
+ discovery: {
826
+ issuer: data.discovery.issuer,
827
+ discoveryUrl: data.discovery.discoveryUrl,
828
+ jwksUri: data.discovery.jwksUri,
829
+ audience: data.discovery.audience
830
+ },
831
+ client: {
832
+ id: data.client.id,
833
+ authMethod: data.client.authMethod
834
+ },
835
+ request: {
836
+ scopes: data.request?.scopes ?? [
837
+ "openid",
838
+ "profile",
839
+ "email"
840
+ ],
841
+ loginHint: data.request?.loginHint,
842
+ authorizationParams: data.request?.authorizationParams
843
+ },
844
+ security: {
845
+ clockToleranceSeconds: data.security?.clockToleranceSeconds,
846
+ strictIssuer: data.security?.strictIssuer
847
+ },
848
+ profile: {
849
+ mapping: data.profile?.mapping,
850
+ extraFields: data.profile?.extraFields
851
+ }
852
+ });
853
+ try {
854
+ await updateGroupConnection(ctx, config.component.public, {
855
+ connectionId: data.connectionId,
856
+ data: { config: nextConfig }
857
+ });
858
+ } catch {
859
+ throw convexError({
860
+ code: "INTERNAL_ERROR",
861
+ message: "Failed to persist OIDC registration."
862
+ });
863
+ }
864
+ if (data.client.secret !== void 0) {
865
+ let ciphertext;
866
+ try {
867
+ ciphertext = await encryptSecret(data.client.secret);
868
+ } catch {
869
+ throw convexError({
870
+ code: "INTERNAL_ERROR",
871
+ message: "Failed to encrypt OIDC client secret."
872
+ });
873
+ }
874
+ try {
875
+ await upsertGroupConnectionSecret(ctx, config.component.public, {
876
+ connectionId: data.connectionId,
877
+ groupId: connection.groupId,
878
+ kind: GROUP_CONNECTION_OIDC_CLIENT_SECRET_KIND,
879
+ ciphertext,
880
+ updatedAt: Date.now()
881
+ });
882
+ } catch {
883
+ throw convexError({
884
+ code: "INTERNAL_ERROR",
885
+ message: "Failed to persist OIDC client secret."
886
+ });
887
+ }
888
+ }
889
+ try {
890
+ await recordGroupAuditEvent(ctx, {
891
+ connectionId: data.connectionId,
892
+ groupId: connection.groupId,
893
+ eventType: "group.sso.oidc.registered",
894
+ actorType: "system",
895
+ subjectType: "group_connection_oidc",
896
+ subjectId: data.connectionId,
897
+ ok: true,
898
+ metadata: {
899
+ issuer: data.discovery.issuer,
900
+ discoveryUrl: data.discovery.discoveryUrl,
901
+ jwksUri: data.discovery.jwksUri,
902
+ audience: data.discovery.audience,
903
+ tokenEndpointAuthMethod: data.client.authMethod
904
+ }
905
+ });
906
+ } catch {
907
+ throw convexError({
908
+ code: "INTERNAL_ERROR",
909
+ message: "Failed to record OIDC registration audit event."
910
+ });
911
+ }
912
+ let secret;
913
+ try {
914
+ secret = await getGroupConnectionSecret(ctx, data.connectionId, GROUP_CONNECTION_OIDC_CLIENT_SECRET_KIND);
915
+ } catch {
916
+ throw convexError({
917
+ code: "INTERNAL_ERROR",
918
+ message: "Failed to load OIDC secret metadata."
919
+ });
920
+ }
921
+ return withOidcSecretState(getPublicOidcConfig(nextConfig), secret !== null);
922
+ },
923
+ get: async (ctx, connectionId) => {
924
+ let connection;
925
+ try {
926
+ connection = await getGroupConnection(ctx, config.component.public, connectionId);
927
+ } catch {
928
+ throw convexError({
929
+ code: "INTERNAL_ERROR",
930
+ message: "Failed to load connection."
931
+ });
932
+ }
933
+ if (connection === null) throw convexError({
934
+ code: "INVALID_PARAMETERS",
935
+ message: connectionNotFoundError
936
+ });
937
+ let secret;
938
+ try {
939
+ secret = await getGroupConnectionSecret(ctx, connection._id, GROUP_CONNECTION_OIDC_CLIENT_SECRET_KIND);
940
+ } catch {
941
+ throw convexError({
942
+ code: "INTERNAL_ERROR",
943
+ message: "Failed to load OIDC secret metadata."
944
+ });
945
+ }
946
+ return withOidcSecretState(getPublicOidcConfig(connection.config), secret !== null);
947
+ },
948
+ status: (ctx, connectionId) => {
949
+ return Promise.all([getGroupConnection(ctx, config.component.public, connectionId), getGroupConnectionSecret(ctx, connectionId, GROUP_CONNECTION_OIDC_CLIENT_SECRET_KIND)]).then(([connection, secret]) => {
950
+ if (!connection) throw convexError({
951
+ code: "INVALID_PARAMETERS",
952
+ message: connectionNotFoundError
953
+ });
954
+ const currentConfig = getPublicOidcConfig(connection.config);
955
+ const oidcConfig = getOidcConfig(connection.config);
956
+ const configured = currentConfig.enabled === true && typeof oidcConfig.client?.id === "string" && (typeof oidcConfig.discovery?.issuer === "string" || typeof oidcConfig.discovery?.discoveryUrl === "string");
957
+ return {
958
+ connectionId,
959
+ configured,
960
+ ready: configured && secret !== null,
961
+ config: withOidcSecretState(currentConfig, secret !== null),
962
+ checks: [{
963
+ name: "oidc_configured",
964
+ ok: configured,
965
+ message: configured ? void 0 : "OIDC is not configured."
966
+ }, {
967
+ name: "client_secret_stored",
968
+ ok: secret !== null,
969
+ message: secret !== null ? void 0 : "OIDC client secret is missing."
970
+ }]
971
+ };
972
+ });
973
+ },
974
+ signIn: async (ctx, data) => {
975
+ log("DEBUG", "[group-sso] resolver:start", {
976
+ connectionId: data.connectionId,
977
+ email: data.email,
978
+ domain: data.domain,
979
+ redirectTo: data.redirectTo
980
+ });
981
+ let connection;
982
+ if (data.connectionId !== void 0) {
983
+ try {
984
+ connection = await getGroupConnection(ctx, config.component.public, data.connectionId);
985
+ } catch {
986
+ throw convexError({
987
+ code: "INTERNAL_ERROR",
988
+ message: "Failed to load connection."
989
+ });
990
+ }
991
+ if (connection === null) throw convexError({
992
+ code: "INVALID_PARAMETERS",
993
+ message: connectionNotFoundError
994
+ });
995
+ } else if (data.domain !== void 0 || data.email !== void 0) {
996
+ let result;
997
+ try {
998
+ result = await getGroupConnectionByDomain(ctx, config.component.public, normalizeDomain(data.domain ?? String(data.email).split("@").pop() ?? ""));
999
+ } catch {
1000
+ throw convexError({
1001
+ code: "INTERNAL_ERROR",
1002
+ message: "Failed to resolve connection by domain."
1003
+ });
1004
+ }
1005
+ log("DEBUG", "[group-sso] resolver:domainLookup", result);
1006
+ if (result?.connection && result.domain?.verifiedAt !== void 0) connection = result.connection;
1007
+ else throw convexError({
1008
+ code: "INVALID_PARAMETERS",
1009
+ message: "No group connection matched the provided input."
1010
+ });
1011
+ } else throw convexError({
1012
+ code: "INVALID_PARAMETERS",
1013
+ message: "No group connection matched the provided input."
1014
+ });
1015
+ if (connection.status !== "active") throw convexError({
1016
+ code: "INVALID_PARAMETERS",
1017
+ message: "Group connection is not active."
1018
+ });
1019
+ const protocol = resolveGroupConnectionProtocol(connection);
1020
+ log("DEBUG", "[group-sso] resolver:connection", {
1021
+ connectionId: connection._id,
1022
+ status: connection.status,
1023
+ protocol
1024
+ });
1025
+ const { signInPath, callbackPath, providerId } = protocol === "oidc" ? (() => {
1026
+ const urls = getGroupOidcUrls({
1027
+ rootUrl: requireEnv("CONVEX_SITE_URL"),
1028
+ connectionId: connection._id,
1029
+ sharedRedirectURI: deps.sharedOidcRedirectURI
1030
+ });
1031
+ return {
1032
+ signInPath: urls.signInUrl,
1033
+ callbackPath: urls.callbackUrl,
1034
+ providerId: groupOidcProviderId(connection._id)
1035
+ };
1036
+ })() : (() => {
1037
+ const urls = getGroupSamlUrls({
1038
+ rootUrl: requireEnv("CONVEX_SITE_URL"),
1039
+ source: {
1040
+ kind: "connection",
1041
+ id: connection._id
1042
+ }
1043
+ });
1044
+ return {
1045
+ signInPath: `${requireEnv("CONVEX_SITE_URL")}/api/auth/connections/${connection._id}/saml/signin`,
1046
+ callbackPath: urls.acsUrl,
1047
+ providerId: groupSamlProviderId(connection._id)
1048
+ };
1049
+ })();
1050
+ log("DEBUG", "[group-sso] resolver:paths", {
1051
+ connectionId: connection._id,
1052
+ signInPath,
1053
+ callbackPath
1054
+ });
1055
+ return {
1056
+ connectionId: connection._id,
1057
+ protocol,
1058
+ providerId,
1059
+ signInPath: protocol === "oidc" && typeof data.loginHint === "string" ? (() => {
1060
+ const signInUrl = new URL(signInPath);
1061
+ signInUrl.searchParams.set("loginHint", data.loginHint);
1062
+ return signInUrl.toString();
1063
+ })() : signInPath,
1064
+ callbackPath,
1065
+ redirectTo: data.redirectTo
1066
+ };
1067
+ },
1068
+ validate: async (ctx, connectionId) => {
1069
+ const checks = [];
1070
+ const connection = await getGroupConnection(ctx, config.component.public, connectionId);
1071
+ if (!connection) return {
1072
+ ok: false,
1073
+ connectionId,
1074
+ checks: [{
1075
+ name: "group_connection_exists",
1076
+ ok: false,
1077
+ message: "Connection not found."
1078
+ }]
1079
+ };
1080
+ const oidc = getOidcConfig(connection.config);
1081
+ const secret = await getGroupConnectionSecret(ctx, connection._id, GROUP_CONNECTION_OIDC_CLIENT_SECRET_KIND);
1082
+ const oidcConfigured = oidc.enabled === true && typeof oidc.client?.id === "string" && oidc.client.id.length > 0;
1083
+ checks.push({
1084
+ name: "oidc_configured",
1085
+ ok: oidcConfigured,
1086
+ message: oidcConfigured ? void 0 : "OIDC is not configured."
1087
+ });
1088
+ const hasClientId = typeof oidc.client?.id === "string" && oidc.client.id.length > 0;
1089
+ checks.push({
1090
+ name: "client_id_present",
1091
+ ok: hasClientId,
1092
+ message: hasClientId ? void 0 : "clientId is missing."
1093
+ });
1094
+ checks.push({
1095
+ name: "client_secret_stored",
1096
+ ok: secret !== null,
1097
+ message: secret !== null ? void 0 : "OIDC client secret is missing."
1098
+ });
1099
+ const discoveryConfig = typeof oidc.discovery === "object" && oidc.discovery !== null ? oidc.discovery : {};
1100
+ const clientConfig = typeof oidc.client === "object" && oidc.client !== null ? oidc.client : {};
1101
+ const discoveryTarget = discoveryConfig.discoveryUrl ?? discoveryConfig.issuer;
1102
+ const hasDiscovery = typeof discoveryTarget === "string" && discoveryTarget.length > 0;
1103
+ checks.push({
1104
+ name: "issuer_or_discovery_url_present",
1105
+ ok: hasDiscovery,
1106
+ message: hasDiscovery ? void 0 : "issuer or discoveryUrl is missing."
1107
+ });
1108
+ let discoveryOk = false;
1109
+ let discoveryMessage;
1110
+ if (hasDiscovery) {
1111
+ const discoveryUrl = typeof discoveryConfig.discoveryUrl === "string" && discoveryConfig.discoveryUrl.length > 0 ? discoveryConfig.discoveryUrl : `${String(discoveryConfig.issuer)}/.well-known/openid-configuration`;
1112
+ try {
1113
+ const res = await fetch(discoveryUrl, {
1114
+ headers: { Accept: "application/json" },
1115
+ signal: AbortSignal.timeout(8e3)
1116
+ });
1117
+ if (!res.ok) discoveryMessage = `Discovery endpoint returned ${res.status}.`;
1118
+ else {
1119
+ const json = await res.json();
1120
+ if (typeof json.issuer !== "string") discoveryMessage = "Discovery document is missing issuer field.";
1121
+ else if (typeof json.authorization_endpoint !== "string") discoveryMessage = "Discovery document is missing authorization_endpoint.";
1122
+ else if (typeof json.token_endpoint !== "string") discoveryMessage = "Discovery document is missing token_endpoint.";
1123
+ else if (discoveryConfig.jwksUri === void 0 && typeof json.jwks_uri !== "string") discoveryMessage = "Discovery document is missing jwks_uri and no jwksUri override is configured.";
1124
+ else discoveryOk = true;
1125
+ }
1126
+ } catch (e) {
1127
+ discoveryMessage = e instanceof Error ? `Discovery fetch failed: ${e.message}` : "Discovery fetch failed.";
1128
+ }
1129
+ } else discoveryMessage = "Skipped — issuer or discoveryUrl not set.";
1130
+ checks.push({
1131
+ name: "discovery_reachable",
1132
+ ok: discoveryOk,
1133
+ message: discoveryMessage
1134
+ });
1135
+ const hasValidTokenAuthMethod = clientConfig.authMethod === void 0 || clientConfig.authMethod === "client_secret_post" || clientConfig.authMethod === "client_secret_basic";
1136
+ checks.push({
1137
+ name: "token_endpoint_auth_method_supported",
1138
+ ok: hasValidTokenAuthMethod,
1139
+ message: hasValidTokenAuthMethod ? void 0 : "tokenEndpointAuthMethod must be client_secret_post or client_secret_basic."
1140
+ });
1141
+ const hasJwksUri = discoveryConfig.jwksUri === void 0 || typeof discoveryConfig.jwksUri === "string" && discoveryConfig.jwksUri.length > 0;
1142
+ checks.push({
1143
+ name: "jwks_uri_present",
1144
+ ok: hasJwksUri,
1145
+ message: hasJwksUri ? void 0 : "jwksUri is empty."
1146
+ });
1147
+ const hasAudience = discoveryConfig.audience === void 0 || typeof discoveryConfig.audience === "string" || Array.isArray(discoveryConfig.audience) && discoveryConfig.audience.every((value) => typeof value === "string");
1148
+ checks.push({
1149
+ name: "audience_valid",
1150
+ ok: hasAudience,
1151
+ message: hasAudience ? void 0 : "audience must be a string or string array."
1152
+ });
1153
+ return {
1154
+ ok: checks.every((c) => c.ok),
1155
+ connectionId: connection._id,
1156
+ checks
1157
+ };
1158
+ }
1159
+ },
1160
+ scim,
1161
+ audit: {
1162
+ record: async (ctx, data) => {
1163
+ return await recordGroupAuditEvent(ctx, data);
1164
+ },
1165
+ list: async (ctx, data) => {
1166
+ return await listAuditEvents(ctx, config.component.public, data);
1167
+ }
1168
+ },
1169
+ webhook
1170
+ };
1171
+ }
1172
+
1173
+ //#endregion
1174
+ export { createGroupConnectionDomain };
1175
+ //# sourceMappingURL=domain.js.map