@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
@@ -1,1331 +0,0 @@
1
- import { Fx } from "@robelest/fx";
2
- import { Cv } from "@robelest/fx/convex";
3
- import type { GenericActionCtx, HttpRouter } from "convex/server";
4
- import { ConvexError } from "convex/values";
5
- import { serialize as serializeCookie } from "cookie";
6
-
7
- import { redirectToParamCookie, useRedirectToParam } from "../cookies";
8
- import { addSSORoutes, convertErrorsToResponse, getCookies } from "../http";
9
- import type { SSORuntimeRoute } from "../http";
10
- import { createOAuthAuthorizationURL, handleOAuthCallback } from "../oauth";
11
- import { redirectAbsoluteUrl, setURLSearchParam } from "../redirects";
12
- import { createEnterpriseOidcRuntime } from "./oidc";
13
- import {
14
- createEnterpriseSamlMetadataXml,
15
- createEnterpriseSamlSignInRequest,
16
- createSamlPostBindingResponse,
17
- encodeEnterpriseSamlRelayState,
18
- parseEnterpriseSamlLoginResponse,
19
- parseEnterpriseSamlLogoutMessage,
20
- profileFromSamlExtract,
21
- validateEnterpriseSamlLoginRelayState,
22
- } from "./saml";
23
- import {
24
- parseScimListRequest,
25
- scimError,
26
- scimJson,
27
- serializeScimGroup,
28
- serializeScimUser,
29
- } from "./scim";
30
- import {
31
- enterpriseSamlProviderId,
32
- SCIM_GROUP_SCHEMA_ID,
33
- SCIM_USER_SCHEMA_ID,
34
- } from "./shared";
35
-
36
- export type EnterpriseHttpRuntimeDeps = {
37
- http: HttpRouter;
38
- hasSSO: boolean;
39
- auth: any;
40
- config: any;
41
- routeBase: string;
42
- requireEnv: (name: string) => string;
43
- loadActiveEnterpriseSamlOrThrow: any;
44
- loadEnterpriseOidcOrThrow: any;
45
- getEnterpriseScimContext: any;
46
- getPolicyFromEnterprise: any;
47
- normalizeEnterprisePolicy: any;
48
- recordEnterpriseAuditEvent: any;
49
- emitEnterpriseWebhookDeliveries: any;
50
- generateRandomString: (length: number, alphabet: string) => string;
51
- inviteTokenAlphabet: string;
52
- callUserOAuth: any;
53
- callVerifierSignature: any;
54
- };
55
-
56
- export function addEnterpriseHttpRuntime(deps: EnterpriseHttpRuntimeDeps) {
57
- if (!deps.hasSSO) {
58
- return;
59
- }
60
-
61
- const {
62
- http,
63
- auth,
64
- config,
65
- requireEnv,
66
- loadActiveEnterpriseSamlOrThrow,
67
- loadEnterpriseOidcOrThrow,
68
- getEnterpriseScimContext,
69
- getPolicyFromEnterprise,
70
- recordEnterpriseAuditEvent,
71
- emitEnterpriseWebhookDeliveries,
72
- generateRandomString,
73
- inviteTokenAlphabet: INVITE_TOKEN_ALPHABET,
74
- callUserOAuth,
75
- callVerifierSignature,
76
- } = deps;
77
- const ENTERPRISE_CONTROL_ROUTE_BASE = deps.routeBase;
78
-
79
- type ScimState = {
80
- ctx: any;
81
- request: Request;
82
- url: URL;
83
- parsedPath: Awaited<
84
- ReturnType<typeof getEnterpriseScimContext>
85
- >["parsedPath"];
86
- enterprise: Awaited<
87
- ReturnType<typeof getEnterpriseScimContext>
88
- >["enterprise"];
89
- scimConfig: Awaited<
90
- ReturnType<typeof getEnterpriseScimContext>
91
- >["scimConfig"];
92
- policy: any;
93
- recordScimEvent: (
94
- eventType: string,
95
- ok: boolean,
96
- subjectType: string,
97
- subjectId?: string,
98
- metadata?: Record<string, unknown>,
99
- ) => Promise<void>;
100
- };
101
-
102
- type ScimHandler = (state: ScimState) => Promise<Response>;
103
-
104
- const SCIM_SCHEMAS = [
105
- {
106
- id: SCIM_USER_SCHEMA_ID,
107
- name: "User",
108
- description: "User Account",
109
- attributes: [
110
- { name: "userName", type: "string", required: true },
111
- { name: "displayName", type: "string" },
112
- { name: "active", type: "boolean" },
113
- { name: "emails", type: "complex", multiValued: true },
114
- ],
115
- },
116
- {
117
- id: SCIM_GROUP_SCHEMA_ID,
118
- name: "Group",
119
- description: "Group",
120
- attributes: [
121
- { name: "displayName", type: "string", required: true },
122
- { name: "members", type: "complex", multiValued: true },
123
- ],
124
- },
125
- ] as const;
126
-
127
- const SCIM_RESOURCE_TYPES = [
128
- {
129
- id: "User",
130
- name: "User",
131
- endpoint: "/Users",
132
- schema: SCIM_USER_SCHEMA_ID,
133
- },
134
- {
135
- id: "Group",
136
- name: "Group",
137
- endpoint: "/Groups",
138
- schema: SCIM_GROUP_SCHEMA_ID,
139
- },
140
- ] as const;
141
-
142
- const handleStaticScimCollection = <T extends { id?: string; name?: string }>(
143
- items: readonly T[],
144
- resourceId: string | undefined,
145
- opts: { by: "id" | "name"; notFound: string },
146
- ) => {
147
- if (resourceId !== undefined) {
148
- const item = items.find(
149
- (entry) => entry[opts.by] === decodeURIComponent(resourceId),
150
- );
151
- return item ? scimJson(item) : scimError(404, "notFound", opts.notFound);
152
- }
153
- return scimJson({
154
- schemas: ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
155
- Resources: items,
156
- totalResults: items.length,
157
- startIndex: 1,
158
- itemsPerPage: items.length,
159
- });
160
- };
161
-
162
- const filterScimCollection = <T>(
163
- items: T[],
164
- filter: ReturnType<typeof parseScimListRequest>["filter"],
165
- filters: Record<string, (item: T, value: string) => boolean>,
166
- ) => {
167
- if (!filter) {
168
- return items;
169
- }
170
- const predicate = filters[filter.attribute];
171
- if (!predicate) {
172
- throw new Error("Unsupported SCIM filter.");
173
- }
174
- return items.filter((item) => predicate(item, filter.value));
175
- };
176
-
177
- const paginateScimCollection = <T>(
178
- items: T[],
179
- listRequest: ReturnType<typeof parseScimListRequest>,
180
- ) => {
181
- const start = listRequest.startIndex - 1;
182
- return items.slice(start, start + listRequest.count);
183
- };
184
-
185
- const requireScimResourceId = (
186
- resourceId: string | undefined,
187
- label: string,
188
- ) => {
189
- if (!resourceId) {
190
- return scimError(400, "invalidPath", `${label} resource ID is required.`);
191
- }
192
- return null;
193
- };
194
-
195
- const readScimJson = async (request: Request) =>
196
- (await request.json()) as Record<string, any>;
197
-
198
- const handleSamlAcs = async (
199
- ctx: GenericActionCtx<any>,
200
- request: Request,
201
- runtimeRoute: SSORuntimeRoute,
202
- ) =>
203
- Fx.run(
204
- Fx.gen(function* () {
205
- yield* Fx.guard(
206
- runtimeRoute.protocol !== "saml" ||
207
- runtimeRoute.rest.length !== 1 ||
208
- runtimeRoute.rest[0] !== "acs",
209
- Cv.fail({
210
- code: "INVALID_PARAMETERS",
211
- message: "Invalid enterprise runtime path.",
212
- }),
213
- );
214
-
215
- const enterpriseId = runtimeRoute.enterpriseId;
216
- const { loaded, enterprise, saml } = yield* Fx.from({
217
- ok: () => loadActiveEnterpriseSamlOrThrow(ctx, enterpriseId),
218
- err: (e) => e,
219
- });
220
-
221
- const parsedResponse = yield* Fx.from({
222
- ok: () =>
223
- parseEnterpriseSamlLoginResponse({
224
- request,
225
- rootUrl: requireEnv("CONVEX_SITE_URL"),
226
- source: { kind: "enterprise", id: enterprise._id },
227
- config: loaded.config,
228
- }),
229
- err: (e) =>
230
- Cv.error({
231
- code: "OAUTH_PROVIDER_ERROR",
232
- message: `SAML response parse failed: ${e instanceof Error ? e.message : String(e)}`,
233
- }),
234
- });
235
-
236
- yield* Fx.from({
237
- ok: () => {
238
- validateEnterpriseSamlLoginRelayState({
239
- relayState: parsedResponse.relayState,
240
- source: { kind: "enterprise", id: enterprise._id },
241
- inResponseTo:
242
- parsedResponse.parsed.extract?.response?.inResponseTo,
243
- });
244
- return Promise.resolve();
245
- },
246
- err: () =>
247
- Cv.error({
248
- code: "OAUTH_INVALID_STATE",
249
- message:
250
- "SAML RelayState did not match the pending login request.",
251
- }),
252
- });
253
-
254
- const { samlAttributes, samlSessionIndex, ...userProfile } =
255
- profileFromSamlExtract(
256
- parsedResponse.parsed.extract,
257
- saml.attributeMapping,
258
- );
259
- const profile = userProfile as Record<string, unknown> & {
260
- id: string;
261
- };
262
-
263
- const maybeRedirectTo = useRedirectToParam(
264
- enterpriseSamlProviderId(enterprise._id),
265
- getCookies(request),
266
- );
267
-
268
- const verificationCode = yield* Fx.from({
269
- ok: () =>
270
- callUserOAuth(ctx, {
271
- provider: enterpriseSamlProviderId(enterprise._id),
272
- providerAccountId: profile.id,
273
- profile,
274
- signature: parsedResponse.relayState.signature,
275
- accountExtend: {
276
- identity: {
277
- protocol: "saml",
278
- enterpriseId: enterprise._id,
279
- subject: profile.id,
280
- entityId:
281
- typeof saml.entityId === "string"
282
- ? saml.entityId
283
- : undefined,
284
- },
285
- saml: {
286
- attributes: samlAttributes,
287
- sessionIndex: samlSessionIndex,
288
- },
289
- },
290
- }),
291
- err: (e) => e,
292
- });
293
-
294
- const destinationUrl = yield* Fx.from({
295
- ok: () =>
296
- redirectAbsoluteUrl(config, {
297
- redirectTo:
298
- maybeRedirectTo?.redirectTo ??
299
- (typeof parsedResponse.relayState.redirectTo === "string"
300
- ? parsedResponse.relayState.redirectTo
301
- : undefined),
302
- }),
303
- err: (e) => e,
304
- });
305
-
306
- const vurl = setURLSearchParam(
307
- destinationUrl,
308
- "code",
309
- verificationCode,
310
- );
311
- const vheaders = new Headers({ Location: vurl });
312
- vheaders.set("Cache-Control", "must-revalidate");
313
- for (const { name, value, options } of maybeRedirectTo !== null
314
- ? [maybeRedirectTo.updatedCookie]
315
- : []) {
316
- vheaders.append("Set-Cookie", serializeCookie(name, value, options));
317
- }
318
- return new Response(null, { status: 302, headers: vheaders });
319
- }).pipe(Fx.recover((e) => Fx.fatal(e))),
320
- );
321
-
322
- const handleSamlSlo = async (
323
- ctx: GenericActionCtx<any>,
324
- request: Request,
325
- runtimeRoute: SSORuntimeRoute,
326
- ) => {
327
- if (
328
- runtimeRoute.protocol !== "saml" ||
329
- runtimeRoute.rest.length !== 1 ||
330
- runtimeRoute.rest[0] !== "slo"
331
- ) {
332
- throw Cv.error({
333
- code: "INVALID_PARAMETERS",
334
- message: "Invalid enterprise runtime path.",
335
- });
336
- }
337
- const { loaded, enterprise } = await loadActiveEnterpriseSamlOrThrow(
338
- ctx,
339
- runtimeRoute.enterpriseId,
340
- );
341
- const parsedMessage = await parseEnterpriseSamlLogoutMessage({
342
- request,
343
- rootUrl: requireEnv("CONVEX_SITE_URL"),
344
- source: { kind: "enterprise", id: enterprise._id },
345
- config: loaded.config,
346
- });
347
- if (parsedMessage.hasSamlRequest && parsedMessage.parsedRequest) {
348
- const responseContext = (
349
- parsedMessage.runtime.sp as any
350
- ).createLogoutResponse(
351
- parsedMessage.runtime.idp as any,
352
- parsedMessage.parsedRequest.extract,
353
- parsedMessage.binding as any,
354
- parsedMessage.relayState ?? "",
355
- ) as any;
356
- if (parsedMessage.binding === "redirect") {
357
- return new Response(null, {
358
- status: 302,
359
- headers: { Location: responseContext.context },
360
- });
361
- }
362
- return createSamlPostBindingResponse({
363
- endpoint: responseContext.entityEndpoint,
364
- parameter: "SAMLResponse",
365
- value: responseContext.context,
366
- relayState: parsedMessage.relayState,
367
- });
368
- }
369
- if (parsedMessage.hasSamlResponse) {
370
- return new Response(null, { status: 204 });
371
- }
372
- throw Cv.error({
373
- code: "INVALID_PARAMETERS",
374
- message: "Missing SAML logout payload.",
375
- });
376
- };
377
-
378
- const handleScimRequest = async (
379
- ctx: GenericActionCtx<any>,
380
- request: Request,
381
- ) => {
382
- try {
383
- const { scimConfig, enterprise, parsedPath } =
384
- await getEnterpriseScimContext(ctx, request);
385
- const url = new URL(request.url);
386
- const state: ScimState = {
387
- ctx,
388
- request,
389
- url,
390
- parsedPath,
391
- enterprise,
392
- scimConfig,
393
- policy: getPolicyFromEnterprise(enterprise),
394
- recordScimEvent: async (
395
- eventType,
396
- ok,
397
- subjectType,
398
- subjectId,
399
- metadata,
400
- ) => {
401
- const auditEventId = await recordEnterpriseAuditEvent(ctx, {
402
- enterpriseId: enterprise._id,
403
- groupId: enterprise.groupId,
404
- eventType,
405
- actorType: "scim",
406
- subjectType,
407
- subjectId,
408
- ok,
409
- metadata,
410
- });
411
- await emitEnterpriseWebhookDeliveries(ctx, {
412
- enterpriseId: enterprise._id,
413
- eventType,
414
- auditEventId,
415
- payload: {
416
- enterpriseId: enterprise._id,
417
- subjectId,
418
- metadata,
419
- },
420
- });
421
- },
422
- };
423
-
424
- const handleUsersGet: ScimHandler = async (state) => {
425
- const members = await auth.member.list(state.ctx, {
426
- where: { groupId: state.enterprise.groupId },
427
- limit: 100,
428
- });
429
- const identities = await state.ctx.runQuery(
430
- config.component.public.enterpriseScimIdentityListByEnterprise,
431
- { enterpriseId: state.enterprise._id },
432
- );
433
- const identityByUserId = new Map(
434
- identities
435
- .filter((identity: any) => identity.userId !== undefined)
436
- .map((identity: any) => [identity.userId, identity]),
437
- );
438
- const users = (
439
- await Promise.all(
440
- members.items.map(async (member: any) => {
441
- const user = await auth.user.get(state.ctx, member.userId);
442
- return user
443
- ? {
444
- user,
445
- member,
446
- identity: identityByUserId.get(user._id),
447
- }
448
- : null;
449
- }),
450
- )
451
- ).filter(Boolean) as Array<{
452
- user: any;
453
- member: any;
454
- identity?: any;
455
- }>;
456
- const listRequest = parseScimListRequest(state.url);
457
- const filtered = filterScimCollection(users, listRequest.filter, {
458
- id: (item: { user: any }, value: string) => item.user._id === value,
459
- externalId: (item: { identity?: any }, value: string) =>
460
- item.identity?.externalId === value,
461
- userName: (item: { user: any }, value: string) =>
462
- item.user.email === value,
463
- "emails.value": (item: { user: any }, value: string) =>
464
- item.user.email === value,
465
- active: (item: { identity?: any; member: any }, value: string) =>
466
- String(item.identity?.active ?? item.member.status === "active") ===
467
- value,
468
- });
469
- if (state.parsedPath.resourceId) {
470
- const resource = filtered.find(
471
- ({ user }) => user._id === state.parsedPath.resourceId,
472
- );
473
- return resource
474
- ? scimJson(
475
- serializeScimUser({
476
- id: resource.user._id,
477
- user: resource.user,
478
- externalId: resource.identity?.externalId,
479
- location: `${state.url.origin}${state.url.pathname.replace(/\/[^/]+$/, "")}/${resource.user._id}`,
480
- active:
481
- resource.identity?.active ??
482
- resource.member.status === "active",
483
- }),
484
- 200,
485
- {
486
- Location: `${state.url.origin}${state.url.pathname.replace(/\/[^/]+$/, "")}/${resource.user._id}`,
487
- },
488
- )
489
- : scimError(404, "notFound", "User not found.");
490
- }
491
- const paged = paginateScimCollection(filtered, listRequest);
492
- await state.recordScimEvent(
493
- "enterprise.scim.read",
494
- true,
495
- "enterprise_scim",
496
- state.scimConfig._id,
497
- );
498
- return scimJson({
499
- schemas: ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
500
- Resources: paged.map(({ user, identity, member }) =>
501
- serializeScimUser({
502
- id: user._id,
503
- user,
504
- externalId: identity?.externalId,
505
- location: `${state.url.origin}${state.url.pathname}/${user._id}`,
506
- active: identity?.active ?? member.status === "active",
507
- }),
508
- ),
509
- totalResults: filtered.length,
510
- startIndex: listRequest.startIndex,
511
- itemsPerPage: paged.length,
512
- });
513
- };
514
-
515
- const handleUsersPost: ScimHandler = async (state) => {
516
- const body = await readScimJson(state.request);
517
- const primaryEmail = Array.isArray(body.emails)
518
- ? (body.emails.find((entry) => entry.primary === true)?.value ??
519
- body.emails[0]?.value)
520
- : undefined;
521
- const phone = Array.isArray(body.phoneNumbers)
522
- ? body.phoneNumbers[0]?.value
523
- : undefined;
524
- const userId = (await state.ctx.runMutation(
525
- config.component.public.userInsert,
526
- {
527
- data: {
528
- name: body.displayName ?? body.name?.formatted,
529
- email: primaryEmail ?? body.userName,
530
- ...(typeof (primaryEmail ?? body.userName) === "string"
531
- ? { emailVerificationTime: Date.now() }
532
- : {}),
533
- phone,
534
- ...(typeof phone === "string"
535
- ? { phoneVerificationTime: Date.now() }
536
- : {}),
537
- },
538
- },
539
- )) as string;
540
- try {
541
- await auth.member.create(state.ctx, {
542
- groupId: state.enterprise.groupId,
543
- userId,
544
- roleIds: state.policy.provisioning.jit.defaultRoleIds,
545
- status: body.active === false ? "inactive" : "active",
546
- });
547
- } catch {}
548
- if (typeof body.externalId === "string") {
549
- await state.ctx.runMutation(
550
- config.component.public.enterpriseScimIdentityUpsert,
551
- {
552
- enterpriseId: state.enterprise._id,
553
- groupId: state.enterprise.groupId,
554
- resourceType: "user",
555
- externalId: body.externalId,
556
- userId,
557
- active: body.active !== false,
558
- raw: body,
559
- lastProvisionedAt: Date.now(),
560
- },
561
- );
562
- }
563
- await state.recordScimEvent(
564
- "enterprise.scim.user.created",
565
- true,
566
- "user",
567
- userId,
568
- );
569
- const createdUser = await auth.user.get(state.ctx, userId);
570
- const location = `${state.url.origin}${state.url.pathname}/${userId}`;
571
- return scimJson(
572
- serializeScimUser({
573
- id: userId,
574
- user: createdUser ?? {},
575
- externalId: body.externalId,
576
- location,
577
- active: body.active !== false,
578
- }),
579
- 201,
580
- { Location: location },
581
- );
582
- };
583
-
584
- const handleUsersUpsert: ScimHandler = async (state) => {
585
- const missing = requireScimResourceId(
586
- state.parsedPath.resourceId,
587
- "User",
588
- );
589
- if (missing) return missing;
590
- const userId = state.parsedPath.resourceId!;
591
- const existingUser = await auth.user.get(state.ctx, userId);
592
- if (!existingUser) {
593
- return scimError(404, "notFound", "User not found.");
594
- }
595
- const body = await readScimJson(state.request);
596
- const patchData: Record<string, unknown> = {};
597
- let nextActive: boolean | undefined;
598
- if (state.request.method === "PUT") {
599
- patchData.name = body.displayName ?? body.name?.formatted;
600
- patchData.email =
601
- body.userName ??
602
- (Array.isArray(body.emails) ? body.emails[0]?.value : undefined);
603
- patchData.phone = Array.isArray(body.phoneNumbers)
604
- ? body.phoneNumbers[0]?.value
605
- : undefined;
606
- if (typeof patchData.email === "string") {
607
- patchData.emailVerificationTime = Date.now();
608
- }
609
- if (typeof patchData.phone === "string") {
610
- patchData.phoneVerificationTime = Date.now();
611
- }
612
- } else {
613
- for (const operation of Array.isArray(body.Operations)
614
- ? body.Operations
615
- : []) {
616
- if (operation.path === "active") {
617
- nextActive = operation.value;
618
- }
619
- if (
620
- operation.path === "displayName" ||
621
- operation.path === "name.formatted"
622
- ) {
623
- patchData.name = operation.value;
624
- }
625
- if (
626
- operation.path === "userName" ||
627
- operation.path === "emails.value"
628
- ) {
629
- patchData.email = operation.value;
630
- if (typeof operation.value === "string") {
631
- patchData.emailVerificationTime = Date.now();
632
- }
633
- }
634
- if (operation.path === "phoneNumbers.value") {
635
- patchData.phone = operation.value;
636
- if (typeof operation.value === "string") {
637
- patchData.phoneVerificationTime = Date.now();
638
- }
639
- }
640
- }
641
- }
642
- await state.ctx.runMutation(config.component.public.userPatch, {
643
- userId,
644
- data: patchData,
645
- });
646
- const resolution = await auth.member.inspect(state.ctx, {
647
- groupId: state.enterprise.groupId,
648
- userId,
649
- });
650
- if (resolution.membership) {
651
- await auth.member.update(state.ctx, resolution.membership._id, {
652
- status:
653
- body.active === false || nextActive === false
654
- ? "inactive"
655
- : "active",
656
- });
657
- }
658
- await state.ctx.runMutation(
659
- config.component.public.enterpriseScimIdentityUpsert,
660
- {
661
- enterpriseId: state.enterprise._id,
662
- groupId: state.enterprise.groupId,
663
- resourceType: "user",
664
- externalId:
665
- typeof body.externalId === "string"
666
- ? body.externalId
667
- : ((
668
- await state.ctx.runQuery(
669
- config.component.public
670
- .enterpriseScimIdentityGetByEnterpriseAndUser,
671
- {
672
- enterpriseId: state.enterprise._id,
673
- userId,
674
- },
675
- )
676
- )?.externalId ?? userId),
677
- userId,
678
- active: body.active !== false && nextActive !== false,
679
- raw: body,
680
- lastProvisionedAt: Date.now(),
681
- },
682
- );
683
- await state.recordScimEvent(
684
- "enterprise.scim.user.updated",
685
- true,
686
- "user",
687
- userId,
688
- );
689
- const updatedUser = await auth.user.get(state.ctx, userId);
690
- const location = `${state.url.origin}${state.url.pathname}`;
691
- return scimJson(
692
- serializeScimUser({
693
- id: userId,
694
- user: updatedUser ?? existingUser,
695
- externalId:
696
- typeof body.externalId === "string" ? body.externalId : undefined,
697
- location,
698
- active: body.active !== false && nextActive !== false,
699
- }),
700
- 200,
701
- { Location: location },
702
- );
703
- };
704
-
705
- const handleUsersDelete: ScimHandler = async (state) => {
706
- const missing = requireScimResourceId(
707
- state.parsedPath.resourceId,
708
- "User",
709
- );
710
- if (missing) return missing;
711
- const userId = state.parsedPath.resourceId!;
712
- const resolution = await auth.member.inspect(state.ctx, {
713
- groupId: state.enterprise.groupId,
714
- userId,
715
- });
716
- if (resolution.membership) {
717
- await auth.member.delete(state.ctx, resolution.membership._id);
718
- }
719
- const identity = await state.ctx.runQuery(
720
- config.component.public.enterpriseScimIdentityGetByEnterpriseAndUser,
721
- {
722
- enterpriseId: state.enterprise._id,
723
- userId,
724
- },
725
- );
726
- if (identity) {
727
- if (state.policy.provisioning.deprovision.mode === "hard") {
728
- await state.ctx.runMutation(
729
- config.component.public.enterpriseScimIdentityDelete,
730
- { identityId: identity._id },
731
- );
732
- } else {
733
- await state.ctx.runMutation(
734
- config.component.public.enterpriseScimIdentityUpsert,
735
- {
736
- enterpriseId: identity.enterpriseId,
737
- groupId: identity.groupId,
738
- resourceType: identity.resourceType,
739
- externalId: identity.externalId,
740
- userId: identity.userId,
741
- mappedGroupId: identity.mappedGroupId,
742
- active: false,
743
- raw: identity.raw,
744
- lastProvisionedAt: Date.now(),
745
- },
746
- );
747
- }
748
- }
749
- await state.recordScimEvent(
750
- "enterprise.scim.user.deleted",
751
- true,
752
- "user",
753
- userId,
754
- );
755
- return new Response(null, { status: 204 });
756
- };
757
-
758
- const handleGroupsGet: ScimHandler = async (state) => {
759
- const groupsList = await auth.group.list(state.ctx, {
760
- where: { parentGroupId: state.enterprise.groupId },
761
- limit: 100,
762
- });
763
- const identities = await state.ctx.runQuery(
764
- config.component.public.enterpriseScimIdentityListByEnterprise,
765
- { enterpriseId: state.enterprise._id },
766
- );
767
- const identityByGroupId = new Map(
768
- identities
769
- .filter((identity: any) => identity.mappedGroupId !== undefined)
770
- .map((identity: any) => [identity.mappedGroupId, identity]),
771
- );
772
- const groups = groupsList.items.map((group: any) => ({
773
- group,
774
- identity: identityByGroupId.get(group._id),
775
- }));
776
- const listRequest = parseScimListRequest(state.url);
777
- const filtered = filterScimCollection<{
778
- group: any;
779
- identity?: any;
780
- }>(groups, listRequest.filter, {
781
- id: (item: { group: any }, value: string) => item.group._id === value,
782
- externalId: (item: { identity?: any }, value: string) =>
783
- item.identity?.externalId === value,
784
- displayName: (item: { group: any }, value: string) =>
785
- item.group.name === value,
786
- });
787
- if (state.parsedPath.resourceId) {
788
- const resource = filtered.find(
789
- ({ group }) => group._id === state.parsedPath.resourceId,
790
- );
791
- if (!resource) {
792
- return scimError(404, "notFound", "Group not found.");
793
- }
794
- const members = (
795
- await auth.member.list(state.ctx, {
796
- where: {
797
- groupId: resource.group._id,
798
- status: "active",
799
- },
800
- limit: 100,
801
- })
802
- ).items.map((member: any) => ({ value: member.userId }));
803
- const location = `${state.url.origin}${state.url.pathname.replace(/\/[^/]+$/, "")}/${resource.group._id}`;
804
- return scimJson(
805
- serializeScimGroup({
806
- id: resource.group._id,
807
- group: resource.group,
808
- externalId: resource.identity?.externalId,
809
- location,
810
- members,
811
- }),
812
- 200,
813
- { Location: location },
814
- );
815
- }
816
- const paged = paginateScimCollection(filtered, listRequest);
817
- return scimJson({
818
- schemas: ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
819
- Resources: paged.map(({ group, identity }) =>
820
- serializeScimGroup({
821
- id: group._id,
822
- group,
823
- externalId: identity?.externalId,
824
- location: `${state.url.origin}${state.url.pathname}/${group._id}`,
825
- }),
826
- ),
827
- totalResults: filtered.length,
828
- startIndex: listRequest.startIndex,
829
- itemsPerPage: paged.length,
830
- });
831
- };
832
-
833
- const handleGroupsPost: ScimHandler = async (state) => {
834
- const body = await readScimJson(state.request);
835
- const { groupId } = await auth.group.create(state.ctx, {
836
- name: String(body.displayName ?? "Group"),
837
- parentGroupId: state.enterprise.groupId,
838
- type: "organization",
839
- });
840
- await state.ctx.runMutation(
841
- config.component.public.enterpriseScimIdentityUpsert,
842
- {
843
- enterpriseId: state.enterprise._id,
844
- groupId: state.enterprise.groupId,
845
- resourceType: "group",
846
- externalId: body.externalId ?? groupId,
847
- mappedGroupId: groupId,
848
- active: true,
849
- raw: body,
850
- lastProvisionedAt: Date.now(),
851
- },
852
- );
853
- for (const member of Array.isArray(body.members) ? body.members : []) {
854
- try {
855
- await auth.member.create(state.ctx, {
856
- groupId,
857
- userId: String(member.value),
858
- roleIds: state.policy.provisioning.jit.defaultRoleIds,
859
- status: "active",
860
- });
861
- } catch {}
862
- }
863
- await state.recordScimEvent(
864
- "enterprise.scim.group.created",
865
- true,
866
- "group",
867
- groupId,
868
- );
869
- const group = await auth.group.get(state.ctx, groupId);
870
- const location = `${state.url.origin}${state.url.pathname}/${groupId}`;
871
- return scimJson(
872
- serializeScimGroup({
873
- id: groupId,
874
- group: group ?? {},
875
- externalId: body.externalId,
876
- location,
877
- members: (
878
- await auth.member.list(state.ctx, {
879
- where: { groupId, status: "active" },
880
- limit: 100,
881
- })
882
- ).items.map((member: any) => ({ value: member.userId })),
883
- }),
884
- 201,
885
- { Location: location },
886
- );
887
- };
888
-
889
- const handleGroupsPatch: ScimHandler = async (state) => {
890
- const missing = requireScimResourceId(
891
- state.parsedPath.resourceId,
892
- "Group",
893
- );
894
- if (missing) return missing;
895
- const groupId = state.parsedPath.resourceId!;
896
- const body = await readScimJson(state.request);
897
- for (const operation of Array.isArray(body.Operations)
898
- ? body.Operations
899
- : []) {
900
- if (operation.path === "displayName") {
901
- await auth.group.update(state.ctx, groupId, {
902
- name: operation.value,
903
- });
904
- }
905
- if (operation.path === "members" && operation.op === "add") {
906
- for (const member of Array.isArray(operation.value)
907
- ? operation.value
908
- : []) {
909
- try {
910
- await auth.member.create(state.ctx, {
911
- groupId,
912
- userId: String(member.value),
913
- roleIds: state.policy.provisioning.jit.defaultRoleIds,
914
- status: "active",
915
- });
916
- } catch {}
917
- }
918
- }
919
- if (operation.path === "members" && operation.op === "replace") {
920
- const currentMembers = (
921
- await auth.member.list(state.ctx, {
922
- where: { groupId, status: "active" },
923
- limit: 100,
924
- })
925
- ).items as Array<{ _id: string; userId: string }>;
926
- const currentUserIds = new Set<string>(
927
- currentMembers.map((member) => member.userId),
928
- );
929
- const nextUserIds = new Set<string>(
930
- (Array.isArray(operation.value) ? operation.value : []).map(
931
- (member: any) => String(member.value),
932
- ),
933
- );
934
- for (const member of currentMembers) {
935
- if (!nextUserIds.has(member.userId)) {
936
- await auth.member.delete(state.ctx, member._id);
937
- }
938
- }
939
- for (const userId of nextUserIds.values()) {
940
- if (!currentUserIds.has(userId)) {
941
- try {
942
- await auth.member.create(state.ctx, {
943
- groupId,
944
- userId,
945
- roleIds: state.policy.provisioning.jit.defaultRoleIds,
946
- status: "active",
947
- });
948
- } catch {}
949
- }
950
- }
951
- }
952
- if (
953
- typeof operation.path === "string" &&
954
- operation.op === "remove" &&
955
- operation.path.startsWith("members[")
956
- ) {
957
- const match = operation.path.match(
958
- /^members\[value eq "([^"]+)"\]$/,
959
- );
960
- const userId = match?.[1];
961
- if (userId) {
962
- const resolution = await auth.member.inspect(state.ctx, {
963
- groupId,
964
- userId,
965
- });
966
- if (resolution.membership) {
967
- await auth.member.delete(state.ctx, resolution.membership._id);
968
- }
969
- }
970
- }
971
- }
972
- await state.recordScimEvent(
973
- "enterprise.scim.group.updated",
974
- true,
975
- "group",
976
- groupId,
977
- );
978
- const group = await auth.group.get(state.ctx, groupId);
979
- const location = `${state.url.origin}${state.url.pathname}`;
980
- const members = (
981
- await auth.member.list(state.ctx, {
982
- where: { groupId, status: "active" },
983
- limit: 100,
984
- })
985
- ).items as Array<{ userId: string }>;
986
- return scimJson(
987
- serializeScimGroup({
988
- id: groupId,
989
- group: group ?? {},
990
- location,
991
- members: members.map((member) => ({
992
- value: member.userId,
993
- })),
994
- }),
995
- 200,
996
- { Location: location },
997
- );
998
- };
999
-
1000
- const handleGroupsDelete: ScimHandler = async (state) => {
1001
- const missing = requireScimResourceId(
1002
- state.parsedPath.resourceId,
1003
- "Group",
1004
- );
1005
- if (missing) return missing;
1006
- const groupId = state.parsedPath.resourceId!;
1007
- await auth.group.delete(state.ctx, groupId);
1008
- const identity = await state.ctx.runQuery(
1009
- config.component.public.enterpriseScimIdentityGetByMappedGroup,
1010
- { mappedGroupId: groupId },
1011
- );
1012
- if (identity) {
1013
- await state.ctx.runMutation(
1014
- config.component.public.enterpriseScimIdentityDelete,
1015
- { identityId: identity._id },
1016
- );
1017
- }
1018
- await state.recordScimEvent(
1019
- "enterprise.scim.group.deleted",
1020
- true,
1021
- "group",
1022
- groupId,
1023
- );
1024
- return new Response(null, { status: 204 });
1025
- };
1026
-
1027
- const scimHandlers: Record<
1028
- string,
1029
- Partial<Record<string, ScimHandler>>
1030
- > = {
1031
- ServiceProviderConfig: {
1032
- GET: async () =>
1033
- scimJson({
1034
- schemas: [
1035
- "urn:ietf:params:scim:schemas:core:2.0:ServiceProviderConfig",
1036
- ],
1037
- patch: { supported: true },
1038
- bulk: {
1039
- supported: false,
1040
- maxOperations: 0,
1041
- maxPayloadSize: 0,
1042
- },
1043
- filter: { supported: true, maxResults: 100 },
1044
- changePassword: { supported: false },
1045
- sort: { supported: false },
1046
- etag: { supported: false },
1047
- authenticationSchemes: [
1048
- {
1049
- type: "oauthbearertoken",
1050
- name: "Bearer Token",
1051
- description:
1052
- "Use the SCIM token generated by Convex Auth enterprise.",
1053
- },
1054
- ],
1055
- }),
1056
- },
1057
- Schemas: {
1058
- GET: async (state) =>
1059
- handleStaticScimCollection(
1060
- SCIM_SCHEMAS,
1061
- state.parsedPath.resourceId,
1062
- {
1063
- by: "id",
1064
- notFound: "Schema not found.",
1065
- },
1066
- ),
1067
- },
1068
- ResourceTypes: {
1069
- GET: async (state) =>
1070
- handleStaticScimCollection(
1071
- SCIM_RESOURCE_TYPES,
1072
- state.parsedPath.resourceId,
1073
- { by: "name", notFound: "Resource type not found." },
1074
- ),
1075
- },
1076
- Users: {
1077
- GET: handleUsersGet,
1078
- POST: handleUsersPost,
1079
- PATCH: handleUsersUpsert,
1080
- PUT: handleUsersUpsert,
1081
- DELETE: handleUsersDelete,
1082
- },
1083
- Groups: {
1084
- GET: handleGroupsGet,
1085
- POST: handleGroupsPost,
1086
- PATCH: handleGroupsPatch,
1087
- DELETE: handleGroupsDelete,
1088
- },
1089
- };
1090
-
1091
- const handler =
1092
- scimHandlers[state.parsedPath.resource]?.[state.request.method];
1093
- return handler
1094
- ? await handler(state)
1095
- : scimError(404, "notFound", "SCIM resource not found.");
1096
- } catch (error) {
1097
- if (
1098
- error instanceof Error &&
1099
- error.message === "Unsupported SCIM filter."
1100
- ) {
1101
- return scimError(400, "invalidFilter", error.message);
1102
- }
1103
- if (
1104
- error instanceof ConvexError &&
1105
- typeof error.data === "object" &&
1106
- error.data !== null &&
1107
- "code" in error.data &&
1108
- "message" in error.data
1109
- ) {
1110
- const code = error.data.code as string;
1111
- const status =
1112
- code === "MISSING_BEARER_TOKEN" || code === "INVALID_API_KEY"
1113
- ? 401
1114
- : 400;
1115
- return scimError(status, code, error.data.message);
1116
- }
1117
- throw error;
1118
- }
1119
- };
1120
-
1121
- addSSORoutes(http, {
1122
- routeBase: ENTERPRISE_CONTROL_ROUTE_BASE,
1123
- convertErrorsToResponse,
1124
- handleSamlMetadata: async (ctx, _request, runtimeRoute) => {
1125
- const { loaded } = await loadActiveEnterpriseSamlOrThrow(
1126
- ctx,
1127
- runtimeRoute.enterpriseId,
1128
- );
1129
- return new Response(
1130
- createEnterpriseSamlMetadataXml({
1131
- rootUrl: requireEnv("CONVEX_SITE_URL"),
1132
- source: loaded.source,
1133
- config: loaded.config,
1134
- }),
1135
- {
1136
- status: 200,
1137
- headers: { "Content-Type": "application/xml" },
1138
- },
1139
- );
1140
- },
1141
- handleSamlSignIn: async (ctx, request, runtimeRoute) => {
1142
- const url = new URL(request.url);
1143
- const verifier = url.searchParams.get("code");
1144
- if (!verifier) {
1145
- throw Cv.error({
1146
- code: "OAUTH_MISSING_VERIFIER",
1147
- message: "Missing sign-in verifier.",
1148
- });
1149
- }
1150
- const { loaded, enterprise } = await loadActiveEnterpriseSamlOrThrow(
1151
- ctx,
1152
- runtimeRoute.enterpriseId,
1153
- );
1154
- const state = generateRandomString(24, INVITE_TOKEN_ALPHABET);
1155
- const signInRequest = createEnterpriseSamlSignInRequest({
1156
- rootUrl: requireEnv("CONVEX_SITE_URL"),
1157
- source: { kind: "enterprise", id: enterprise._id },
1158
- config: loaded.config,
1159
- state,
1160
- signature: `saml ${enterprise._id} pending ${state}`,
1161
- redirectTo: url.searchParams.get("redirectTo") ?? undefined,
1162
- });
1163
- const signature = `saml ${enterprise._id} ${signInRequest.requestId} ${state}`;
1164
- await callVerifierSignature(ctx, { verifier, signature });
1165
- const redirectTo = url.searchParams.get("redirectTo");
1166
- const redirectCookies =
1167
- redirectTo !== null
1168
- ? [
1169
- redirectToParamCookie(
1170
- enterpriseSamlProviderId(enterprise._id),
1171
- redirectTo,
1172
- ),
1173
- ]
1174
- : [];
1175
- const relayState = encodeEnterpriseSamlRelayState({
1176
- source: { kind: "enterprise", id: enterprise._id },
1177
- signature,
1178
- requestId: signInRequest.requestId,
1179
- state,
1180
- redirectTo: url.searchParams.get("redirectTo") ?? undefined,
1181
- });
1182
- if (signInRequest.binding === "redirect" && signInRequest.redirectUrl) {
1183
- const redirectUrl = new URL(signInRequest.redirectUrl);
1184
- redirectUrl.searchParams.set("RelayState", relayState);
1185
- const headers = new Headers({
1186
- Location: redirectUrl.toString(),
1187
- });
1188
- for (const { name, value, options } of redirectCookies as any) {
1189
- headers.append("Set-Cookie", serializeCookie(name, value, options));
1190
- }
1191
- return new Response(null, { status: 302, headers });
1192
- }
1193
- const response = createSamlPostBindingResponse({
1194
- endpoint: signInRequest.post!.endpoint,
1195
- parameter: "SAMLRequest",
1196
- value: signInRequest.post!.value,
1197
- relayState,
1198
- });
1199
- for (const { name, value, options } of redirectCookies as any) {
1200
- response.headers.append(
1201
- "Set-Cookie",
1202
- serializeCookie(name, value, options),
1203
- );
1204
- }
1205
- return response;
1206
- },
1207
- handleOidcSignIn: async (ctx, request, runtimeRoute) => {
1208
- const url = new URL(request.url);
1209
- const verifier = url.searchParams.get("code");
1210
- if (!verifier) {
1211
- throw Cv.error({
1212
- code: "OAUTH_MISSING_VERIFIER",
1213
- message: "Missing sign-in verifier.",
1214
- });
1215
- }
1216
- const { enterprise, oidc } = await loadEnterpriseOidcOrThrow(
1217
- ctx,
1218
- runtimeRoute.enterpriseId,
1219
- );
1220
- const { providerId, provider, oauthConfig } =
1221
- await createEnterpriseOidcRuntime({
1222
- rootUrl: requireEnv("CONVEX_SITE_URL"),
1223
- enterpriseId: enterprise._id,
1224
- oidc,
1225
- });
1226
- const { redirect, cookies, signature } =
1227
- await createOAuthAuthorizationURL(providerId, provider, oauthConfig);
1228
- await callVerifierSignature(ctx, { verifier, signature });
1229
- const redirectTo = url.searchParams.get("redirectTo");
1230
- const headers_ = new Headers({ Location: redirect });
1231
- for (const { name, value, options } of [
1232
- ...cookies,
1233
- ...(redirectTo !== null
1234
- ? [redirectToParamCookie(providerId, redirectTo)]
1235
- : []),
1236
- ] as any) {
1237
- headers_.append("Set-Cookie", serializeCookie(name, value, options));
1238
- }
1239
- return new Response(null, {
1240
- status: 302,
1241
- headers: headers_,
1242
- });
1243
- },
1244
- handleOidcCallback: async (ctx, request, runtimeRoute) => {
1245
- const url = new URL(request.url);
1246
- const { enterprise, oidc } = await loadEnterpriseOidcOrThrow(
1247
- ctx,
1248
- runtimeRoute.enterpriseId,
1249
- );
1250
- const { providerId, provider, oauthConfig } =
1251
- await createEnterpriseOidcRuntime({
1252
- rootUrl: requireEnv("CONVEX_SITE_URL"),
1253
- enterpriseId: enterprise._id,
1254
- oidc,
1255
- });
1256
- const cookies = getCookies(request);
1257
- const maybeRedirectTo = useRedirectToParam(providerId, cookies);
1258
- const destinationUrl = await redirectAbsoluteUrl(config, {
1259
- redirectTo: maybeRedirectTo?.redirectTo,
1260
- });
1261
- const params = url.searchParams;
1262
- const result = (await Fx.run(
1263
- handleOAuthCallback(
1264
- providerId,
1265
- provider,
1266
- oauthConfig,
1267
- Object.fromEntries(params.entries()),
1268
- cookies,
1269
- ),
1270
- )) as any;
1271
- const extraFields = oidc.extraFields as
1272
- | Record<string, string>
1273
- | undefined;
1274
- let profile = result.profile as Record<string, unknown>;
1275
- if (extraFields && typeof profile === "object" && profile) {
1276
- const extend: Record<string, unknown> = {};
1277
- for (const [claimName, fieldName] of Object.entries(extraFields)) {
1278
- if (claimName in profile) {
1279
- extend[fieldName] = profile[claimName];
1280
- }
1281
- }
1282
- if (Object.keys(extend).length > 0) {
1283
- profile = { ...profile, extend };
1284
- }
1285
- }
1286
-
1287
- const verificationCode = await callUserOAuth(ctx, {
1288
- provider: providerId,
1289
- providerAccountId: result.providerAccountId,
1290
- profile,
1291
- signature: result.signature,
1292
- accountExtend: {
1293
- identity: {
1294
- protocol: "oidc",
1295
- enterpriseId: enterprise._id,
1296
- subject: result.providerAccountId,
1297
- issuer: typeof oidc.issuer === "string" ? oidc.issuer : undefined,
1298
- discoveryUrl:
1299
- typeof oidc.discoveryUrl === "string"
1300
- ? oidc.discoveryUrl
1301
- : undefined,
1302
- },
1303
- },
1304
- });
1305
- const headers = new Headers({
1306
- Location: setURLSearchParam(destinationUrl, "code", verificationCode),
1307
- });
1308
- for (const { name, value, options } of result.cookies) {
1309
- headers.append(
1310
- "Set-Cookie",
1311
- serializeCookie(name, value, options as any),
1312
- );
1313
- }
1314
- if (maybeRedirectTo) {
1315
- headers.append(
1316
- "Set-Cookie",
1317
- serializeCookie(
1318
- maybeRedirectTo.updatedCookie.name,
1319
- maybeRedirectTo.updatedCookie.value,
1320
- maybeRedirectTo.updatedCookie.options as any,
1321
- ),
1322
- );
1323
- }
1324
- return new Response(null, { status: 302, headers });
1325
- },
1326
- handleSamlAcs,
1327
- handleSamlSlo,
1328
- handleScimRequest,
1329
- scimError,
1330
- });
1331
- }