@robelest/convex-auth 0.0.3-preview → 0.0.3-preview.3

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 (304) hide show
  1. package/dist/bin.cjs +15 -15
  2. package/dist/client/index.d.ts +40 -12
  3. package/dist/client/index.d.ts.map +1 -1
  4. package/dist/client/index.js +73 -12
  5. package/dist/client/index.js.map +1 -1
  6. package/dist/component/_generated/api.d.ts +2 -2
  7. package/dist/component/_generated/api.d.ts.map +1 -1
  8. package/dist/component/_generated/component.d.ts +1 -1
  9. package/dist/component/_generated/component.d.ts.map +1 -1
  10. package/dist/component/{portalBridge.d.ts → bridge.d.ts} +2 -2
  11. package/dist/component/bridge.d.ts.map +1 -0
  12. package/dist/component/{portalBridge.js → bridge.js} +2 -2
  13. package/dist/component/bridge.js.map +1 -0
  14. package/dist/component/index.d.ts +11 -4
  15. package/dist/component/index.d.ts.map +1 -1
  16. package/dist/component/index.js +8 -2
  17. package/dist/component/index.js.map +1 -1
  18. package/dist/component/public.d.ts +24 -17
  19. package/dist/component/public.d.ts.map +1 -1
  20. package/dist/component/public.js +23 -4
  21. package/dist/component/public.js.map +1 -1
  22. package/dist/component/schema.d.ts +11 -7
  23. package/dist/component/schema.d.ts.map +1 -1
  24. package/dist/component/schema.js +4 -1
  25. package/dist/component/schema.js.map +1 -1
  26. package/dist/providers/anonymous.d.ts +3 -0
  27. package/dist/providers/anonymous.d.ts.map +1 -1
  28. package/dist/providers/anonymous.js +3 -0
  29. package/dist/providers/anonymous.js.map +1 -1
  30. package/dist/providers/credentials.d.ts +3 -0
  31. package/dist/providers/credentials.d.ts.map +1 -1
  32. package/dist/providers/credentials.js +3 -0
  33. package/dist/providers/credentials.js.map +1 -1
  34. package/dist/providers/email.d.ts +3 -0
  35. package/dist/providers/email.d.ts.map +1 -1
  36. package/dist/providers/email.js +3 -0
  37. package/dist/providers/email.js.map +1 -1
  38. package/dist/providers/passkey.d.ts +7 -1
  39. package/dist/providers/passkey.d.ts.map +1 -1
  40. package/dist/providers/passkey.js +7 -1
  41. package/dist/providers/passkey.js.map +1 -1
  42. package/dist/providers/password.d.ts +3 -0
  43. package/dist/providers/password.d.ts.map +1 -1
  44. package/dist/providers/password.js +3 -0
  45. package/dist/providers/password.js.map +1 -1
  46. package/dist/providers/phone.d.ts +3 -0
  47. package/dist/providers/phone.d.ts.map +1 -1
  48. package/dist/providers/phone.js +3 -0
  49. package/dist/providers/phone.js.map +1 -1
  50. package/dist/providers/totp.d.ts +8 -0
  51. package/dist/providers/totp.d.ts.map +1 -1
  52. package/dist/providers/totp.js +8 -0
  53. package/dist/providers/totp.js.map +1 -1
  54. package/dist/server/{convex-auth.d.ts → auth.d.ts} +226 -36
  55. package/dist/server/auth.d.ts.map +1 -0
  56. package/dist/server/{convex-auth.js → auth.js} +287 -111
  57. package/dist/server/auth.js.map +1 -0
  58. package/dist/server/errors.d.ts +148 -0
  59. package/dist/server/errors.d.ts.map +1 -0
  60. package/dist/server/errors.js +179 -0
  61. package/dist/server/errors.js.map +1 -0
  62. package/dist/server/implementation/index.d.ts +170 -48
  63. package/dist/server/implementation/index.d.ts.map +1 -1
  64. package/dist/server/implementation/index.js +383 -167
  65. package/dist/server/implementation/index.js.map +1 -1
  66. package/dist/server/implementation/{apiKey.d.ts → keys.d.ts} +1 -1
  67. package/dist/server/implementation/keys.d.ts.map +1 -0
  68. package/dist/server/implementation/{apiKey.js → keys.js} +4 -5
  69. package/dist/server/implementation/keys.js.map +1 -0
  70. package/dist/server/implementation/mutations/{modifyAccount.d.ts → account.d.ts} +3 -3
  71. package/dist/server/implementation/mutations/account.d.ts.map +1 -0
  72. package/dist/server/implementation/mutations/{modifyAccount.js → account.js} +4 -3
  73. package/dist/server/implementation/mutations/account.js.map +1 -0
  74. package/dist/server/implementation/mutations/{createVerificationCode.d.ts → code.d.ts} +1 -1
  75. package/dist/server/implementation/mutations/code.d.ts.map +1 -0
  76. package/dist/server/implementation/mutations/{createVerificationCode.js → code.js} +2 -2
  77. package/dist/server/implementation/mutations/code.js.map +1 -0
  78. package/dist/server/implementation/mutations/index.d.ts +33 -33
  79. package/dist/server/implementation/mutations/index.d.ts.map +1 -1
  80. package/dist/server/implementation/mutations/index.js +22 -22
  81. package/dist/server/implementation/mutations/index.js.map +1 -1
  82. package/dist/server/implementation/mutations/{invalidateSessions.d.ts → invalidate.d.ts} +1 -1
  83. package/dist/server/implementation/mutations/invalidate.d.ts.map +1 -0
  84. package/dist/server/implementation/mutations/{invalidateSessions.js → invalidate.js} +2 -2
  85. package/dist/server/implementation/mutations/invalidate.js.map +1 -0
  86. package/dist/server/implementation/mutations/{userOAuth.d.ts → oauth.d.ts} +3 -3
  87. package/dist/server/implementation/mutations/oauth.d.ts.map +1 -0
  88. package/dist/server/implementation/mutations/{userOAuth.js → oauth.js} +4 -3
  89. package/dist/server/implementation/mutations/oauth.js.map +1 -0
  90. package/dist/server/implementation/mutations/{refreshSession.d.ts → refresh.d.ts} +1 -1
  91. package/dist/server/implementation/mutations/refresh.d.ts.map +1 -0
  92. package/dist/server/implementation/mutations/{refreshSession.js → refresh.js} +3 -3
  93. package/dist/server/implementation/mutations/refresh.js.map +1 -0
  94. package/dist/server/implementation/mutations/{createAccountFromCredentials.d.ts → register.d.ts} +4 -4
  95. package/dist/server/implementation/mutations/register.d.ts.map +1 -0
  96. package/dist/server/implementation/mutations/{createAccountFromCredentials.js → register.js} +4 -3
  97. package/dist/server/implementation/mutations/register.js.map +1 -0
  98. package/dist/server/implementation/mutations/{retrieveAccountWithCredentials.d.ts → retrieve.d.ts} +3 -3
  99. package/dist/server/implementation/mutations/retrieve.d.ts.map +1 -0
  100. package/dist/server/implementation/mutations/{retrieveAccountWithCredentials.js → retrieve.js} +3 -3
  101. package/dist/server/implementation/mutations/retrieve.js.map +1 -0
  102. package/dist/server/implementation/mutations/{verifierSignature.d.ts → signature.d.ts} +1 -1
  103. package/dist/server/implementation/mutations/signature.d.ts.map +1 -0
  104. package/dist/server/implementation/mutations/{verifierSignature.js → signature.js} +4 -3
  105. package/dist/server/implementation/mutations/signature.js.map +1 -0
  106. package/dist/server/implementation/mutations/{signIn.d.ts → signin.d.ts} +1 -1
  107. package/dist/server/implementation/mutations/{signIn.d.ts.map → signin.d.ts.map} +1 -1
  108. package/dist/server/implementation/mutations/{signIn.js → signin.js} +2 -2
  109. package/dist/server/implementation/mutations/{signIn.js.map → signin.js.map} +1 -1
  110. package/dist/server/implementation/mutations/{signOut.d.ts → signout.d.ts} +1 -1
  111. package/dist/server/implementation/mutations/{signOut.d.ts.map → signout.d.ts.map} +1 -1
  112. package/dist/server/implementation/mutations/{signOut.js → signout.js} +2 -2
  113. package/dist/server/implementation/mutations/{signOut.js.map → signout.js.map} +1 -1
  114. package/dist/server/implementation/mutations/{storeRef.d.ts → store.d.ts} +1 -1
  115. package/dist/server/implementation/mutations/store.d.ts.map +1 -0
  116. package/dist/server/implementation/mutations/{storeRef.js → store.js} +1 -1
  117. package/dist/server/implementation/mutations/store.js.map +1 -0
  118. package/dist/server/implementation/mutations/verifier.js +1 -1
  119. package/dist/server/implementation/mutations/verifier.js.map +1 -1
  120. package/dist/server/implementation/mutations/{verifyCodeAndSignIn.d.ts → verify.d.ts} +1 -1
  121. package/dist/server/implementation/mutations/verify.d.ts.map +1 -0
  122. package/dist/server/implementation/mutations/{verifyCodeAndSignIn.js → verify.js} +3 -3
  123. package/dist/server/implementation/mutations/verify.js.map +1 -0
  124. package/dist/server/implementation/passkey.d.ts.map +1 -1
  125. package/dist/server/implementation/passkey.js +47 -55
  126. package/dist/server/implementation/passkey.js.map +1 -1
  127. package/dist/server/implementation/provider.d.ts.map +1 -1
  128. package/dist/server/implementation/provider.js +5 -4
  129. package/dist/server/implementation/provider.js.map +1 -1
  130. package/dist/server/implementation/{rateLimit.d.ts → ratelimit.d.ts} +1 -1
  131. package/dist/server/implementation/{rateLimit.d.ts.map → ratelimit.d.ts.map} +1 -1
  132. package/dist/server/implementation/{rateLimit.js → ratelimit.js} +1 -1
  133. package/dist/server/implementation/{rateLimit.js.map → ratelimit.js.map} +1 -1
  134. package/dist/server/implementation/redirects.d.ts.map +1 -1
  135. package/dist/server/implementation/redirects.js +2 -1
  136. package/dist/server/implementation/redirects.js.map +1 -1
  137. package/dist/server/implementation/{refreshTokens.d.ts → refresh.d.ts} +1 -1
  138. package/dist/server/implementation/refresh.d.ts.map +1 -0
  139. package/dist/server/implementation/{refreshTokens.js → refresh.js} +3 -2
  140. package/dist/server/implementation/refresh.js.map +1 -0
  141. package/dist/server/implementation/sessions.js +1 -1
  142. package/dist/server/implementation/sessions.js.map +1 -1
  143. package/dist/server/implementation/{signIn.d.ts → signin.d.ts} +1 -1
  144. package/dist/server/implementation/{signIn.d.ts.map → signin.d.ts.map} +1 -1
  145. package/dist/server/implementation/{signIn.js → signin.js} +12 -8
  146. package/dist/server/implementation/signin.js.map +1 -0
  147. package/dist/server/implementation/totp.d.ts.map +1 -1
  148. package/dist/server/implementation/totp.js +29 -29
  149. package/dist/server/implementation/totp.js.map +1 -1
  150. package/dist/server/implementation/types.d.ts +131 -1
  151. package/dist/server/implementation/types.d.ts.map +1 -1
  152. package/dist/server/implementation/types.js +65 -1
  153. package/dist/server/implementation/types.js.map +1 -1
  154. package/dist/server/implementation/users.d.ts.map +1 -1
  155. package/dist/server/implementation/users.js +3 -2
  156. package/dist/server/implementation/users.js.map +1 -1
  157. package/dist/server/index.d.ts +131 -1
  158. package/dist/server/index.d.ts.map +1 -1
  159. package/dist/server/index.js +117 -1
  160. package/dist/server/index.js.map +1 -1
  161. package/dist/server/oauth/{authorizationUrl.d.ts → authorization.d.ts} +1 -1
  162. package/dist/server/oauth/authorization.d.ts.map +1 -0
  163. package/dist/server/oauth/{authorizationUrl.js → authorization.js} +4 -3
  164. package/dist/server/oauth/authorization.js.map +1 -0
  165. package/dist/server/oauth/callback.d.ts.map +1 -1
  166. package/dist/server/oauth/callback.js +7 -6
  167. package/dist/server/oauth/callback.js.map +1 -1
  168. package/dist/server/oauth/checks.d.ts.map +1 -1
  169. package/dist/server/oauth/checks.js +2 -1
  170. package/dist/server/oauth/checks.js.map +1 -1
  171. package/dist/server/oauth/{convexAuth.d.ts → helpers.d.ts} +1 -1
  172. package/dist/server/oauth/helpers.d.ts.map +1 -0
  173. package/dist/server/oauth/{convexAuth.js → helpers.js} +6 -5
  174. package/dist/server/oauth/helpers.js.map +1 -0
  175. package/dist/server/oauth/lib/utils/{customFetch.d.ts → fetch.d.ts} +1 -1
  176. package/dist/server/oauth/lib/utils/fetch.d.ts.map +1 -0
  177. package/dist/server/oauth/lib/utils/{customFetch.js → fetch.js} +1 -1
  178. package/dist/server/oauth/lib/utils/fetch.js.map +1 -0
  179. package/dist/server/{provider_utils.d.ts → providers.d.ts} +1 -1
  180. package/dist/server/providers.d.ts.map +1 -0
  181. package/dist/server/{provider_utils.js → providers.js} +1 -1
  182. package/dist/server/providers.js.map +1 -0
  183. package/dist/server/{email-templates.d.ts → templates.d.ts} +8 -1
  184. package/dist/server/templates.d.ts.map +1 -0
  185. package/dist/server/{portal-email.js → templates.js} +74 -3
  186. package/dist/server/templates.js.map +1 -0
  187. package/dist/server/types.d.ts +88 -5
  188. package/dist/server/types.d.ts.map +1 -1
  189. package/dist/server/utils.d.ts.map +1 -1
  190. package/dist/server/utils.js +2 -1
  191. package/dist/server/utils.js.map +1 -1
  192. package/dist/server/version.d.ts +1 -1
  193. package/dist/server/version.d.ts.map +1 -1
  194. package/dist/server/version.js +1 -1
  195. package/dist/server/version.js.map +1 -1
  196. package/package.json +5 -1
  197. package/src/cli/index.ts +5 -5
  198. package/src/cli/{portal-link.ts → link.ts} +1 -1
  199. package/src/cli/utils.ts +1 -1
  200. package/src/client/index.ts +102 -17
  201. package/src/component/_generated/api.ts +2 -2
  202. package/src/component/_generated/component.ts +1 -1
  203. package/src/component/{portalBridge.ts → bridge.ts} +2 -2
  204. package/src/component/index.ts +10 -2
  205. package/src/component/public.ts +25 -4
  206. package/src/component/schema.ts +4 -1
  207. package/src/providers/anonymous.ts +3 -0
  208. package/src/providers/credentials.ts +3 -0
  209. package/src/providers/email.ts +3 -0
  210. package/src/providers/passkey.ts +8 -1
  211. package/src/providers/password.ts +3 -0
  212. package/src/providers/phone.ts +3 -0
  213. package/src/providers/totp.ts +9 -0
  214. package/src/server/auth.ts +969 -0
  215. package/src/server/errors.ts +275 -0
  216. package/src/server/implementation/index.ts +370 -88
  217. package/src/server/implementation/{apiKey.ts → keys.ts} +7 -6
  218. package/src/server/implementation/mutations/{modifyAccount.ts → account.ts} +3 -4
  219. package/src/server/implementation/mutations/{createVerificationCode.ts → code.ts} +1 -1
  220. package/src/server/implementation/mutations/index.ts +22 -22
  221. package/src/server/implementation/mutations/{invalidateSessions.ts → invalidate.ts} +1 -1
  222. package/src/server/implementation/mutations/{userOAuth.ts → oauth.ts} +3 -2
  223. package/src/server/implementation/mutations/{refreshSession.ts → refresh.ts} +2 -2
  224. package/src/server/implementation/mutations/{createAccountFromCredentials.ts → register.ts} +3 -2
  225. package/src/server/implementation/mutations/{retrieveAccountWithCredentials.ts → retrieve.ts} +2 -2
  226. package/src/server/implementation/mutations/{verifierSignature.ts → signature.ts} +3 -2
  227. package/src/server/implementation/mutations/{signIn.ts → signin.ts} +1 -1
  228. package/src/server/implementation/mutations/{signOut.ts → signout.ts} +1 -1
  229. package/src/server/implementation/mutations/verifier.ts +1 -1
  230. package/src/server/implementation/mutations/{verifyCodeAndSignIn.ts → verify.ts} +2 -2
  231. package/src/server/implementation/passkey.ts +86 -116
  232. package/src/server/implementation/provider.ts +5 -8
  233. package/src/server/implementation/redirects.ts +2 -3
  234. package/src/server/implementation/{refreshTokens.ts → refresh.ts} +2 -1
  235. package/src/server/implementation/sessions.ts +1 -1
  236. package/src/server/implementation/{signIn.ts → signin.ts} +13 -11
  237. package/src/server/implementation/totp.ts +60 -84
  238. package/src/server/implementation/types.ts +316 -1
  239. package/src/server/implementation/users.ts +4 -7
  240. package/src/server/index.ts +142 -3
  241. package/src/server/oauth/{authorizationUrl.ts → authorization.ts} +3 -2
  242. package/src/server/oauth/callback.ts +7 -6
  243. package/src/server/oauth/checks.ts +3 -1
  244. package/src/server/oauth/{convexAuth.ts → helpers.ts} +8 -5
  245. package/src/server/{portal-email.ts → templates.ts} +78 -2
  246. package/src/server/types.ts +133 -4
  247. package/src/server/utils.ts +3 -1
  248. package/src/server/version.ts +1 -1
  249. package/dist/component/portalBridge.d.ts.map +0 -1
  250. package/dist/component/portalBridge.js.map +0 -1
  251. package/dist/server/convex-auth.d.ts.map +0 -1
  252. package/dist/server/convex-auth.js.map +0 -1
  253. package/dist/server/convex_types.d.ts +0 -17
  254. package/dist/server/convex_types.d.ts.map +0 -1
  255. package/dist/server/convex_types.js +0 -2
  256. package/dist/server/convex_types.js.map +0 -1
  257. package/dist/server/email-templates.d.ts.map +0 -1
  258. package/dist/server/email-templates.js +0 -74
  259. package/dist/server/email-templates.js.map +0 -1
  260. package/dist/server/implementation/apiKey.d.ts.map +0 -1
  261. package/dist/server/implementation/apiKey.js.map +0 -1
  262. package/dist/server/implementation/mutations/createAccountFromCredentials.d.ts.map +0 -1
  263. package/dist/server/implementation/mutations/createAccountFromCredentials.js.map +0 -1
  264. package/dist/server/implementation/mutations/createVerificationCode.d.ts.map +0 -1
  265. package/dist/server/implementation/mutations/createVerificationCode.js.map +0 -1
  266. package/dist/server/implementation/mutations/invalidateSessions.d.ts.map +0 -1
  267. package/dist/server/implementation/mutations/invalidateSessions.js.map +0 -1
  268. package/dist/server/implementation/mutations/modifyAccount.d.ts.map +0 -1
  269. package/dist/server/implementation/mutations/modifyAccount.js.map +0 -1
  270. package/dist/server/implementation/mutations/refreshSession.d.ts.map +0 -1
  271. package/dist/server/implementation/mutations/refreshSession.js.map +0 -1
  272. package/dist/server/implementation/mutations/retrieveAccountWithCredentials.d.ts.map +0 -1
  273. package/dist/server/implementation/mutations/retrieveAccountWithCredentials.js.map +0 -1
  274. package/dist/server/implementation/mutations/storeRef.d.ts.map +0 -1
  275. package/dist/server/implementation/mutations/storeRef.js.map +0 -1
  276. package/dist/server/implementation/mutations/userOAuth.d.ts.map +0 -1
  277. package/dist/server/implementation/mutations/userOAuth.js.map +0 -1
  278. package/dist/server/implementation/mutations/verifierSignature.d.ts.map +0 -1
  279. package/dist/server/implementation/mutations/verifierSignature.js.map +0 -1
  280. package/dist/server/implementation/mutations/verifyCodeAndSignIn.d.ts.map +0 -1
  281. package/dist/server/implementation/mutations/verifyCodeAndSignIn.js.map +0 -1
  282. package/dist/server/implementation/refreshTokens.d.ts.map +0 -1
  283. package/dist/server/implementation/refreshTokens.js.map +0 -1
  284. package/dist/server/implementation/signIn.js.map +0 -1
  285. package/dist/server/oauth/authorizationUrl.d.ts.map +0 -1
  286. package/dist/server/oauth/authorizationUrl.js.map +0 -1
  287. package/dist/server/oauth/convexAuth.d.ts.map +0 -1
  288. package/dist/server/oauth/convexAuth.js.map +0 -1
  289. package/dist/server/oauth/lib/utils/customFetch.d.ts.map +0 -1
  290. package/dist/server/oauth/lib/utils/customFetch.js.map +0 -1
  291. package/dist/server/portal-email.d.ts +0 -19
  292. package/dist/server/portal-email.d.ts.map +0 -1
  293. package/dist/server/portal-email.js.map +0 -1
  294. package/dist/server/provider_utils.d.ts.map +0 -1
  295. package/dist/server/provider_utils.js.map +0 -1
  296. package/src/server/convex-auth.ts +0 -602
  297. package/src/server/convex_types.ts +0 -55
  298. package/src/server/email-templates.ts +0 -77
  299. /package/src/cli/{generateKeys.ts → keys.ts} +0 -0
  300. /package/src/cli/{portal-upload.ts → upload.ts} +0 -0
  301. /package/src/server/implementation/mutations/{storeRef.ts → store.ts} +0 -0
  302. /package/src/server/implementation/{rateLimit.ts → ratelimit.ts} +0 -0
  303. /package/src/server/oauth/lib/utils/{customFetch.ts → fetch.ts} +0 -0
  304. /package/src/server/{provider_utils.ts → providers.ts} +0 -0
@@ -11,9 +11,7 @@
11
11
  * `@oslojs/encoding` for base-32 secret encoding.
12
12
  */
13
13
 
14
- import { GenericId } from "convex/values";
15
14
  import {
16
- generateTOTP,
17
15
  verifyTOTPWithGracePeriod,
18
16
  createTOTPKeyURI,
19
17
  } from "@oslojs/otp";
@@ -22,9 +20,21 @@ import {
22
20
  TotpProviderConfig,
23
21
  GenericActionCtxWithAuthConfig,
24
22
  } from "../types.js";
25
- import { AuthDataModel, SessionInfo } from "./types.js";
23
+ import {
24
+ AuthDataModel,
25
+ SessionInfo,
26
+ queryUserById,
27
+ queryTotpById,
28
+ queryTotpVerifiedByUserId,
29
+ queryVerifierById,
30
+ mutateTotpInsert,
31
+ mutateTotpMarkVerified,
32
+ mutateTotpUpdateLastUsed,
33
+ mutateVerifierDelete,
34
+ } from "./types.js";
26
35
  import { callSignIn, callVerifier } from "./mutations/index.js";
27
- import { callVerifierSignature } from "./mutations/verifierSignature.js";
36
+ import { callVerifierSignature } from "./mutations/signature.js";
37
+ import { throwAuthError } from "../errors.js";
28
38
 
29
39
  type EnrichedActionCtx = GenericActionCtxWithAuthConfig<AuthDataModel>;
30
40
 
@@ -53,10 +63,7 @@ async function handleSetup(
53
63
  // TOTP enrollment requires an authenticated user
54
64
  const identity = await ctx.auth.getUserIdentity();
55
65
  if (identity === null) {
56
- throw new Error(
57
- "TOTP enrollment requires an authenticated user. " +
58
- "Sign in first, then add TOTP to your account.",
59
- );
66
+ throwAuthError("TOTP_AUTH_REQUIRED");
60
67
  }
61
68
  const [userId] = identity.subject.split("|");
62
69
 
@@ -67,11 +74,8 @@ async function handleSetup(
67
74
  // Resolve the account name for the otpauth:// URI
68
75
  let accountName: string = params.accountName as string;
69
76
  if (!accountName) {
70
- const user = await ctx.runQuery(
71
- ctx.auth.config.component.public.userGetById,
72
- { userId: userId! },
73
- );
74
- accountName = (user as any)?.email ?? "user";
77
+ const user = await queryUserById(ctx, userId!);
78
+ accountName = user?.email ?? "user";
75
79
  }
76
80
 
77
81
  // Build the otpauth:// URI for QR code scanning
@@ -99,28 +103,25 @@ async function handleSetup(
99
103
  });
100
104
 
101
105
  // Insert an UNVERIFIED TOTP record in the DB
102
- const totpId = await ctx.runMutation(
103
- ctx.auth.config.component.public.totpInsert,
104
- {
105
- userId: userId as any,
106
- secret: secret.buffer.slice(
107
- secret.byteOffset,
108
- secret.byteOffset + secret.byteLength,
109
- ),
110
- digits: provider.options.digits,
111
- period: provider.options.period,
112
- verified: false,
113
- name: params.name,
114
- createdAt: Date.now(),
115
- },
116
- );
106
+ const totpId = await mutateTotpInsert(ctx, {
107
+ userId: userId!,
108
+ secret: secret.buffer.slice(
109
+ secret.byteOffset,
110
+ secret.byteOffset + secret.byteLength,
111
+ ),
112
+ digits: provider.options.digits,
113
+ period: provider.options.period,
114
+ verified: false,
115
+ name: params.name,
116
+ createdAt: Date.now(),
117
+ });
117
118
 
118
119
  return {
119
120
  kind: "totpSetup" as const,
120
121
  uri,
121
122
  secret: base32Secret,
122
123
  verifier,
123
- totpId: totpId as string,
124
+ totpId,
124
125
  };
125
126
  }
126
127
 
@@ -143,37 +144,31 @@ async function handleConfirm(
143
144
  // TOTP confirmation requires an authenticated user
144
145
  const identity = await ctx.auth.getUserIdentity();
145
146
  if (identity === null) {
146
- throw new Error(
147
- "TOTP confirmation requires an authenticated user. " +
148
- "Sign in first, then confirm your TOTP enrollment.",
149
- );
147
+ throwAuthError("TOTP_AUTH_REQUIRED");
150
148
  }
151
149
  const [userId] = identity.subject.split("|");
152
150
 
153
151
  if (!verifierValue) {
154
- throw new Error("Missing verifier");
152
+ throwAuthError("TOTP_MISSING_VERIFIER");
155
153
  }
156
154
  if (!params.code) {
157
- throw new Error("Missing `code` parameter");
155
+ throwAuthError("TOTP_MISSING_CODE");
158
156
  }
159
157
  if (!params.totpId) {
160
- throw new Error("Missing `totpId` parameter");
158
+ throwAuthError("TOTP_MISSING_ID");
161
159
  }
162
160
 
163
161
  // Look up the TOTP record
164
- const totpDoc = await ctx.runQuery(
165
- ctx.auth.config.component.public.totpGetById,
166
- { totpId: params.totpId },
167
- );
162
+ const totpDoc = await queryTotpById(ctx, params.totpId);
168
163
  if (!totpDoc) {
169
- throw new Error("TOTP enrollment not found");
164
+ throwAuthError("TOTP_NOT_FOUND");
170
165
  }
171
- if ((totpDoc as any).verified) {
172
- throw new Error("TOTP enrollment is already verified");
166
+ if (totpDoc.verified) {
167
+ throwAuthError("TOTP_ALREADY_VERIFIED");
173
168
  }
174
169
 
175
170
  // Extract the secret from the TOTP record
176
- const secret = new Uint8Array((totpDoc as any).secret);
171
+ const secret = new Uint8Array(totpDoc.secret);
177
172
 
178
173
  // Verify the code with a 30-second grace period
179
174
  const valid = verifyTOTPWithGracePeriod(
@@ -184,20 +179,14 @@ async function handleConfirm(
184
179
  30,
185
180
  );
186
181
  if (!valid) {
187
- throw new Error("Invalid TOTP code");
182
+ throwAuthError("TOTP_INVALID_CODE");
188
183
  }
189
184
 
190
185
  // Mark the enrollment as verified
191
- await ctx.runMutation(
192
- ctx.auth.config.component.public.totpMarkVerified,
193
- { totpId: params.totpId as any, lastUsedAt: Date.now() },
194
- );
186
+ await mutateTotpMarkVerified(ctx, params.totpId, Date.now());
195
187
 
196
188
  // Clean up the verifier
197
- await ctx.runMutation(
198
- ctx.auth.config.component.public.verifierDelete,
199
- { verifierId: verifierValue },
200
- );
189
+ await mutateVerifierDelete(ctx, verifierValue);
201
190
 
202
191
  // Return tokens for the existing session
203
192
  const signInResult = await callSignIn(ctx, {
@@ -225,60 +214,48 @@ async function handleVerify(
225
214
  verifierValue: string | undefined,
226
215
  ): Promise<{ kind: "signedIn"; signedIn: SessionInfo | null }> {
227
216
  if (!verifierValue) {
228
- throw new Error("Missing verifier");
217
+ throwAuthError("TOTP_MISSING_VERIFIER");
229
218
  }
230
219
  if (!params.code) {
231
- throw new Error("Missing `code` parameter");
220
+ throwAuthError("TOTP_MISSING_CODE");
232
221
  }
233
222
 
234
223
  // Look up the verifier to retrieve the stored userId
235
- const verifierDoc = await ctx.runQuery(
236
- ctx.auth.config.component.public.verifierGetById,
237
- { verifierId: verifierValue },
238
- );
224
+ const verifierDoc = await queryVerifierById(ctx, verifierValue);
239
225
  if (!verifierDoc) {
240
- throw new Error("Invalid or expired verifier");
226
+ throwAuthError("TOTP_INVALID_VERIFIER");
241
227
  }
242
228
 
243
229
  // Parse the signature to extract userId
244
- const signatureData = JSON.parse((verifierDoc as any).signature);
230
+ const signatureData = JSON.parse(verifierDoc.signature!);
245
231
  const userId = signatureData.userId as string;
246
232
 
247
233
  // Look up the user's verified TOTP enrollment
248
- const totpDoc = await ctx.runQuery(
249
- ctx.auth.config.component.public.totpGetVerifiedByUserId,
250
- { userId: userId as any },
251
- );
234
+ const totpDoc = await queryTotpVerifiedByUserId(ctx, userId);
252
235
  if (!totpDoc) {
253
- throw new Error("No TOTP enrollment found");
236
+ throwAuthError("TOTP_NO_ENROLLMENT");
254
237
  }
255
238
 
256
239
  // Extract the secret from the TOTP record
257
- const secret = new Uint8Array((totpDoc as any).secret);
240
+ const secret = new Uint8Array(totpDoc.secret);
258
241
 
259
242
  // Verify the code with a 30-second grace period
260
243
  const valid = verifyTOTPWithGracePeriod(
261
244
  secret,
262
- (totpDoc as any).period,
263
- (totpDoc as any).digits,
245
+ totpDoc.period,
246
+ totpDoc.digits,
264
247
  params.code,
265
248
  30,
266
249
  );
267
250
  if (!valid) {
268
- throw new Error("Invalid TOTP code");
251
+ throwAuthError("TOTP_INVALID_CODE");
269
252
  }
270
253
 
271
254
  // Update last used timestamp
272
- await ctx.runMutation(
273
- ctx.auth.config.component.public.totpUpdateLastUsed,
274
- { totpId: (totpDoc as any)._id, lastUsedAt: Date.now() },
275
- );
255
+ await mutateTotpUpdateLastUsed(ctx, totpDoc._id, Date.now());
276
256
 
277
257
  // Clean up the verifier
278
- await ctx.runMutation(
279
- ctx.auth.config.component.public.verifierDelete,
280
- { verifierId: verifierValue },
281
- );
258
+ await mutateVerifierDelete(ctx, verifierValue);
282
259
 
283
260
  // Sign in the user with tokens
284
261
  const signInResult = await callSignIn(ctx, {
@@ -317,7 +294,8 @@ export async function handleTotp(
317
294
  > {
318
295
  const flow = args.params?.flow;
319
296
  if (!flow) {
320
- throw new Error(
297
+ throwAuthError(
298
+ "TOTP_MISSING_FLOW",
321
299
  "Missing `flow` parameter. Expected one of: setup, confirm, verify",
322
300
  );
323
301
  }
@@ -340,7 +318,8 @@ export async function handleTotp(
340
318
  args.verifier,
341
319
  );
342
320
  default:
343
- throw new Error(
321
+ throwAuthError(
322
+ "TOTP_UNKNOWN_FLOW",
344
323
  `Unknown TOTP flow: ${flow}. Expected one of: setup, confirm, verify`,
345
324
  );
346
325
  }
@@ -358,9 +337,6 @@ export async function checkTotpRequired(
358
337
  ctx: EnrichedActionCtx,
359
338
  userId: string,
360
339
  ): Promise<boolean> {
361
- const totpDoc = await ctx.runQuery(
362
- ctx.auth.config.component.public.totpGetVerifiedByUserId,
363
- { userId: userId as any },
364
- );
340
+ const totpDoc = await queryTotpVerifiedByUserId(ctx, userId);
365
341
  return totpDoc !== null;
366
342
  }
@@ -6,8 +6,9 @@ import {
6
6
  TableNamesInDataModel,
7
7
  } from "convex/server";
8
8
  import { GenericId } from "convex/values";
9
- import { GenericDoc } from "../convex_types.js";
9
+ import { GenericDoc } from "../types.js";
10
10
  import schema from "../../component/schema.js";
11
+ import { AuthComponentApi } from "../types.js";
11
12
 
12
13
  /** Data model derived from the component schema. */
13
14
  export type AuthDataModel = DataModelFromSchemaDefinition<typeof schema>;
@@ -43,3 +44,317 @@ export type SessionInfoWithTokens = {
43
44
  sessionId: GenericId<"session">;
44
45
  tokens: Tokens;
45
46
  };
47
+
48
+ // ---------------------------------------------------------------------------
49
+ // Cross-component document shapes
50
+ // ---------------------------------------------------------------------------
51
+ // These mirror the component schema tables. They exist so that server-side
52
+ // code can work with typed results from cross-component queries/mutations
53
+ // instead of casting to `any` at every field access.
54
+
55
+ export interface TotpDoc {
56
+ _id: string;
57
+ _creationTime: number;
58
+ userId: string;
59
+ secret: ArrayBuffer;
60
+ digits: number;
61
+ period: number;
62
+ verified: boolean;
63
+ name?: string;
64
+ createdAt: number;
65
+ lastUsedAt?: number;
66
+ }
67
+
68
+ export interface PasskeyDoc {
69
+ _id: string;
70
+ _creationTime: number;
71
+ userId: string;
72
+ credentialId: string;
73
+ publicKey: ArrayBuffer;
74
+ algorithm: number;
75
+ counter: number;
76
+ transports?: string[];
77
+ deviceType: string;
78
+ backedUp: boolean;
79
+ name?: string;
80
+ createdAt: number;
81
+ lastUsedAt?: number;
82
+ }
83
+
84
+ export interface VerifierDoc {
85
+ _id: string;
86
+ _creationTime: number;
87
+ signature?: string;
88
+ sessionId?: string;
89
+ }
90
+
91
+ export interface UserDoc {
92
+ _id: string;
93
+ _creationTime: number;
94
+ email?: string;
95
+ emailVerificationTime?: number;
96
+ phone?: string;
97
+ phoneVerificationTime?: number;
98
+ name?: string;
99
+ image?: string;
100
+ isAnonymous?: boolean;
101
+ }
102
+
103
+ export interface KeyDoc {
104
+ _id: string;
105
+ _creationTime: number;
106
+ userId: string;
107
+ prefix: string;
108
+ hashedKey: string;
109
+ name: string;
110
+ scopes: Array<{ resource: string; actions: string[] }>;
111
+ rateLimit?: { maxRequests: number; windowMs: number };
112
+ rateLimitState?: { attemptsLeft: number; lastAttemptTime: number };
113
+ expiresAt?: number;
114
+ lastUsedAt?: number;
115
+ createdAt: number;
116
+ revoked: boolean;
117
+ }
118
+
119
+ // ---------------------------------------------------------------------------
120
+ // Cross-component wrapper context
121
+ // ---------------------------------------------------------------------------
122
+ // Structural type accepted by all wrappers below. Works for both action and
123
+ // mutation contexts — the only capabilities we need are runQuery / runMutation
124
+ // and access to the component API via `auth.config.component`.
125
+
126
+ /** @internal */
127
+ export type ComponentCallCtx = {
128
+ runQuery: GenericActionCtx<AuthDataModel>["runQuery"];
129
+ runMutation: GenericActionCtx<AuthDataModel>["runMutation"];
130
+ auth: { config: { component: AuthComponentApi } };
131
+ };
132
+
133
+ // ---------------------------------------------------------------------------
134
+ // Typed wrappers for cross-component calls
135
+ // ---------------------------------------------------------------------------
136
+ // Each wrapper encapsulates the single `as any` cast at the component
137
+ // boundary so that callers get full type safety on both args and return
138
+ // values.
139
+
140
+ // -- User queries --
141
+
142
+ export async function queryUserById(
143
+ ctx: ComponentCallCtx,
144
+ userId: string,
145
+ ): Promise<UserDoc | null> {
146
+ return (await ctx.runQuery(
147
+ ctx.auth.config.component.public.userGetById,
148
+ { userId },
149
+ )) as UserDoc | null;
150
+ }
151
+
152
+ export async function queryUserByVerifiedEmail(
153
+ ctx: ComponentCallCtx,
154
+ email: string,
155
+ ): Promise<UserDoc | null> {
156
+ return (await ctx.runQuery(
157
+ ctx.auth.config.component.public.userFindByVerifiedEmail,
158
+ { email },
159
+ )) as UserDoc | null;
160
+ }
161
+
162
+ // -- Verifier queries / mutations --
163
+
164
+ export async function queryVerifierById(
165
+ ctx: ComponentCallCtx,
166
+ verifierId: string,
167
+ ): Promise<VerifierDoc | null> {
168
+ return (await ctx.runQuery(
169
+ ctx.auth.config.component.public.verifierGetById,
170
+ { verifierId },
171
+ )) as VerifierDoc | null;
172
+ }
173
+
174
+ export async function mutateVerifierDelete(
175
+ ctx: ComponentCallCtx,
176
+ verifierId: string,
177
+ ): Promise<void> {
178
+ await ctx.runMutation(
179
+ ctx.auth.config.component.public.verifierDelete,
180
+ { verifierId },
181
+ );
182
+ }
183
+
184
+ // -- TOTP queries / mutations --
185
+
186
+ export async function queryTotpById(
187
+ ctx: ComponentCallCtx,
188
+ totpId: string,
189
+ ): Promise<TotpDoc | null> {
190
+ return (await ctx.runQuery(
191
+ ctx.auth.config.component.public.totpGetById,
192
+ { totpId },
193
+ )) as TotpDoc | null;
194
+ }
195
+
196
+ export async function queryTotpVerifiedByUserId(
197
+ ctx: ComponentCallCtx,
198
+ userId: string,
199
+ ): Promise<TotpDoc | null> {
200
+ return (await ctx.runQuery(
201
+ ctx.auth.config.component.public.totpGetVerifiedByUserId,
202
+ { userId },
203
+ )) as TotpDoc | null;
204
+ }
205
+
206
+ export async function mutateTotpInsert(
207
+ ctx: ComponentCallCtx,
208
+ args: {
209
+ userId: string;
210
+ secret: ArrayBuffer;
211
+ digits: number;
212
+ period: number;
213
+ verified: boolean;
214
+ name?: string;
215
+ createdAt: number;
216
+ },
217
+ ): Promise<string> {
218
+ return (await ctx.runMutation(
219
+ ctx.auth.config.component.public.totpInsert,
220
+ args,
221
+ )) as string;
222
+ }
223
+
224
+ export async function mutateTotpMarkVerified(
225
+ ctx: ComponentCallCtx,
226
+ totpId: string,
227
+ lastUsedAt: number,
228
+ ): Promise<void> {
229
+ await ctx.runMutation(
230
+ ctx.auth.config.component.public.totpMarkVerified,
231
+ { totpId, lastUsedAt },
232
+ );
233
+ }
234
+
235
+ export async function mutateTotpUpdateLastUsed(
236
+ ctx: ComponentCallCtx,
237
+ totpId: string,
238
+ lastUsedAt: number,
239
+ ): Promise<void> {
240
+ await ctx.runMutation(
241
+ ctx.auth.config.component.public.totpUpdateLastUsed,
242
+ { totpId, lastUsedAt },
243
+ );
244
+ }
245
+
246
+ // -- Passkey queries / mutations --
247
+
248
+ export async function queryPasskeysByUserId(
249
+ ctx: ComponentCallCtx,
250
+ userId: string,
251
+ ): Promise<PasskeyDoc[]> {
252
+ return (await ctx.runQuery(
253
+ ctx.auth.config.component.public.passkeyListByUserId,
254
+ { userId },
255
+ )) as PasskeyDoc[];
256
+ }
257
+
258
+ export async function queryPasskeyByCredentialId(
259
+ ctx: ComponentCallCtx,
260
+ credentialId: string,
261
+ ): Promise<PasskeyDoc | null> {
262
+ return (await ctx.runQuery(
263
+ ctx.auth.config.component.public.passkeyGetByCredentialId,
264
+ { credentialId },
265
+ )) as PasskeyDoc | null;
266
+ }
267
+
268
+ export async function mutatePasskeyInsert(
269
+ ctx: ComponentCallCtx,
270
+ args: {
271
+ userId: string;
272
+ credentialId: string;
273
+ publicKey: ArrayBuffer | ArrayBufferLike;
274
+ algorithm: number;
275
+ counter: number;
276
+ transports?: string[];
277
+ deviceType: string;
278
+ backedUp: boolean;
279
+ name?: string;
280
+ createdAt: number;
281
+ },
282
+ ): Promise<string> {
283
+ return (await ctx.runMutation(
284
+ ctx.auth.config.component.public.passkeyInsert,
285
+ args,
286
+ )) as string;
287
+ }
288
+
289
+ export async function mutatePasskeyUpdateCounter(
290
+ ctx: ComponentCallCtx,
291
+ passkeyId: string,
292
+ counter: number,
293
+ lastUsedAt: number,
294
+ ): Promise<void> {
295
+ await ctx.runMutation(
296
+ ctx.auth.config.component.public.passkeyUpdateCounter,
297
+ { passkeyId, counter, lastUsedAt },
298
+ );
299
+ }
300
+
301
+ // -- Key queries / mutations --
302
+
303
+ export async function mutateKeyInsert(
304
+ ctx: ComponentCallCtx,
305
+ args: {
306
+ userId: string;
307
+ prefix: string;
308
+ hashedKey: string;
309
+ name: string;
310
+ scopes: Array<{ resource: string; actions: string[] }>;
311
+ rateLimit?: { maxRequests: number; windowMs: number };
312
+ expiresAt?: number;
313
+ },
314
+ ): Promise<string> {
315
+ return (await ctx.runMutation(
316
+ ctx.auth.config.component.public.keyInsert,
317
+ args,
318
+ )) as string;
319
+ }
320
+
321
+ export async function queryKeysByUserId(
322
+ ctx: ComponentCallCtx,
323
+ userId: string,
324
+ ): Promise<KeyDoc[]> {
325
+ return (await ctx.runQuery(
326
+ ctx.auth.config.component.public.keyListByUserId,
327
+ { userId },
328
+ )) as KeyDoc[];
329
+ }
330
+
331
+ export async function queryKeyById(
332
+ ctx: ComponentCallCtx,
333
+ keyId: string,
334
+ ): Promise<KeyDoc | null> {
335
+ return (await ctx.runQuery(
336
+ ctx.auth.config.component.public.keyGetById,
337
+ { keyId },
338
+ )) as KeyDoc | null;
339
+ }
340
+
341
+ export async function mutateKeyPatch(
342
+ ctx: ComponentCallCtx,
343
+ keyId: string,
344
+ data: Record<string, unknown>,
345
+ ): Promise<void> {
346
+ await ctx.runMutation(
347
+ ctx.auth.config.component.public.keyPatch,
348
+ { keyId, data },
349
+ );
350
+ }
351
+
352
+ export async function mutateKeyDelete(
353
+ ctx: ComponentCallCtx,
354
+ keyId: string,
355
+ ): Promise<void> {
356
+ await ctx.runMutation(
357
+ ctx.auth.config.component.public.keyDelete,
358
+ { keyId },
359
+ );
360
+ }
@@ -3,6 +3,7 @@ import { Doc, MutationCtx } from "./types.js";
3
3
  import { AuthProviderMaterializedConfig, ConvexAuthConfig } from "../types.js";
4
4
  import { LOG_LEVELS, logWithLevel } from "./utils.js";
5
5
  import { authDb } from "./db.js";
6
+ import { throwAuthError } from "../errors.js";
6
7
 
7
8
  type CreateOrUpdateUserArgs = {
8
9
  type: "oauth" | "credentials" | "email" | "phone" | "verification";
@@ -137,12 +138,10 @@ async function defaultCreateOrUpdateUser(
137
138
  try {
138
139
  await db.users.patch(userId, userData);
139
140
  } catch (error) {
140
- throw new Error(
141
- `Could not update user document with ID \`${userId}\`, ` +
141
+ throwAuthError("USER_UPDATE_FAILED", `Could not update user document with ID \`${userId}\`, ` +
142
142
  `either the user has been deleted but their account has not, ` +
143
143
  `or the profile data doesn't match the \`users\` table schema: ` +
144
- `${(error as Error).message}`,
145
- );
144
+ `${(error as Error).message}`);
146
145
  }
147
146
  } else {
148
147
  userId = (await db.users.insert(userData)) as GenericId<"user">;
@@ -231,9 +230,7 @@ export async function getAccountOrThrow(
231
230
  ) {
232
231
  const existingAccount = await authDb(ctx, config).accounts.getById(existingAccountId);
233
232
  if (existingAccount === null) {
234
- throw new Error(
235
- `Expected an account to exist for ID "${existingAccountId}"`,
236
- );
233
+ throwAuthError("ACCOUNT_NOT_FOUND", `Expected an account to exist for ID "${existingAccountId}"`);
237
234
  }
238
235
  return existingAccount;
239
236
  }