@robelest/convex-auth 0.0.2 → 0.0.3-preview.1

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 (173) hide show
  1. package/dist/bin.cjs +1 -1
  2. package/dist/client/index.d.ts +33 -9
  3. package/dist/client/index.d.ts.map +1 -1
  4. package/dist/client/index.js +79 -13
  5. package/dist/client/index.js.map +1 -1
  6. package/dist/component/_generated/component.d.ts +48 -0
  7. package/dist/component/_generated/component.d.ts.map +1 -1
  8. package/dist/component/index.d.ts +10 -4
  9. package/dist/component/index.d.ts.map +1 -1
  10. package/dist/component/index.js +8 -3
  11. package/dist/component/index.js.map +1 -1
  12. package/dist/component/public.d.ts +163 -3
  13. package/dist/component/public.d.ts.map +1 -1
  14. package/dist/component/public.js +124 -0
  15. package/dist/component/public.js.map +1 -1
  16. package/dist/component/schema.d.ts +81 -2
  17. package/dist/component/schema.d.ts.map +1 -1
  18. package/dist/component/schema.js +45 -0
  19. package/dist/component/schema.js.map +1 -1
  20. package/dist/providers/anonymous.d.ts +3 -0
  21. package/dist/providers/anonymous.d.ts.map +1 -1
  22. package/dist/providers/anonymous.js +3 -0
  23. package/dist/providers/anonymous.js.map +1 -1
  24. package/dist/providers/credentials.d.ts +3 -0
  25. package/dist/providers/credentials.d.ts.map +1 -1
  26. package/dist/providers/credentials.js +3 -0
  27. package/dist/providers/credentials.js.map +1 -1
  28. package/dist/providers/email.d.ts +3 -0
  29. package/dist/providers/email.d.ts.map +1 -1
  30. package/dist/providers/email.js +3 -0
  31. package/dist/providers/email.js.map +1 -1
  32. package/dist/providers/passkey.d.ts +7 -1
  33. package/dist/providers/passkey.d.ts.map +1 -1
  34. package/dist/providers/passkey.js +7 -1
  35. package/dist/providers/passkey.js.map +1 -1
  36. package/dist/providers/password.d.ts +3 -0
  37. package/dist/providers/password.d.ts.map +1 -1
  38. package/dist/providers/password.js +3 -0
  39. package/dist/providers/password.js.map +1 -1
  40. package/dist/providers/phone.d.ts +3 -0
  41. package/dist/providers/phone.d.ts.map +1 -1
  42. package/dist/providers/phone.js +3 -0
  43. package/dist/providers/phone.js.map +1 -1
  44. package/dist/providers/totp.d.ts +8 -0
  45. package/dist/providers/totp.d.ts.map +1 -1
  46. package/dist/providers/totp.js +8 -0
  47. package/dist/providers/totp.js.map +1 -1
  48. package/dist/server/convex-auth.d.ts +185 -25
  49. package/dist/server/convex-auth.d.ts.map +1 -1
  50. package/dist/server/convex-auth.js +317 -58
  51. package/dist/server/convex-auth.js.map +1 -1
  52. package/dist/server/email-templates.d.ts +18 -0
  53. package/dist/server/email-templates.d.ts.map +1 -0
  54. package/dist/server/email-templates.js +74 -0
  55. package/dist/server/email-templates.js.map +1 -0
  56. package/dist/server/errors.d.ts +146 -0
  57. package/dist/server/errors.d.ts.map +1 -0
  58. package/dist/server/errors.js +176 -0
  59. package/dist/server/errors.js.map +1 -0
  60. package/dist/server/implementation/apiKey.d.ts +74 -0
  61. package/dist/server/implementation/apiKey.d.ts.map +1 -0
  62. package/dist/server/implementation/apiKey.js +139 -0
  63. package/dist/server/implementation/apiKey.js.map +1 -0
  64. package/dist/server/implementation/index.d.ts +151 -14
  65. package/dist/server/implementation/index.d.ts.map +1 -1
  66. package/dist/server/implementation/index.js +216 -24
  67. package/dist/server/implementation/index.js.map +1 -1
  68. package/dist/server/implementation/mutations/createAccountFromCredentials.d.ts.map +1 -1
  69. package/dist/server/implementation/mutations/createAccountFromCredentials.js +2 -1
  70. package/dist/server/implementation/mutations/createAccountFromCredentials.js.map +1 -1
  71. package/dist/server/implementation/mutations/createVerificationCode.d.ts +2 -2
  72. package/dist/server/implementation/mutations/index.d.ts +6 -6
  73. package/dist/server/implementation/mutations/modifyAccount.d.ts.map +1 -1
  74. package/dist/server/implementation/mutations/modifyAccount.js +2 -1
  75. package/dist/server/implementation/mutations/modifyAccount.js.map +1 -1
  76. package/dist/server/implementation/mutations/userOAuth.d.ts.map +1 -1
  77. package/dist/server/implementation/mutations/userOAuth.js +2 -1
  78. package/dist/server/implementation/mutations/userOAuth.js.map +1 -1
  79. package/dist/server/implementation/mutations/verifierSignature.d.ts.map +1 -1
  80. package/dist/server/implementation/mutations/verifierSignature.js +2 -1
  81. package/dist/server/implementation/mutations/verifierSignature.js.map +1 -1
  82. package/dist/server/implementation/passkey.d.ts.map +1 -1
  83. package/dist/server/implementation/passkey.js +28 -29
  84. package/dist/server/implementation/passkey.js.map +1 -1
  85. package/dist/server/implementation/provider.d.ts.map +1 -1
  86. package/dist/server/implementation/provider.js +5 -4
  87. package/dist/server/implementation/provider.js.map +1 -1
  88. package/dist/server/implementation/redirects.d.ts.map +1 -1
  89. package/dist/server/implementation/redirects.js +2 -1
  90. package/dist/server/implementation/redirects.js.map +1 -1
  91. package/dist/server/implementation/refreshTokens.d.ts.map +1 -1
  92. package/dist/server/implementation/refreshTokens.js +2 -1
  93. package/dist/server/implementation/refreshTokens.js.map +1 -1
  94. package/dist/server/implementation/signIn.d.ts.map +1 -1
  95. package/dist/server/implementation/signIn.js +8 -18
  96. package/dist/server/implementation/signIn.js.map +1 -1
  97. package/dist/server/implementation/totp.d.ts.map +1 -1
  98. package/dist/server/implementation/totp.js +16 -17
  99. package/dist/server/implementation/totp.js.map +1 -1
  100. package/dist/server/implementation/users.d.ts.map +1 -1
  101. package/dist/server/implementation/users.js +3 -2
  102. package/dist/server/implementation/users.js.map +1 -1
  103. package/dist/server/index.d.ts +157 -3
  104. package/dist/server/index.d.ts.map +1 -1
  105. package/dist/server/index.js +180 -17
  106. package/dist/server/index.js.map +1 -1
  107. package/dist/server/oauth/authorizationUrl.d.ts.map +1 -1
  108. package/dist/server/oauth/authorizationUrl.js +2 -1
  109. package/dist/server/oauth/authorizationUrl.js.map +1 -1
  110. package/dist/server/oauth/callback.d.ts.map +1 -1
  111. package/dist/server/oauth/callback.js +5 -4
  112. package/dist/server/oauth/callback.js.map +1 -1
  113. package/dist/server/oauth/checks.d.ts.map +1 -1
  114. package/dist/server/oauth/checks.js +2 -1
  115. package/dist/server/oauth/checks.js.map +1 -1
  116. package/dist/server/oauth/convexAuth.d.ts.map +1 -1
  117. package/dist/server/oauth/convexAuth.js +3 -2
  118. package/dist/server/oauth/convexAuth.js.map +1 -1
  119. package/dist/server/provider_utils.d.ts +2 -0
  120. package/dist/server/provider_utils.d.ts.map +1 -1
  121. package/dist/server/types.d.ts +240 -5
  122. package/dist/server/types.d.ts.map +1 -1
  123. package/dist/server/utils.d.ts.map +1 -1
  124. package/dist/server/utils.js +2 -1
  125. package/dist/server/utils.js.map +1 -1
  126. package/dist/server/version.d.ts +2 -0
  127. package/dist/server/version.d.ts.map +1 -0
  128. package/dist/server/version.js +3 -0
  129. package/dist/server/version.js.map +1 -0
  130. package/package.json +7 -2
  131. package/src/cli/index.ts +1 -1
  132. package/src/cli/utils.ts +248 -0
  133. package/src/client/index.ts +105 -15
  134. package/src/component/_generated/component.ts +61 -0
  135. package/src/component/index.ts +11 -2
  136. package/src/component/public.ts +142 -0
  137. package/src/component/schema.ts +52 -0
  138. package/src/providers/anonymous.ts +3 -0
  139. package/src/providers/credentials.ts +3 -0
  140. package/src/providers/email.ts +3 -0
  141. package/src/providers/passkey.ts +8 -1
  142. package/src/providers/password.ts +3 -0
  143. package/src/providers/phone.ts +3 -0
  144. package/src/providers/totp.ts +9 -0
  145. package/src/server/convex-auth.ts +385 -73
  146. package/src/server/email-templates.ts +77 -0
  147. package/src/server/errors.ts +269 -0
  148. package/src/server/implementation/apiKey.ts +186 -0
  149. package/src/server/implementation/index.ts +288 -28
  150. package/src/server/implementation/mutations/createAccountFromCredentials.ts +2 -1
  151. package/src/server/implementation/mutations/modifyAccount.ts +2 -3
  152. package/src/server/implementation/mutations/userOAuth.ts +2 -1
  153. package/src/server/implementation/mutations/verifierSignature.ts +2 -1
  154. package/src/server/implementation/passkey.ts +33 -35
  155. package/src/server/implementation/provider.ts +5 -8
  156. package/src/server/implementation/redirects.ts +2 -3
  157. package/src/server/implementation/refreshTokens.ts +2 -1
  158. package/src/server/implementation/signIn.ts +9 -18
  159. package/src/server/implementation/totp.ts +18 -21
  160. package/src/server/implementation/users.ts +4 -7
  161. package/src/server/index.ts +240 -37
  162. package/src/server/oauth/authorizationUrl.ts +2 -1
  163. package/src/server/oauth/callback.ts +5 -4
  164. package/src/server/oauth/checks.ts +3 -1
  165. package/src/server/oauth/convexAuth.ts +6 -3
  166. package/src/server/types.ts +254 -5
  167. package/src/server/utils.ts +3 -1
  168. package/src/server/version.ts +2 -0
  169. package/dist/server/portal.d.ts +0 -116
  170. package/dist/server/portal.d.ts.map +0 -1
  171. package/dist/server/portal.js +0 -294
  172. package/dist/server/portal.js.map +0 -1
  173. package/src/server/portal.ts +0 -375
@@ -986,4 +986,146 @@ export const inviteRevoke = mutation({
986
986
  },
987
987
  });
988
988
 
989
+ // ============================================================================
990
+ // API Keys
991
+ // ============================================================================
992
+
993
+ /**
994
+ * Insert a new API key record.
995
+ *
996
+ * The caller is responsible for hashing the raw key before passing it here —
997
+ * this function only stores the hash and metadata.
998
+ */
999
+ export const keyInsert = mutation({
1000
+ args: {
1001
+ userId: v.id("user"),
1002
+ prefix: v.string(),
1003
+ hashedKey: v.string(),
1004
+ name: v.string(),
1005
+ scopes: v.array(
1006
+ v.object({
1007
+ resource: v.string(),
1008
+ actions: v.array(v.string()),
1009
+ }),
1010
+ ),
1011
+ rateLimit: v.optional(
1012
+ v.object({
1013
+ maxRequests: v.number(),
1014
+ windowMs: v.number(),
1015
+ }),
1016
+ ),
1017
+ expiresAt: v.optional(v.number()),
1018
+ },
1019
+ handler: async (ctx, args) => {
1020
+ return await ctx.db.insert("key", {
1021
+ ...args,
1022
+ createdAt: Date.now(),
1023
+ revoked: false,
1024
+ });
1025
+ },
1026
+ });
1027
+
1028
+ /**
1029
+ * Look up an API key by its SHA-256 hash.
1030
+ *
1031
+ * Used during Bearer token verification. Returns the full key record
1032
+ * (including rate limit state) or `null` if not found.
1033
+ */
1034
+ export const keyGetByHashedKey = query({
1035
+ args: { hashedKey: v.string() },
1036
+ handler: async (ctx, { hashedKey }) => {
1037
+ return await ctx.db
1038
+ .query("key")
1039
+ .withIndex("hashedKey", (q) => q.eq("hashedKey", hashedKey))
1040
+ .first();
1041
+ },
1042
+ });
1043
+
1044
+ /** List all API keys for a user. */
1045
+ export const keyListByUserId = query({
1046
+ args: { userId: v.id("user") },
1047
+ handler: async (ctx, { userId }) => {
1048
+ return await ctx.db
1049
+ .query("key")
1050
+ .withIndex("userId", (q) => q.eq("userId", userId))
1051
+ .collect();
1052
+ },
1053
+ });
1054
+
1055
+ /** List all API keys across all users (for portal admin). */
1056
+ export const keyList = query({
1057
+ args: {},
1058
+ handler: async (ctx) => {
1059
+ return await ctx.db.query("key").collect();
1060
+ },
1061
+ });
989
1062
 
1063
+ /** Get a single API key by document ID. */
1064
+ export const keyGetById = query({
1065
+ args: { keyId: v.id("key") },
1066
+ handler: async (ctx, { keyId }) => {
1067
+ return await ctx.db.get(keyId);
1068
+ },
1069
+ });
1070
+
1071
+ /**
1072
+ * Patch an API key record. Used for updating name, scopes, rate limit config,
1073
+ * revocation, and lastUsedAt / rate limit state tracking.
1074
+ */
1075
+ export const keyPatch = mutation({
1076
+ args: {
1077
+ keyId: v.id("key"),
1078
+ data: v.object({
1079
+ name: v.optional(v.string()),
1080
+ scopes: v.optional(
1081
+ v.array(
1082
+ v.object({
1083
+ resource: v.string(),
1084
+ actions: v.array(v.string()),
1085
+ }),
1086
+ ),
1087
+ ),
1088
+ rateLimit: v.optional(
1089
+ v.object({
1090
+ maxRequests: v.number(),
1091
+ windowMs: v.number(),
1092
+ }),
1093
+ ),
1094
+ rateLimitState: v.optional(
1095
+ v.object({
1096
+ attemptsLeft: v.number(),
1097
+ lastAttemptTime: v.number(),
1098
+ }),
1099
+ ),
1100
+ revoked: v.optional(v.boolean()),
1101
+ lastUsedAt: v.optional(v.number()),
1102
+ }),
1103
+ },
1104
+ handler: async (ctx, { keyId, data }) => {
1105
+ const key = await ctx.db.get(keyId);
1106
+ if (key === null) {
1107
+ throw new ConvexError({
1108
+ code: "KEY_NOT_FOUND",
1109
+ message: "API key not found",
1110
+ keyId,
1111
+ });
1112
+ }
1113
+ await ctx.db.patch(keyId, data);
1114
+ },
1115
+ });
1116
+
1117
+ /** Hard delete an API key record. */
1118
+ export const keyDelete = mutation({
1119
+ args: { keyId: v.id("key") },
1120
+ handler: async (ctx, { keyId }) => {
1121
+ const key = await ctx.db.get(keyId);
1122
+ if (key === null) {
1123
+ throw new ConvexError({
1124
+ code: "KEY_NOT_FOUND",
1125
+ message: "API key not found",
1126
+ keyId,
1127
+ });
1128
+ }
1129
+ await ctx.db.delete(keyId);
1130
+ },
1131
+ });
@@ -226,4 +226,56 @@ export default defineSchema({
226
226
  "status",
227
227
  "acceptedByUserId",
228
228
  ]),
229
+
230
+ /**
231
+ * API keys for programmatic access. Each key links a user to a set of
232
+ * scoped permissions and optional per-key rate limiting.
233
+ *
234
+ * The raw key is never stored — only a SHA-256 hash. A short prefix
235
+ * (e.g. "sk_live_abc1...") is kept for display in the portal.
236
+ *
237
+ * Keys support:
238
+ * - **Scoped permissions**: resource:action pairs (e.g. users:read)
239
+ * - **Per-key rate limiting**: token-bucket with configurable window
240
+ * - **Expiration**: optional TTL
241
+ * - **Soft revocation**: `revoked` flag preserves audit trail
242
+ */
243
+ key: defineTable({
244
+ userId: v.id("user"),
245
+ /** First chars of the key for display (e.g. "sk_live_abc1..."). */
246
+ prefix: v.string(),
247
+ /** SHA-256 hex hash of the full raw key. */
248
+ hashedKey: v.string(),
249
+ /** User-assigned name (e.g. "CI Pipeline", "Production API"). */
250
+ name: v.string(),
251
+ /** Scoped permissions: [{ resource: "users", actions: ["read", "list"] }]. */
252
+ scopes: v.array(
253
+ v.object({
254
+ resource: v.string(),
255
+ actions: v.array(v.string()),
256
+ }),
257
+ ),
258
+ /** Optional per-key rate limit configuration. */
259
+ rateLimit: v.optional(
260
+ v.object({
261
+ maxRequests: v.number(),
262
+ windowMs: v.number(),
263
+ }),
264
+ ),
265
+ /** Rate limit state tracking (token-bucket). */
266
+ rateLimitState: v.optional(
267
+ v.object({
268
+ attemptsLeft: v.number(),
269
+ lastAttemptTime: v.number(),
270
+ }),
271
+ ),
272
+ /** Expiration timestamp. Null/undefined = never expires. */
273
+ expiresAt: v.optional(v.number()),
274
+ lastUsedAt: v.optional(v.number()),
275
+ createdAt: v.number(),
276
+ /** Soft-revoke flag. Revoked keys are kept for audit trail. */
277
+ revoked: v.boolean(),
278
+ })
279
+ .index("userId", ["userId"])
280
+ .index("hashedKey", ["hashedKey"]),
229
281
  });
@@ -56,6 +56,9 @@ export interface AnonymousConfig<DataModel extends GenericDataModel> {
56
56
  * An anonymous authentication provider.
57
57
  *
58
58
  * This provider doesn't require any user-provided information.
59
+ *
60
+ * @param config - Optional overrides (custom ID, profile, etc.).
61
+ * @returns A `ConvexCredentialsConfig` to include in your `providers` array.
59
62
  */
60
63
  export default function anonymous<DataModel extends GenericDataModel>(
61
64
  config: AnonymousConfig<DataModel> = {},
@@ -94,6 +94,9 @@ export interface CredentialsUserConfig<
94
94
  /**
95
95
  * The Credentials provider allows you to handle signing in with arbitrary credentials,
96
96
  * such as a username and password, domain, or two factor authentication or hardware device (e.g. YubiKey U2F / FIDO).
97
+ *
98
+ * @param config - Credential-specific options (authorize callback, profile, etc.).
99
+ * @returns A `ConvexCredentialsConfig` to include in your `providers` array.
97
100
  */
98
101
  export default function credentials<DataModel extends GenericDataModel>(
99
102
  config: CredentialsUserConfig<DataModel>,
@@ -30,6 +30,9 @@ import { EmailConfig, EmailUserConfig } from "../server/types.js";
30
30
  * ```
31
31
  *
32
32
  * Make sure the token has high enough entropy to be secure.
33
+ *
34
+ * @param config - Email provider options including `sendVerificationRequest`.
35
+ * @returns An `EmailConfig` to include in your `providers` array.
33
36
  */
34
37
  export default function email<DataModel extends GenericDataModel>(
35
38
  config: EmailUserConfig<DataModel> &
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Passkey (WebAuthn) authentication provider.
3
+ *
4
+ * @module
5
+ */
6
+
1
7
  import { PasskeyProviderConfig } from "../server/types.js";
2
8
 
3
9
  /**
@@ -15,7 +21,8 @@ import { PasskeyProviderConfig } from "../server/types.js";
15
21
  * });
16
22
  * ```
17
23
  *
18
- * @param config Optional configuration for the relying party and credential options.
24
+ * @param config - Optional relying party and credential options.
25
+ * @returns A `PasskeyProviderConfig` to include in your `providers` array.
19
26
  */
20
27
  export default function passkey(
21
28
  config?: Partial<PasskeyProviderConfig["options"]>,
@@ -105,6 +105,9 @@ export interface PasswordConfig<DataModel extends GenericDataModel> {
105
105
  *
106
106
  * Email verification is not required unless you pass
107
107
  * an email provider to the `verify` option.
108
+ *
109
+ * @param config - Password options (custom ID, crypto, verify, profile, etc.).
110
+ * @returns A `ConvexCredentialsConfig` to include in your `providers` array.
108
111
  */
109
112
  export default function password<DataModel extends GenericDataModel>(
110
113
  config: PasswordConfig<DataModel> = {},
@@ -19,6 +19,9 @@ import { PhoneConfig, PhoneUserConfig } from "../server/types.js";
19
19
  * When you use this function to create your config, it
20
20
  * checks that there is a `phone` field during token verification
21
21
  * that matches the `phone` used during the initial `signIn` call.
22
+ *
23
+ * @param config - Phone provider options including `sendVerificationRequest`.
24
+ * @returns A `PhoneConfig` to include in your `providers` array.
22
25
  */
23
26
  export default function phone<DataModel extends GenericDataModel>(
24
27
  config: PhoneUserConfig & Pick<PhoneConfig, "sendVerificationRequest">,
@@ -1,3 +1,9 @@
1
+ /**
2
+ * TOTP (Time-based One-Time Password) two-factor authentication provider.
3
+ *
4
+ * @module
5
+ */
6
+
1
7
  import { TotpProviderConfig } from "../server/types.js";
2
8
 
3
9
  /**
@@ -10,6 +16,9 @@ import { TotpProviderConfig } from "../server/types.js";
10
16
  * providers: [TOTP({ issuer: "My App" })],
11
17
  * });
12
18
  * ```
19
+ *
20
+ * @param config - TOTP options: issuer name, digit count, and period.
21
+ * @returns A `TotpProviderConfig` to include in your `providers` array.
13
22
  */
14
23
  export default function totp(
15
24
  config?: Partial<TotpProviderConfig["options"]>,