@robelest/convex-auth 0.0.4-preview.13 → 0.0.4-preview.15

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 (323) hide show
  1. package/README.md +140 -9
  2. package/dist/bin.cjs +5957 -5478
  3. package/dist/client/index.d.ts +3 -7
  4. package/dist/client/index.d.ts.map +1 -1
  5. package/dist/client/index.js +27 -26
  6. package/dist/client/index.js.map +1 -1
  7. package/dist/component/_generated/api.d.ts +14 -0
  8. package/dist/component/_generated/api.d.ts.map +1 -1
  9. package/dist/component/_generated/api.js.map +1 -1
  10. package/dist/component/_generated/component.d.ts +1513 -3
  11. package/dist/component/_generated/component.d.ts.map +1 -1
  12. package/dist/component/convex.config.d.ts +2 -2
  13. package/dist/component/convex.config.d.ts.map +1 -1
  14. package/dist/component/model.d.ts +153 -0
  15. package/dist/component/model.d.ts.map +1 -0
  16. package/dist/component/model.js +327 -0
  17. package/dist/component/model.js.map +1 -0
  18. package/dist/component/providers/sso.d.ts +1 -1
  19. package/dist/component/public/enterprise.d.ts +49 -0
  20. package/dist/component/public/enterprise.d.ts.map +1 -0
  21. package/dist/component/public/enterprise.js +450 -0
  22. package/dist/component/public/enterprise.js.map +1 -0
  23. package/dist/component/public/factors.d.ts +52 -0
  24. package/dist/component/public/factors.d.ts.map +1 -0
  25. package/dist/component/public/factors.js +285 -0
  26. package/dist/component/public/factors.js.map +1 -0
  27. package/dist/component/public/groups.d.ts +118 -0
  28. package/dist/component/public/groups.d.ts.map +1 -0
  29. package/dist/component/public/groups.js +599 -0
  30. package/dist/component/public/groups.js.map +1 -0
  31. package/dist/component/public/identity.d.ts +93 -0
  32. package/dist/component/public/identity.d.ts.map +1 -0
  33. package/dist/component/public/identity.js +426 -0
  34. package/dist/component/public/identity.js.map +1 -0
  35. package/dist/component/public/keys.d.ts +41 -0
  36. package/dist/component/public/keys.d.ts.map +1 -0
  37. package/dist/component/public/keys.js +157 -0
  38. package/dist/component/public/keys.js.map +1 -0
  39. package/dist/component/public/shared.d.ts +26 -0
  40. package/dist/component/public/shared.d.ts.map +1 -0
  41. package/dist/component/public/shared.js +32 -0
  42. package/dist/component/public/shared.js.map +1 -0
  43. package/dist/component/public.d.ts +9 -321
  44. package/dist/component/public.d.ts.map +1 -1
  45. package/dist/component/public.js +6 -2145
  46. package/dist/component/schema.d.ts +368 -258
  47. package/dist/component/schema.js +23 -27
  48. package/dist/component/schema.js.map +1 -1
  49. package/dist/component/server/auth.d.ts +42 -7
  50. package/dist/component/server/auth.d.ts.map +1 -1
  51. package/dist/component/server/auth.js +70 -6
  52. package/dist/component/server/auth.js.map +1 -1
  53. package/dist/component/server/cookies.js +3 -0
  54. package/dist/component/server/cookies.js.map +1 -1
  55. package/dist/component/server/db.js +1 -0
  56. package/dist/component/server/db.js.map +1 -1
  57. package/dist/component/server/device.js +3 -1
  58. package/dist/component/server/device.js.map +1 -1
  59. package/dist/component/server/domains/core.js +466 -0
  60. package/dist/component/server/domains/core.js.map +1 -0
  61. package/dist/component/server/domains/sso.js +689 -0
  62. package/dist/component/server/domains/sso.js.map +1 -0
  63. package/dist/component/server/factory.d.ts +136 -0
  64. package/dist/component/server/factory.d.ts.map +1 -0
  65. package/dist/component/server/factory.js +1128 -0
  66. package/dist/component/server/factory.js.map +1 -0
  67. package/dist/component/server/fx.js +2 -1
  68. package/dist/component/server/fx.js.map +1 -1
  69. package/dist/component/server/http.js +287 -0
  70. package/dist/component/server/http.js.map +1 -0
  71. package/dist/component/server/identity.js +13 -0
  72. package/dist/component/server/identity.js.map +1 -0
  73. package/dist/component/server/keys.js +4 -0
  74. package/dist/component/server/keys.js.map +1 -1
  75. package/dist/component/server/mutations/account.js +1 -1
  76. package/dist/component/server/mutations/index.js +2 -2
  77. package/dist/component/server/mutations/index.js.map +1 -1
  78. package/dist/component/server/mutations/invalidate.js +1 -1
  79. package/dist/component/server/mutations/oauth.js +10 -7
  80. package/dist/component/server/mutations/oauth.js.map +1 -1
  81. package/dist/component/server/mutations/refresh.js +1 -1
  82. package/dist/component/server/mutations/register.js +1 -1
  83. package/dist/component/server/mutations/retrieve.js +1 -1
  84. package/dist/component/server/mutations/signature.js +1 -1
  85. package/dist/component/server/mutations/store.js +6 -3
  86. package/dist/component/server/mutations/store.js.map +1 -1
  87. package/dist/component/server/mutations/verify.js +1 -1
  88. package/dist/component/server/oauth.js +3 -0
  89. package/dist/component/server/oauth.js.map +1 -1
  90. package/dist/component/server/passkey.js +3 -2
  91. package/dist/component/server/passkey.js.map +1 -1
  92. package/dist/component/server/provider.js +2 -0
  93. package/dist/component/server/provider.js.map +1 -1
  94. package/dist/component/server/providers.js +3 -0
  95. package/dist/component/server/providers.js.map +1 -1
  96. package/dist/component/server/ratelimit.js +3 -0
  97. package/dist/component/server/ratelimit.js.map +1 -1
  98. package/dist/component/server/redirects.js +2 -0
  99. package/dist/component/server/redirects.js.map +1 -1
  100. package/dist/component/server/refresh.js +5 -0
  101. package/dist/component/server/refresh.js.map +1 -1
  102. package/dist/component/server/sessions.js +5 -0
  103. package/dist/component/server/sessions.js.map +1 -1
  104. package/dist/component/server/signin.js +2 -1
  105. package/dist/component/server/signin.js.map +1 -1
  106. package/dist/component/server/sso.js +166 -19
  107. package/dist/component/server/sso.js.map +1 -1
  108. package/dist/component/server/tokens.js +1 -0
  109. package/dist/component/server/tokens.js.map +1 -1
  110. package/dist/component/server/totp.js +4 -2
  111. package/dist/component/server/totp.js.map +1 -1
  112. package/dist/component/server/types.d.ts +50 -35
  113. package/dist/component/server/types.d.ts.map +1 -1
  114. package/dist/component/server/types.js.map +1 -1
  115. package/dist/component/server/users.js +1 -0
  116. package/dist/component/server/users.js.map +1 -1
  117. package/dist/component/server/utils.js +44 -2
  118. package/dist/component/server/utils.js.map +1 -1
  119. package/dist/providers/anonymous.d.ts +1 -1
  120. package/dist/providers/credentials.d.ts +1 -1
  121. package/dist/providers/password.d.ts +1 -1
  122. package/dist/providers/sso.d.ts +1 -1
  123. package/dist/providers/sso.js.map +1 -1
  124. package/dist/server/auth.d.ts +44 -9
  125. package/dist/server/auth.d.ts.map +1 -1
  126. package/dist/server/auth.js +70 -6
  127. package/dist/server/auth.js.map +1 -1
  128. package/dist/server/cookies.d.ts +1 -38
  129. package/dist/server/cookies.js +3 -0
  130. package/dist/server/cookies.js.map +1 -1
  131. package/dist/server/db.d.ts +1 -125
  132. package/dist/server/db.js +1 -0
  133. package/dist/server/db.js.map +1 -1
  134. package/dist/server/device.d.ts +1 -24
  135. package/dist/server/device.js +3 -1
  136. package/dist/server/device.js.map +1 -1
  137. package/dist/server/domains/core.d.ts +320 -0
  138. package/dist/server/domains/core.d.ts.map +1 -0
  139. package/dist/server/domains/core.js +466 -0
  140. package/dist/server/domains/core.js.map +1 -0
  141. package/dist/server/domains/sso.d.ts +340 -0
  142. package/dist/server/domains/sso.d.ts.map +1 -0
  143. package/dist/server/domains/sso.js +689 -0
  144. package/dist/server/domains/sso.js.map +1 -0
  145. package/dist/server/enterpriseValidators.d.ts +1 -0
  146. package/dist/server/enterpriseValidators.js +56 -0
  147. package/dist/server/enterpriseValidators.js.map +1 -0
  148. package/dist/server/factory.d.ts +136 -0
  149. package/dist/server/factory.d.ts.map +1 -0
  150. package/dist/server/factory.js +1128 -0
  151. package/dist/server/factory.js.map +1 -0
  152. package/dist/server/fx.d.ts +1 -16
  153. package/dist/server/fx.d.ts.map +1 -1
  154. package/dist/server/fx.js +1 -0
  155. package/dist/server/fx.js.map +1 -1
  156. package/dist/server/http.d.ts +59 -0
  157. package/dist/server/http.d.ts.map +1 -0
  158. package/dist/server/http.js +287 -0
  159. package/dist/server/http.js.map +1 -0
  160. package/dist/server/identity.d.ts +1 -0
  161. package/dist/server/identity.js +13 -0
  162. package/dist/server/identity.js.map +1 -0
  163. package/dist/server/index.d.ts +432 -1
  164. package/dist/server/index.d.ts.map +1 -1
  165. package/dist/server/index.js +486 -36
  166. package/dist/server/index.js.map +1 -1
  167. package/dist/server/keys.d.ts +1 -57
  168. package/dist/server/keys.js +4 -0
  169. package/dist/server/keys.js.map +1 -1
  170. package/dist/server/mutations/account.d.ts +7 -7
  171. package/dist/server/mutations/account.d.ts.map +1 -1
  172. package/dist/server/mutations/code.d.ts +13 -13
  173. package/dist/server/mutations/index.d.ts +107 -107
  174. package/dist/server/mutations/index.d.ts.map +1 -1
  175. package/dist/server/mutations/index.js +1 -1
  176. package/dist/server/mutations/index.js.map +1 -1
  177. package/dist/server/mutations/invalidate.d.ts +5 -5
  178. package/dist/server/mutations/oauth.d.ts +10 -10
  179. package/dist/server/mutations/oauth.d.ts.map +1 -1
  180. package/dist/server/mutations/oauth.js +9 -6
  181. package/dist/server/mutations/oauth.js.map +1 -1
  182. package/dist/server/mutations/refresh.d.ts +4 -4
  183. package/dist/server/mutations/register.d.ts +12 -12
  184. package/dist/server/mutations/register.d.ts.map +1 -1
  185. package/dist/server/mutations/retrieve.d.ts +1 -1
  186. package/dist/server/mutations/signature.d.ts +5 -5
  187. package/dist/server/mutations/signature.d.ts.map +1 -1
  188. package/dist/server/mutations/signin.d.ts +1 -1
  189. package/dist/server/mutations/signout.d.ts +1 -1
  190. package/dist/server/mutations/store.d.ts +3 -2
  191. package/dist/server/mutations/store.d.ts.map +1 -1
  192. package/dist/server/mutations/store.js +6 -3
  193. package/dist/server/mutations/store.js.map +1 -1
  194. package/dist/server/mutations/verifier.d.ts +1 -1
  195. package/dist/server/mutations/verify.d.ts +4 -4
  196. package/dist/server/oauth.d.ts +1 -59
  197. package/dist/server/oauth.js +3 -0
  198. package/dist/server/oauth.js.map +1 -1
  199. package/dist/server/passkey.d.ts.map +1 -1
  200. package/dist/server/passkey.js +3 -2
  201. package/dist/server/passkey.js.map +1 -1
  202. package/dist/server/provider.d.ts +1 -14
  203. package/dist/server/provider.d.ts.map +1 -1
  204. package/dist/server/provider.js +2 -0
  205. package/dist/server/provider.js.map +1 -1
  206. package/dist/server/providers.js +3 -0
  207. package/dist/server/providers.js.map +1 -1
  208. package/dist/server/ratelimit.d.ts +1 -22
  209. package/dist/server/ratelimit.js +3 -0
  210. package/dist/server/ratelimit.js.map +1 -1
  211. package/dist/server/redirects.d.ts +1 -10
  212. package/dist/server/redirects.js +2 -0
  213. package/dist/server/redirects.js.map +1 -1
  214. package/dist/server/refresh.d.ts +1 -37
  215. package/dist/server/refresh.js +5 -0
  216. package/dist/server/refresh.js.map +1 -1
  217. package/dist/server/sessions.d.ts +1 -28
  218. package/dist/server/sessions.js +5 -0
  219. package/dist/server/sessions.js.map +1 -1
  220. package/dist/server/signin.d.ts +1 -55
  221. package/dist/server/signin.js +2 -1
  222. package/dist/server/signin.js.map +1 -1
  223. package/dist/server/sso.d.ts +1 -348
  224. package/dist/server/sso.js +165 -18
  225. package/dist/server/sso.js.map +1 -1
  226. package/dist/server/templates.d.ts +1 -21
  227. package/dist/server/templates.js +1 -0
  228. package/dist/server/templates.js.map +1 -1
  229. package/dist/server/tokens.d.ts +1 -11
  230. package/dist/server/tokens.js +1 -0
  231. package/dist/server/tokens.js.map +1 -1
  232. package/dist/server/totp.d.ts +1 -23
  233. package/dist/server/totp.js +4 -2
  234. package/dist/server/totp.js.map +1 -1
  235. package/dist/server/types.d.ts +55 -71
  236. package/dist/server/types.d.ts.map +1 -1
  237. package/dist/server/types.js.map +1 -1
  238. package/dist/server/users.d.ts +1 -31
  239. package/dist/server/users.js +1 -0
  240. package/dist/server/users.js.map +1 -1
  241. package/dist/server/utils.d.ts +1 -27
  242. package/dist/server/utils.js +44 -2
  243. package/dist/server/utils.js.map +1 -1
  244. package/dist/server/version.d.ts +1 -1
  245. package/dist/server/version.js +1 -1
  246. package/dist/server/version.js.map +1 -1
  247. package/package.json +4 -5
  248. package/src/cli/bin.ts +5 -0
  249. package/src/cli/index.ts +22 -9
  250. package/src/cli/keys.ts +3 -0
  251. package/src/client/index.ts +36 -37
  252. package/src/component/_generated/api.ts +14 -0
  253. package/src/component/_generated/component.ts +1920 -3
  254. package/src/component/index.ts +2 -0
  255. package/src/component/model.ts +424 -0
  256. package/src/component/public/enterprise.ts +654 -0
  257. package/src/component/public/factors.ts +332 -0
  258. package/src/component/public/groups.ts +951 -0
  259. package/src/component/public/identity.ts +566 -0
  260. package/src/component/public/keys.ts +209 -0
  261. package/src/component/public/shared.ts +117 -0
  262. package/src/component/public.ts +5 -2965
  263. package/src/component/schema.ts +47 -57
  264. package/src/providers/sso.ts +1 -1
  265. package/src/server/auth.ts +192 -9
  266. package/src/server/cookies.ts +3 -0
  267. package/src/server/db.ts +3 -0
  268. package/src/server/device.ts +3 -1
  269. package/src/server/domains/core.ts +916 -0
  270. package/src/server/domains/sso.ts +1462 -0
  271. package/src/server/enterpriseValidators.ts +88 -0
  272. package/src/server/factory.ts +2168 -0
  273. package/src/server/fx.ts +1 -0
  274. package/src/server/http.ts +529 -0
  275. package/src/server/identity.ts +18 -0
  276. package/src/server/index.ts +712 -40
  277. package/src/server/keys.ts +4 -0
  278. package/src/server/mutations/index.ts +1 -1
  279. package/src/server/mutations/oauth.ts +36 -8
  280. package/src/server/mutations/store.ts +6 -3
  281. package/src/server/oauth.ts +6 -0
  282. package/src/server/passkey.ts +3 -2
  283. package/src/server/provider.ts +2 -0
  284. package/src/server/providers.ts +3 -0
  285. package/src/server/ratelimit.ts +3 -0
  286. package/src/server/redirects.ts +2 -0
  287. package/src/server/refresh.ts +5 -0
  288. package/src/server/sessions.ts +5 -0
  289. package/src/server/signin.ts +1 -0
  290. package/src/server/sso.ts +251 -17
  291. package/src/server/templates.ts +1 -0
  292. package/src/server/tokens.ts +1 -0
  293. package/src/server/totp.ts +4 -2
  294. package/src/server/types.ts +85 -77
  295. package/src/server/users.ts +1 -0
  296. package/src/server/utils.ts +71 -1
  297. package/src/server/version.ts +1 -1
  298. package/dist/component/public.js.map +0 -1
  299. package/dist/component/server/implementation.d.ts +0 -1264
  300. package/dist/component/server/implementation.d.ts.map +0 -1
  301. package/dist/component/server/implementation.js +0 -2365
  302. package/dist/component/server/implementation.js.map +0 -1
  303. package/dist/server/cookies.d.ts.map +0 -1
  304. package/dist/server/db.d.ts.map +0 -1
  305. package/dist/server/device.d.ts.map +0 -1
  306. package/dist/server/implementation.d.ts +0 -1264
  307. package/dist/server/implementation.d.ts.map +0 -1
  308. package/dist/server/implementation.js +0 -2365
  309. package/dist/server/implementation.js.map +0 -1
  310. package/dist/server/keys.d.ts.map +0 -1
  311. package/dist/server/oauth.d.ts.map +0 -1
  312. package/dist/server/ratelimit.d.ts.map +0 -1
  313. package/dist/server/redirects.d.ts.map +0 -1
  314. package/dist/server/refresh.d.ts.map +0 -1
  315. package/dist/server/sessions.d.ts.map +0 -1
  316. package/dist/server/signin.d.ts.map +0 -1
  317. package/dist/server/sso.d.ts.map +0 -1
  318. package/dist/server/templates.d.ts.map +0 -1
  319. package/dist/server/tokens.d.ts.map +0 -1
  320. package/dist/server/totp.d.ts.map +0 -1
  321. package/dist/server/users.d.ts.map +0 -1
  322. package/dist/server/utils.d.ts.map +0 -1
  323. package/src/server/implementation.ts +0 -5336
package/src/server/sso.ts CHANGED
@@ -24,14 +24,22 @@ function ensureSamlifyValidator() {
24
24
  setSchemaValidator(_samlifyPermissiveValidator);
25
25
  }
26
26
  import { decodeIdToken } from "arctic";
27
- import { createRemoteJWKSet, decodeProtectedHeader, jwtVerify } from "jose";
27
+ import {
28
+ createRemoteJWKSet,
29
+ customFetch,
30
+ decodeProtectedHeader,
31
+ jwtVerify,
32
+ } from "jose";
28
33
 
29
34
  import type {
35
+ EnterprisePolicy,
36
+ EnterprisePolicyPatch,
30
37
  OAuthMaterializedConfig,
31
38
  OAuthProfile,
32
39
  SAMLAttributeMapping,
33
40
  } from "./types";
34
41
 
42
+ /** @internal */
35
43
  export type ParsedSamlMetadata = {
36
44
  issuer: string;
37
45
  sso: {
@@ -48,8 +56,10 @@ export type ParsedSamlMetadata = {
48
56
  wantsSignedAuthnRequests: boolean;
49
57
  };
50
58
 
59
+ /** @internal */
51
60
  export type EnterpriseSamlSource = { kind: "enterprise"; id: string };
52
61
 
62
+ /** @internal */
53
63
  export type EnterpriseSamlRelayState = {
54
64
  source: EnterpriseSamlSource;
55
65
  signature: string;
@@ -58,18 +68,21 @@ export type EnterpriseSamlRelayState = {
58
68
  redirectTo?: string;
59
69
  };
60
70
 
71
+ /** @internal */
61
72
  export type EnterpriseSamlUrls = {
62
73
  metadataUrl: string;
63
74
  acsUrl: string;
64
75
  sloUrl?: string;
65
76
  };
66
77
 
78
+ /** @internal */
67
79
  export type EnterpriseSamlLoadedSource = {
68
80
  source: EnterpriseSamlSource;
69
81
  config: unknown;
70
82
  status?: string;
71
83
  };
72
84
 
85
+ /** @internal */
73
86
  export type EnterpriseSamlHttpRequest = {
74
87
  url: URL;
75
88
  body: Record<string, string>;
@@ -80,35 +93,44 @@ export type EnterpriseSamlHttpRequest = {
80
93
  hasSamlResponse: boolean;
81
94
  };
82
95
 
96
+ /** @internal */
83
97
  export type ScimListRequest = {
84
98
  startIndex: number;
85
99
  count: number;
86
100
  filter?: { attribute: string; value: string };
87
101
  };
88
102
 
103
+ /** @internal */
89
104
  export const SCIM_USER_SCHEMA_ID = "urn:ietf:params:scim:schemas:core:2.0:User";
105
+ /** @internal */
90
106
  export const SCIM_GROUP_SCHEMA_ID =
91
107
  "urn:ietf:params:scim:schemas:core:2.0:Group";
92
108
 
109
+ /** @internal */
93
110
  export const ENTERPRISE_OIDC_PROVIDER_PREFIX = "enterprise:oidc:";
111
+ /** @internal */
94
112
  export const ENTERPRISE_SAML_PROVIDER_PREFIX = "enterprise:saml:";
95
113
  const OIDC_JWKS_CACHE = new Map<
96
114
  string,
97
115
  ReturnType<typeof createRemoteJWKSet>
98
116
  >();
99
117
 
118
+ /** @internal */
100
119
  export function normalizeDomain(domain: string): string {
101
120
  return domain.trim().toLowerCase().replace(/^@+/, "");
102
121
  }
103
122
 
123
+ /** @internal */
104
124
  export function enterpriseOidcProviderId(enterpriseId: string): string {
105
125
  return `${ENTERPRISE_OIDC_PROVIDER_PREFIX}${enterpriseId}`;
106
126
  }
107
127
 
128
+ /** @internal */
108
129
  export function enterpriseSamlProviderId(enterpriseId: string): string {
109
130
  return `${ENTERPRISE_SAML_PROVIDER_PREFIX}${enterpriseId}`;
110
131
  }
111
132
 
133
+ /** @internal */
112
134
  export function getEnterpriseSamlUrls(opts: {
113
135
  rootUrl: string;
114
136
  source: EnterpriseSamlSource;
@@ -124,6 +146,7 @@ export function getEnterpriseSamlUrls(opts: {
124
146
  };
125
147
  }
126
148
 
149
+ /** @internal */
127
150
  export function getEnterpriseOidcUrls(opts: {
128
151
  rootUrl: string;
129
152
  enterpriseId: string;
@@ -135,12 +158,14 @@ export function getEnterpriseOidcUrls(opts: {
135
158
  };
136
159
  }
137
160
 
161
+ /** @internal */
138
162
  export function isEnterpriseSamlSourceActive(
139
163
  source: EnterpriseSamlLoadedSource,
140
164
  ) {
141
165
  return source.status === "active";
142
166
  }
143
167
 
168
+ /** @internal */
144
169
  export function isEnterpriseProviderId(providerId: string): boolean {
145
170
  return (
146
171
  providerId.startsWith(ENTERPRISE_OIDC_PROVIDER_PREFIX) ||
@@ -153,6 +178,124 @@ const asRecord = (value: unknown) =>
153
178
  ? (value as Record<string, any>)
154
179
  : null;
155
180
 
181
+ /** @internal */
182
+ export const DEFAULT_ENTERPRISE_POLICY: EnterprisePolicy = {
183
+ version: 1,
184
+ identity: {
185
+ accountLinking: {
186
+ oidc: "verifiedEmail",
187
+ saml: "verifiedEmail",
188
+ },
189
+ },
190
+ provisioning: {
191
+ scimReuse: {
192
+ user: "externalId",
193
+ },
194
+ jit: {
195
+ mode: "createUserAndMembership",
196
+ defaultRole: "member",
197
+ },
198
+ deprovision: {
199
+ mode: "soft",
200
+ },
201
+ },
202
+ };
203
+
204
+ /** @internal */
205
+ export function normalizeEnterprisePolicy(policy: unknown): EnterprisePolicy {
206
+ const input = asRecord(policy) ?? {};
207
+ const identity = asRecord(input.identity) ?? {};
208
+ const accountLinking = asRecord(identity.accountLinking) ?? {};
209
+ const provisioning = asRecord(input.provisioning) ?? {};
210
+ const scimReuse = asRecord(provisioning.scimReuse) ?? {};
211
+ const jit = asRecord(provisioning.jit) ?? {};
212
+ const deprovision = asRecord(provisioning.deprovision) ?? {};
213
+ const extend = asRecord(input.extend) ?? undefined;
214
+
215
+ return {
216
+ version: 1,
217
+ identity: {
218
+ accountLinking: {
219
+ oidc:
220
+ accountLinking.oidc === "none"
221
+ ? "none"
222
+ : DEFAULT_ENTERPRISE_POLICY.identity.accountLinking.oidc,
223
+ saml:
224
+ accountLinking.saml === "none"
225
+ ? "none"
226
+ : DEFAULT_ENTERPRISE_POLICY.identity.accountLinking.saml,
227
+ },
228
+ },
229
+ provisioning: {
230
+ scimReuse: {
231
+ user:
232
+ scimReuse.user === "none"
233
+ ? "none"
234
+ : DEFAULT_ENTERPRISE_POLICY.provisioning.scimReuse.user,
235
+ },
236
+ jit: {
237
+ mode:
238
+ jit.mode === "off" ||
239
+ jit.mode === "createUser" ||
240
+ jit.mode === "createUserAndMembership"
241
+ ? jit.mode
242
+ : DEFAULT_ENTERPRISE_POLICY.provisioning.jit.mode,
243
+ defaultRole:
244
+ typeof jit.defaultRole === "string" && jit.defaultRole.length > 0
245
+ ? jit.defaultRole
246
+ : DEFAULT_ENTERPRISE_POLICY.provisioning.jit.defaultRole,
247
+ },
248
+ deprovision: {
249
+ mode:
250
+ deprovision.mode === "hard"
251
+ ? "hard"
252
+ : DEFAULT_ENTERPRISE_POLICY.provisioning.deprovision.mode,
253
+ },
254
+ },
255
+ ...(extend ? { extend } : {}),
256
+ };
257
+ }
258
+
259
+ /** @internal */
260
+ export function patchEnterprisePolicy(
261
+ current: unknown,
262
+ patch: EnterprisePolicyPatch,
263
+ ): EnterprisePolicy {
264
+ const base = normalizeEnterprisePolicy(current);
265
+ return normalizeEnterprisePolicy({
266
+ ...base,
267
+ ...patch,
268
+ identity: {
269
+ ...base.identity,
270
+ ...patch.identity,
271
+ accountLinking: {
272
+ ...base.identity.accountLinking,
273
+ ...patch.identity?.accountLinking,
274
+ },
275
+ },
276
+ provisioning: {
277
+ ...base.provisioning,
278
+ ...patch.provisioning,
279
+ scimReuse: {
280
+ ...base.provisioning.scimReuse,
281
+ ...patch.provisioning?.scimReuse,
282
+ },
283
+ jit: {
284
+ ...base.provisioning.jit,
285
+ ...patch.provisioning?.jit,
286
+ },
287
+ deprovision: {
288
+ ...base.provisioning.deprovision,
289
+ ...patch.provisioning?.deprovision,
290
+ },
291
+ },
292
+ extend:
293
+ patch.extend === undefined
294
+ ? base.extend
295
+ : { ...base.extend, ...patch.extend },
296
+ });
297
+ }
298
+
156
299
  const getProtocolConfig = (config: unknown, protocol: "oidc" | "saml") => {
157
300
  const base = asRecord(config);
158
301
  const direct = base?.[protocol];
@@ -160,14 +303,35 @@ const getProtocolConfig = (config: unknown, protocol: "oidc" | "saml") => {
160
303
  return asRecord(direct) ?? asRecord(viaProtocols) ?? {};
161
304
  };
162
305
 
306
+ /** @internal */
163
307
  export function getOidcConfig(config: unknown): Record<string, any> {
164
308
  return getProtocolConfig(config, "oidc");
165
309
  }
166
310
 
311
+ /** @internal */
312
+ export function getPublicOidcConfig(config: unknown): Record<string, any> {
313
+ const oidc = getOidcConfig(config);
314
+ const { clientSecret: _clientSecret, ...publicOidc } = oidc;
315
+ return publicOidc;
316
+ }
317
+
318
+ /** @internal */
319
+ export function withOidcSecretState(
320
+ config: Record<string, any>,
321
+ hasClientSecret: boolean,
322
+ ) {
323
+ return {
324
+ ...config,
325
+ hasClientSecret,
326
+ };
327
+ }
328
+
329
+ /** @internal */
167
330
  export function getSamlConfig(config: unknown): Record<string, any> {
168
331
  return getProtocolConfig(config, "saml");
169
332
  }
170
333
 
334
+ /** @internal */
171
335
  export function upsertProtocolConfig(
172
336
  config: unknown,
173
337
  protocol: "oidc" | "saml",
@@ -182,6 +346,7 @@ export function upsertProtocolConfig(
182
346
  return { ...base, protocols };
183
347
  }
184
348
 
349
+ /** @internal */
185
350
  export function createSamlPostBindingResponse(opts: {
186
351
  endpoint: string;
187
352
  parameter: "SAMLRequest" | "SAMLResponse";
@@ -200,6 +365,7 @@ export function createSamlPostBindingResponse(opts: {
200
365
  );
201
366
  }
202
367
 
368
+ /** @internal */
203
369
  export function decodeRelayState(
204
370
  value: string | null,
205
371
  ): Record<string, unknown> {
@@ -215,6 +381,7 @@ export function decodeRelayState(
215
381
  }
216
382
  }
217
383
 
384
+ /** @internal */
218
385
  export function encodeEnterpriseSamlRelayState(
219
386
  value: EnterpriseSamlRelayState,
220
387
  ) {
@@ -231,6 +398,7 @@ export function encodeEnterpriseSamlRelayState(
231
398
  );
232
399
  }
233
400
 
401
+ /** @internal */
234
402
  export function decodeEnterpriseSamlRelayStateOrThrow(
235
403
  value: string | null,
236
404
  ): EnterpriseSamlRelayState {
@@ -261,6 +429,7 @@ export function decodeEnterpriseSamlRelayStateOrThrow(
261
429
  };
262
430
  }
263
431
 
432
+ /** @internal */
264
433
  export async function readRequestBody(
265
434
  request: Request,
266
435
  ): Promise<Record<string, string>> {
@@ -279,6 +448,7 @@ export async function readRequestBody(
279
448
  return {};
280
449
  }
281
450
 
451
+ /** @internal */
282
452
  export async function readEnterpriseSamlHttpRequest(
283
453
  request: Request,
284
454
  ): Promise<EnterpriseSamlHttpRequest> {
@@ -319,11 +489,13 @@ async function discoverOidcConfiguration(config: Record<string, any>) {
319
489
  throw new Error("Enterprise OIDC requires an issuer or discoveryUrl.");
320
490
  }
321
491
 
492
+ const oidcFetch = createEnterpriseOidcFetch(config, config.issuer);
493
+
322
494
  return await Fx.run(
323
495
  Fx.defer(() =>
324
496
  Fx.from({
325
497
  ok: async () => {
326
- const response = await fetch(discoveryUrl);
498
+ const response = await oidcFetch(discoveryUrl);
327
499
  if (!response.ok) {
328
500
  throw new Error(
329
501
  `Failed to discover OIDC configuration: ${response.status}`,
@@ -360,11 +532,46 @@ async function discoverOidcConfiguration(config: Record<string, any>) {
360
532
  );
361
533
  }
362
534
 
363
- function getOidcJwks(url: string) {
364
- let jwks = OIDC_JWKS_CACHE.get(url);
535
+ function createEnterpriseOidcFetch(
536
+ config: Record<string, any>,
537
+ discoveredIssuer?: string,
538
+ ) {
539
+ const runtimeOrigin =
540
+ typeof config.discoveryUrl === "string"
541
+ ? new URL(config.discoveryUrl).origin
542
+ : undefined;
543
+ const externalHost =
544
+ typeof config.issuer === "string"
545
+ ? new URL(config.issuer).host
546
+ : typeof discoveredIssuer === "string"
547
+ ? new URL(discoveredIssuer).host
548
+ : undefined;
549
+
550
+ return async (input: string | URL, init?: RequestInit) => {
551
+ const url = new URL(typeof input === "string" ? input : input.toString());
552
+ const rewrittenUrl =
553
+ runtimeOrigin !== undefined && url.origin !== runtimeOrigin
554
+ ? new URL(`${runtimeOrigin}${url.pathname}${url.search}`)
555
+ : url;
556
+ const headers = new Headers(init?.headers);
557
+ if (runtimeOrigin !== undefined && externalHost !== undefined) {
558
+ headers.set("host", externalHost);
559
+ }
560
+ return await fetch(rewrittenUrl, { ...init, headers });
561
+ };
562
+ }
563
+
564
+ function getOidcJwks(
565
+ url: string,
566
+ fetchImpl?: ReturnType<typeof createEnterpriseOidcFetch>,
567
+ ) {
568
+ const cacheKey = fetchImpl ? `${url}::custom` : url;
569
+ let jwks = OIDC_JWKS_CACHE.get(cacheKey);
365
570
  if (!jwks) {
366
- jwks = createRemoteJWKSet(new URL(url));
367
- OIDC_JWKS_CACHE.set(url, jwks);
571
+ jwks = fetchImpl
572
+ ? createRemoteJWKSet(new URL(url), { [customFetch]: fetchImpl })
573
+ : createRemoteJWKSet(new URL(url));
574
+ OIDC_JWKS_CACHE.set(cacheKey, jwks);
368
575
  }
369
576
  return jwks;
370
577
  }
@@ -378,10 +585,11 @@ function userInfoProfileFx(opts: {
378
585
  accessToken: string;
379
586
  verifiedClaims: Record<string, unknown>;
380
587
  verifiedProfile: OAuthProfile & { emailVerified?: boolean };
588
+ fetchImpl?: ReturnType<typeof createEnterpriseOidcFetch>;
381
589
  }) {
382
590
  return Fx.from({
383
591
  ok: async () => {
384
- const response = await fetch(opts.endpoint, {
592
+ const response = await (opts.fetchImpl ?? fetch)(opts.endpoint, {
385
593
  headers: { Authorization: `Bearer ${opts.accessToken}` },
386
594
  });
387
595
  if (!response.ok) {
@@ -438,6 +646,7 @@ function userInfoProfileFx(opts: {
438
646
  );
439
647
  }
440
648
 
649
+ /** @internal */
441
650
  export async function createEnterpriseOidcProvider(
442
651
  config: Record<string, any>,
443
652
  redirectUri: string,
@@ -478,6 +687,10 @@ export async function createEnterpriseOidcProvider(
478
687
  : [];
479
688
  const userinfoEndpoint =
480
689
  (discovery.userinfo_endpoint as string | undefined) ?? undefined;
690
+ const oidcFetch = createEnterpriseOidcFetch(
691
+ config,
692
+ discovery.issuer as string,
693
+ );
481
694
  const scopes = Array.isArray(config.scopes)
482
695
  ? config.scopes.filter(
483
696
  (value: unknown): value is string => typeof value === "string",
@@ -501,7 +714,7 @@ export async function createEnterpriseOidcProvider(
501
714
  ...getIssuerCandidates(discoveredIssuer),
502
715
  ]),
503
716
  );
504
- const jwks = getOidcJwks(jwksUri);
717
+ const jwks = getOidcJwks(jwksUri, oidcFetch);
505
718
  let verifiedClaims: Record<string, unknown> | null = null;
506
719
  let verifiedProfile: (OAuthProfile & { emailVerified?: boolean }) | null =
507
720
  null;
@@ -563,7 +776,7 @@ export async function createEnterpriseOidcProvider(
563
776
  if (codeVerifier) {
564
777
  body.set("code_verifier", codeVerifier);
565
778
  }
566
- const response = await fetch(tokenEndpoint, {
779
+ const response = await oidcFetch(tokenEndpoint, {
567
780
  method: "POST",
568
781
  headers: { "Content-Type": "application/x-www-form-urlencoded" },
569
782
  body,
@@ -692,6 +905,7 @@ export async function createEnterpriseOidcProvider(
692
905
  accessToken: tokens.accessToken(),
693
906
  verifiedClaims,
694
907
  verifiedProfile,
908
+ fetchImpl: oidcFetch,
695
909
  }),
696
910
  );
697
911
  if (userInfoProfile !== null) {
@@ -705,18 +919,23 @@ export async function createEnterpriseOidcProvider(
705
919
  return { provider, oauthConfig };
706
920
  }
707
921
 
922
+ /** @internal */
708
923
  export function createSyntheticOAuthMaterializedConfig(
709
924
  providerId: string,
925
+ options?: {
926
+ accountLinking?: OAuthMaterializedConfig["accountLinking"];
927
+ },
710
928
  ): OAuthMaterializedConfig {
711
929
  return {
712
930
  id: providerId,
713
931
  type: "oauth",
714
932
  provider: null,
715
933
  scopes: [],
716
- accountLinking: "verifiedEmail",
934
+ accountLinking: options?.accountLinking ?? "verifiedEmail",
717
935
  };
718
936
  }
719
937
 
938
+ /** @internal */
720
939
  export function parseSamlIdpMetadata(metadata: string): ParsedSamlMetadata {
721
940
  const idp = IdentityProvider({ metadata });
722
941
  const entityMeta = idp.entityMeta;
@@ -745,6 +964,7 @@ export function parseSamlIdpMetadata(metadata: string): ParsedSamlMetadata {
745
964
  };
746
965
  }
747
966
 
967
+ /** @internal */
748
968
  export function createServiceProviderMetadata(opts: {
749
969
  entityId: string;
750
970
  acsUrl: string;
@@ -789,6 +1009,7 @@ export function createServiceProviderMetadata(opts: {
789
1009
  return sp.getMetadata();
790
1010
  }
791
1011
 
1012
+ /** @internal */
792
1013
  export function createEnterpriseSamlMetadataXml(opts: {
793
1014
  rootUrl: string;
794
1015
  source: EnterpriseSamlSource;
@@ -803,6 +1024,7 @@ export function createEnterpriseSamlMetadataXml(opts: {
803
1024
  );
804
1025
  }
805
1026
 
1027
+ /** @internal */
806
1028
  export function getSamlServiceProviderOptions(opts: {
807
1029
  rootUrl: string;
808
1030
  source: EnterpriseSamlSource;
@@ -835,6 +1057,7 @@ export function getSamlServiceProviderOptions(opts: {
835
1057
  };
836
1058
  }
837
1059
 
1060
+ /** @internal */
838
1061
  export function createSamlServiceProvider(opts: {
839
1062
  entityId: string;
840
1063
  acsUrl: string;
@@ -874,6 +1097,7 @@ export function createSamlServiceProvider(opts: {
874
1097
  });
875
1098
  }
876
1099
 
1100
+ /** @internal */
877
1101
  export function createEnterpriseSamlRuntime(opts: {
878
1102
  rootUrl: string;
879
1103
  source: EnterpriseSamlSource;
@@ -904,6 +1128,7 @@ export function createEnterpriseSamlRuntime(opts: {
904
1128
  };
905
1129
  }
906
1130
 
1131
+ /** @internal */
907
1132
  export function createEnterpriseSamlSignInRequest(opts: {
908
1133
  rootUrl: string;
909
1134
  source: EnterpriseSamlSource;
@@ -951,6 +1176,7 @@ export function createEnterpriseSamlSignInRequest(opts: {
951
1176
  };
952
1177
  }
953
1178
 
1179
+ /** @internal */
954
1180
  export async function parseEnterpriseSamlLoginResponse(opts: {
955
1181
  request: Request;
956
1182
  rootUrl: string;
@@ -1026,6 +1252,7 @@ function warnDeprecatedSamlAlgorithms(parsed: any) {
1026
1252
  }
1027
1253
  }
1028
1254
 
1255
+ /** @internal */
1029
1256
  export function validateEnterpriseSamlLoginRelayState(opts: {
1030
1257
  relayState: EnterpriseSamlRelayState;
1031
1258
  source: EnterpriseSamlSource;
@@ -1040,6 +1267,7 @@ export function validateEnterpriseSamlLoginRelayState(opts: {
1040
1267
  }
1041
1268
  }
1042
1269
 
1270
+ /** @internal */
1043
1271
  export async function parseEnterpriseSamlLogoutMessage(opts: {
1044
1272
  request: Request;
1045
1273
  rootUrl: string;
@@ -1071,23 +1299,23 @@ export async function parseEnterpriseSamlLogoutMessage(opts: {
1071
1299
  };
1072
1300
  }
1073
1301
 
1302
+ /** @internal */
1074
1303
  export async function createEnterpriseOidcRuntime(opts: {
1075
1304
  rootUrl: string;
1076
1305
  enterpriseId: string;
1077
- config: unknown;
1306
+ oidc: Record<string, any>;
1078
1307
  }) {
1079
- const oidc = getOidcConfig(opts.config);
1080
1308
  const providerId = enterpriseOidcProviderId(opts.enterpriseId);
1081
1309
  const urls = getEnterpriseOidcUrls({
1082
1310
  rootUrl: opts.rootUrl,
1083
1311
  enterpriseId: opts.enterpriseId,
1084
1312
  });
1085
1313
  const { provider, oauthConfig } = await createEnterpriseOidcProvider(
1086
- oidc,
1314
+ opts.oidc,
1087
1315
  urls.callbackUrl,
1088
1316
  );
1089
1317
  return {
1090
- oidc,
1318
+ oidc: opts.oidc,
1091
1319
  providerId,
1092
1320
  provider,
1093
1321
  oauthConfig,
@@ -1095,6 +1323,7 @@ export async function createEnterpriseOidcRuntime(opts: {
1095
1323
  };
1096
1324
  }
1097
1325
 
1326
+ /** @internal */
1098
1327
  export function profileFromSamlExtract(
1099
1328
  extract: any,
1100
1329
  mapping?: SAMLAttributeMapping,
@@ -1145,15 +1374,15 @@ export function profileFromSamlExtract(
1145
1374
  };
1146
1375
  }
1147
1376
 
1377
+ /** @internal */
1148
1378
  export function parseScimPath(pathname: string) {
1149
1379
  const parts = pathname.split("/").filter(Boolean);
1150
- const [api, auth, enterprise, enterpriseId, protocol, version, ...rest] =
1151
- parts;
1380
+ const [api, auth, sso, enterpriseId, protocol, version, ...rest] = parts;
1152
1381
 
1153
1382
  if (
1154
1383
  api !== "api" ||
1155
1384
  auth !== "auth" ||
1156
- enterprise !== "enterprise" ||
1385
+ sso !== "sso" ||
1157
1386
  !enterpriseId ||
1158
1387
  enterpriseId === "setup" ||
1159
1388
  protocol !== "scim" ||
@@ -1173,6 +1402,7 @@ export function parseScimPath(pathname: string) {
1173
1402
  };
1174
1403
  }
1175
1404
 
1405
+ /** @internal */
1176
1406
  export function parseScimListRequest(url: URL): ScimListRequest {
1177
1407
  const startIndex = Math.max(
1178
1408
  1,
@@ -1195,6 +1425,7 @@ export function parseScimListRequest(url: URL): ScimListRequest {
1195
1425
  return { startIndex, count, filter };
1196
1426
  }
1197
1427
 
1428
+ /** @internal */
1198
1429
  export function scimJson(data: unknown, status = 200, headers?: HeadersInit) {
1199
1430
  const responseHeaders = new Headers({
1200
1431
  "Content-Type": "application/scim+json",
@@ -1210,6 +1441,7 @@ export function scimJson(data: unknown, status = 200, headers?: HeadersInit) {
1210
1441
  });
1211
1442
  }
1212
1443
 
1444
+ /** @internal */
1213
1445
  export function scimError(status: number, scimType: string, detail: string) {
1214
1446
  return scimJson(
1215
1447
  {
@@ -1222,6 +1454,7 @@ export function scimError(status: number, scimType: string, detail: string) {
1222
1454
  );
1223
1455
  }
1224
1456
 
1457
+ /** @internal */
1225
1458
  export function serializeScimUser(args: {
1226
1459
  id: string;
1227
1460
  user: Record<string, any>;
@@ -1253,6 +1486,7 @@ export function serializeScimUser(args: {
1253
1486
  };
1254
1487
  }
1255
1488
 
1489
+ /** @internal */
1256
1490
  export function serializeScimGroup(args: {
1257
1491
  id: string;
1258
1492
  group: Record<string, any>;
@@ -15,6 +15,7 @@
15
15
  * Used by the auto-registered `email` provider when `email` is
16
16
  * configured in `createAuth(...)`.
17
17
  */
18
+ /** @internal */
18
19
  export function defaultMagicLinkEmail(url: string, host: string): string {
19
20
  const escapedHost = host.replace(
20
21
  /[&<>"']/g,
@@ -10,6 +10,7 @@ const TOKEN_JTI_LENGTH = 24;
10
10
  const TOKEN_JTI_ALPHABET =
11
11
  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
12
12
 
13
+ /** @internal */
13
14
  export async function generateToken(
14
15
  args: {
15
16
  userId: GenericId<"User">;
@@ -12,6 +12,7 @@ import { verifyTOTPWithGracePeriod, createTOTPKeyURI } from "@oslojs/otp";
12
12
  import type { Fx as FxType } from "@robelest/fx";
13
13
 
14
14
  import { AuthError, Fx } from "./fx";
15
+ import { userIdFromIdentitySubject } from "./identity";
15
16
  import { callSignIn, callVerifier } from "./mutations/index";
16
17
  import { callVerifierSignature } from "./mutations/signature";
17
18
  import { TotpProviderConfig, GenericActionCtxWithAuthConfig } from "./types";
@@ -134,6 +135,7 @@ const resolveTotpDispatchFx = (
134
135
  ),
135
136
  );
136
137
 
138
+ /** @internal */
137
139
  export const handleTotp = (
138
140
  ctx: EnrichedActionCtx,
139
141
  provider: TotpProviderConfig,
@@ -152,7 +154,7 @@ export const handleTotp = (
152
154
  Fx.chain((identity) =>
153
155
  identity === null
154
156
  ? Fx.fail(new AuthError("TOTP_AUTH_REQUIRED"))
155
- : Fx.succeed(identity.subject.split("|")[0]!),
157
+ : Fx.succeed(userIdFromIdentitySubject(identity.subject)),
156
158
  ),
157
159
  Fx.chain((userId) =>
158
160
  Fx.from({
@@ -224,7 +226,7 @@ export const handleTotp = (
224
226
  Fx.chain((identity) =>
225
227
  identity === null
226
228
  ? Fx.fail(new AuthError("TOTP_AUTH_REQUIRED"))
227
- : Fx.succeed(identity.subject.split("|")[0]!),
229
+ : Fx.succeed(userIdFromIdentitySubject(identity.subject)),
228
230
  ),
229
231
  Fx.chain((userId) =>
230
232
  Fx.from({