@robelest/convex-auth 0.0.4-preview.30 → 0.0.4-preview.31

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 (105) hide show
  1. package/dist/bin.js +125 -36
  2. package/dist/browser/index.d.ts +3 -13
  3. package/dist/browser/index.js +47 -12
  4. package/dist/browser/navigation.js +1 -1
  5. package/dist/browser/passkey.js +7 -7
  6. package/dist/browser/runtime.js +13 -15
  7. package/dist/client/core/types.d.ts +179 -63
  8. package/dist/client/core/types.js +6 -0
  9. package/dist/client/factors/totp.js +1 -1
  10. package/dist/client/index.d.ts +5 -4
  11. package/dist/client/index.js +115 -56
  12. package/dist/client/runtime/mutex.js +3 -2
  13. package/dist/component/_generated/component.d.ts +40 -0
  14. package/dist/component/convex.config.d.ts +2 -2
  15. package/dist/component/http.js +9 -0
  16. package/dist/component/index.d.ts +1 -1
  17. package/dist/component/model.d.ts +25 -25
  18. package/dist/component/model.js +2 -1
  19. package/dist/component/modules.js +1 -0
  20. package/dist/component/public/factors/passkeys.js +31 -1
  21. package/dist/component/public/identity/codes.js +1 -1
  22. package/dist/component/public/identity/tokens.js +2 -1
  23. package/dist/component/public/identity/verifiers.js +15 -5
  24. package/dist/component/public.js +2 -2
  25. package/dist/component/schema.d.ts +292 -290
  26. package/dist/component/schema.js +2 -1
  27. package/dist/core/index.d.ts +8 -3
  28. package/dist/core/index.js +7 -2
  29. package/dist/expo/index.d.ts +21 -0
  30. package/dist/expo/index.js +148 -0
  31. package/dist/expo/passkey.js +174 -0
  32. package/dist/providers/apple.d.ts +1 -1
  33. package/dist/providers/apple.js +6 -8
  34. package/dist/providers/custom.d.ts +1 -1
  35. package/dist/providers/custom.js +4 -7
  36. package/dist/providers/github.d.ts +1 -1
  37. package/dist/providers/github.js +5 -8
  38. package/dist/providers/google.d.ts +1 -1
  39. package/dist/providers/google.js +5 -8
  40. package/dist/providers/microsoft.d.ts +1 -1
  41. package/dist/providers/microsoft.js +5 -9
  42. package/dist/providers/password.d.ts +18 -37
  43. package/dist/providers/password.js +170 -115
  44. package/dist/providers/redirect.d.ts +1 -0
  45. package/dist/providers/redirect.js +20 -0
  46. package/dist/server/auth.d.ts +6 -7
  47. package/dist/server/auth.js +3 -2
  48. package/dist/server/{ctxCache.js → cache/context.js} +2 -2
  49. package/dist/server/{componentContext.d.ts → component/context.d.ts} +2 -2
  50. package/dist/server/context.js +3 -10
  51. package/dist/server/contract.d.ts +2 -87
  52. package/dist/server/contract.js +1 -1
  53. package/dist/server/cookies.js +25 -1
  54. package/dist/server/core.js +1 -1
  55. package/dist/server/errors.js +24 -1
  56. package/dist/server/{auth-context.d.ts → facade.d.ts} +3 -45
  57. package/dist/server/{auth-context.js → facade.js} +11 -12
  58. package/dist/server/http.d.ts +7 -7
  59. package/dist/server/http.js +36 -7
  60. package/dist/server/{convexIdentity.d.ts → identity/convex.d.ts} +3 -3
  61. package/dist/server/index.d.ts +5 -3
  62. package/dist/server/index.js +3 -2
  63. package/dist/server/mounts.d.ts +175 -22
  64. package/dist/server/mutations/code.js +7 -1
  65. package/dist/server/mutations/{credentialsSignIn.js → credentials/signin.js} +10 -10
  66. package/dist/server/mutations/index.js +1 -1
  67. package/dist/server/mutations/invalidate.js +11 -1
  68. package/dist/server/mutations/oauth.js +25 -27
  69. package/dist/server/mutations/signin.js +6 -0
  70. package/dist/server/mutations/signout.js +5 -0
  71. package/dist/server/mutations/store.js +1 -1
  72. package/dist/server/oauth/factory.js +11 -3
  73. package/dist/server/passkey.js +126 -110
  74. package/dist/server/prefetch.js +8 -1
  75. package/dist/server/redirects.js +11 -3
  76. package/dist/server/refresh.js +6 -1
  77. package/dist/server/runtime.d.ts +58 -36
  78. package/dist/server/runtime.js +333 -36
  79. package/dist/server/services/group.js +4 -0
  80. package/dist/server/sessions.js +1 -0
  81. package/dist/server/signin.js +8 -6
  82. package/dist/server/sso/domain.d.ts +159 -16
  83. package/dist/server/sso/domain.js +1 -1
  84. package/dist/server/sso/http.js +144 -60
  85. package/dist/server/sso/oidc.js +28 -12
  86. package/dist/server/sso/policy.js +30 -14
  87. package/dist/server/sso/provision.js +1 -1
  88. package/dist/server/sso/saml.js +18 -9
  89. package/dist/server/sso/scim.js +12 -4
  90. package/dist/server/sso/shared.js +5 -5
  91. package/dist/server/telemetry.js +3 -0
  92. package/dist/server/tokens.js +10 -2
  93. package/dist/server/totp.js +127 -100
  94. package/dist/server/types.d.ts +224 -151
  95. package/dist/server/url.js +1 -1
  96. package/dist/server/users.js +93 -53
  97. package/dist/server/wellknown.d.ts +130 -0
  98. package/dist/server/wellknown.js +195 -0
  99. package/dist/shared/errors.js +0 -1
  100. package/package.json +36 -4
  101. package/dist/server/oauth/index.js +0 -12
  102. package/dist/server/utils/dispatch.js +0 -36
  103. package/dist/shared/authResults.d.ts +0 -16
  104. /package/dist/server/{componentContext.js → component/context.js} +0 -0
  105. /package/dist/server/{convexIdentity.js → identity/convex.js} +0 -0
@@ -28,17 +28,20 @@ import { COSEKeyType, ClientDataType, coseAlgorithmES256, coseAlgorithmRS256, cr
28
28
  *
29
29
  * @module
30
30
  */
31
- const PASSKEY_FLOW = {
32
- registerOptions: "registerOptions",
33
- registerVerify: "registerVerify",
34
- authOptions: "authOptions",
35
- authVerify: "authVerify"
36
- };
31
+ /**
32
+ * Passkey provider has three single-word flows:
33
+ *
34
+ * - `register` — issue a WebAuthn registration challenge (phase 1).
35
+ * - `signIn` — issue a WebAuthn authentication challenge (phase 1).
36
+ * - `verify` — consume the WebAuthn response (phase 2). The server
37
+ * auto-detects whether this completes a registration
38
+ * (`attestationObject` present) or a sign-in
39
+ * (`signature` + `credentialId` present).
40
+ */
37
41
  const PASSKEY_FLOWS = [
38
- PASSKEY_FLOW.registerOptions,
39
- PASSKEY_FLOW.registerVerify,
40
- PASSKEY_FLOW.authOptions,
41
- PASSKEY_FLOW.authVerify
42
+ "register",
43
+ "signIn",
44
+ "verify"
42
45
  ];
43
46
  const requireStringParam = (value, name) => {
44
47
  if (typeof value !== "string") throw convexError("INVALID_PARAMETERS", `Missing \`${name}\` parameter.`);
@@ -107,7 +110,7 @@ function verifyUserFlags(authData, rp) {
107
110
  function resolvePasskeyDispatch(params) {
108
111
  const flow = params.flow;
109
112
  if (typeof flow === "string" && PASSKEY_FLOWS.includes(flow)) return { flow };
110
- throw convexError("PASSKEY_MISSING_FLOW", "Missing `flow` parameter. Expected one of: registerOptions, registerVerify, authOptions, authVerify");
113
+ throw convexError("PASSKEY_MISSING_FLOW", "Missing `flow` parameter. Expected one of: " + PASSKEY_FLOWS.join(", "));
111
114
  }
112
115
  function requirePasskeyVerifier(verifier) {
113
116
  if (verifier != null) return verifier;
@@ -163,8 +166,112 @@ function verifyAssertionSignature(passkey, signature, messageHash) {
163
166
  async function handlePasskeyFx(ctx, provider, args) {
164
167
  const params = args.params ?? {};
165
168
  const dispatch = resolvePasskeyDispatch(params);
169
+ const handleRegisterVerify = async () => {
170
+ const userId = await requireAuthenticatedUserId(ctx);
171
+ const rp = resolveRpOptions(provider);
172
+ const verifier = requirePasskeyVerifier(args.verifier);
173
+ const clientData = parseClientDataJSON(decodeBase64urlIgnorePadding(requireStringParam(params.clientDataJSON, "clientDataJSON")));
174
+ verifyClientDataType(clientData, ClientDataType.Create, "webauthn.create");
175
+ verifyOrigin(clientData, rp);
176
+ await verifyAndConsumeChallenge(clientData, ctx, verifier);
177
+ const authData = parseAttestationObject(decodeBase64urlIgnorePadding(requireStringParam(params.attestationObject, "attestationObject"))).authenticatorData;
178
+ verifyRpId(authData, rp.rpId);
179
+ verifyUserFlags(authData, rp);
180
+ if (authData.credential == null) throw convexError("PASSKEY_NO_CREDENTIAL", "No credential in attestation.");
181
+ const credential = authData.credential;
182
+ const credentialId = encodeBase64urlNoPadding(credential.id);
183
+ const publicKey = credential.publicKey;
184
+ const algorithm = publicKey.isAlgorithmDefined() ? publicKey.algorithm() : publicKey.type() === COSEKeyType.EC2 ? coseAlgorithmES256 : publicKey.type() === COSEKeyType.RSA ? coseAlgorithmRS256 : coseAlgorithmES256;
185
+ const publicKeyBytes = resolveRegistrationPublicKeyBytes(publicKey, algorithm);
186
+ try {
187
+ const deviceType = params.deviceType ?? "single-device";
188
+ const backedUp = params.backedUp ?? false;
189
+ await authDb(ctx, ctx.auth.config).accounts.create({
190
+ userId,
191
+ provider: provider.id,
192
+ providerAccountId: credentialId
193
+ });
194
+ const passkeyId = await mutatePasskeyInsert(ctx, {
195
+ userId,
196
+ credentialId,
197
+ publicKey: publicKeyBytes.buffer.slice(publicKeyBytes.byteOffset, publicKeyBytes.byteOffset + publicKeyBytes.byteLength),
198
+ algorithm,
199
+ counter: authData.signatureCounter,
200
+ transports: params.transports,
201
+ deviceType,
202
+ backedUp,
203
+ name: params.passkeyName,
204
+ createdAt: Date.now()
205
+ });
206
+ await ctx.auth.config.callbacks?.after?.(ctx, {
207
+ kind: "passkeyAdded",
208
+ userId,
209
+ passkeyId,
210
+ credentialId
211
+ });
212
+ } catch {
213
+ throw convexError("INTERNAL_ERROR", "An unexpected error occurred.");
214
+ }
215
+ let signInResult;
216
+ try {
217
+ signInResult = await callSignIn(ctx, {
218
+ userId,
219
+ generateTokens: true
220
+ });
221
+ } catch (error) {
222
+ throw asConvexError(error, "INTERNAL_ERROR", "Failed to finalize passkey registration.");
223
+ }
224
+ return {
225
+ kind: "signedIn",
226
+ session: signInResult
227
+ };
228
+ };
229
+ const handleAuthVerify = async () => {
230
+ const rp = resolveRpOptions(provider);
231
+ const verifier = requirePasskeyVerifier(args.verifier);
232
+ const clientDataJSON = decodeBase64urlIgnorePadding(requireStringParam(params.clientDataJSON, "clientDataJSON"));
233
+ const clientData = parseClientDataJSON(clientDataJSON);
234
+ verifyClientDataType(clientData, ClientDataType.Get, "webauthn.get");
235
+ verifyOrigin(clientData, rp);
236
+ await verifyAndConsumeChallenge(clientData, ctx, verifier);
237
+ const credentialId = params.credentialId;
238
+ if (credentialId == null) throw convexError("PASSKEY_UNKNOWN_CREDENTIAL", "Missing credential ID");
239
+ let passkey;
240
+ try {
241
+ passkey = await queryPasskeyByCredentialId(ctx, credentialId);
242
+ } catch {
243
+ throw convexError("PASSKEY_UNKNOWN_CREDENTIAL", "Unknown passkey credential.");
244
+ }
245
+ if (passkey === null) throw convexError("PASSKEY_UNKNOWN_CREDENTIAL", "Unknown credential");
246
+ const authenticatorDataBytes = decodeBase64urlIgnorePadding(requireStringParam(params.authenticatorData, "authenticatorData"));
247
+ const authenticatorData = parseAuthenticatorData(authenticatorDataBytes);
248
+ const signatureBytes = decodeBase64urlIgnorePadding(requireStringParam(params.signature, "signature"));
249
+ const messageHash = sha256(createAssertionSignatureMessage(authenticatorDataBytes, clientDataJSON));
250
+ verifyRpId(authenticatorData, rp.rpId);
251
+ verifyUserFlags(authenticatorData, rp);
252
+ verifyAssertionSignature(passkey, signatureBytes, messageHash);
253
+ if (passkey.counter !== 0 && authenticatorData.signatureCounter !== 0 && authenticatorData.signatureCounter <= passkey.counter) throw convexError("PASSKEY_COUNTER_ERROR", "Authenticator counter did not increase — possible credential cloning detected.");
254
+ try {
255
+ await mutatePasskeyUpdateCounter(ctx, passkey._id, authenticatorData.signatureCounter, Date.now());
256
+ } catch (error) {
257
+ throw asConvexError(error, "INTERNAL_ERROR", "Failed to update passkey counter.");
258
+ }
259
+ let signInResult;
260
+ try {
261
+ signInResult = await callSignIn(ctx, {
262
+ userId: passkey.userId,
263
+ generateTokens: true
264
+ });
265
+ } catch (error) {
266
+ throw asConvexError(error, "INTERNAL_ERROR", "Failed to finalize passkey sign-in.");
267
+ }
268
+ return {
269
+ kind: "signedIn",
270
+ session: signInResult
271
+ };
272
+ };
166
273
  const handler = {
167
- registerOptions: async () => {
274
+ register: async () => {
168
275
  const userId = await requireAuthenticatedUserId(ctx);
169
276
  const rp = resolveRpOptions(provider);
170
277
  const challenge = new Uint8Array(32);
@@ -225,61 +332,7 @@ async function handlePasskeyFx(ctx, provider, args) {
225
332
  verifier
226
333
  };
227
334
  },
228
- registerVerify: async () => {
229
- const userId = await requireAuthenticatedUserId(ctx);
230
- const rp = resolveRpOptions(provider);
231
- const verifier = requirePasskeyVerifier(args.verifier);
232
- const clientData = parseClientDataJSON(decodeBase64urlIgnorePadding(requireStringParam(params.clientDataJSON, "clientDataJSON")));
233
- verifyClientDataType(clientData, ClientDataType.Create, "webauthn.create");
234
- verifyOrigin(clientData, rp);
235
- await verifyAndConsumeChallenge(clientData, ctx, verifier);
236
- const authData = parseAttestationObject(decodeBase64urlIgnorePadding(requireStringParam(params.attestationObject, "attestationObject"))).authenticatorData;
237
- verifyRpId(authData, rp.rpId);
238
- verifyUserFlags(authData, rp);
239
- if (authData.credential == null) throw convexError("PASSKEY_NO_CREDENTIAL", "No credential in attestation.");
240
- const credential = authData.credential;
241
- const credentialId = encodeBase64urlNoPadding(credential.id);
242
- const publicKey = credential.publicKey;
243
- const algorithm = publicKey.isAlgorithmDefined() ? publicKey.algorithm() : publicKey.type() === COSEKeyType.EC2 ? coseAlgorithmES256 : publicKey.type() === COSEKeyType.RSA ? coseAlgorithmRS256 : coseAlgorithmES256;
244
- const publicKeyBytes = resolveRegistrationPublicKeyBytes(publicKey, algorithm);
245
- try {
246
- const deviceType = params.deviceType ?? "single-device";
247
- const backedUp = params.backedUp ?? false;
248
- await authDb(ctx, ctx.auth.config).accounts.create({
249
- userId,
250
- provider: provider.id,
251
- providerAccountId: credentialId
252
- });
253
- await mutatePasskeyInsert(ctx, {
254
- userId,
255
- credentialId,
256
- publicKey: publicKeyBytes.buffer.slice(publicKeyBytes.byteOffset, publicKeyBytes.byteOffset + publicKeyBytes.byteLength),
257
- algorithm,
258
- counter: authData.signatureCounter,
259
- transports: params.transports,
260
- deviceType,
261
- backedUp,
262
- name: params.passkeyName,
263
- createdAt: Date.now()
264
- });
265
- } catch {
266
- throw convexError("INTERNAL_ERROR", "An unexpected error occurred.");
267
- }
268
- let signInResult;
269
- try {
270
- signInResult = await callSignIn(ctx, {
271
- userId,
272
- generateTokens: true
273
- });
274
- } catch (error) {
275
- throw asConvexError(error, "INTERNAL_ERROR", "Failed to finalize passkey registration.");
276
- }
277
- return {
278
- kind: "signedIn",
279
- session: signInResult
280
- };
281
- },
282
- authOptions: async () => {
335
+ signIn: async () => {
283
336
  const rp = resolveRpOptions(provider);
284
337
  const challenge = new Uint8Array(32);
285
338
  crypto.getRandomValues(challenge);
@@ -326,49 +379,12 @@ async function handlePasskeyFx(ctx, provider, args) {
326
379
  verifier
327
380
  };
328
381
  },
329
- authVerify: async () => {
330
- const rp = resolveRpOptions(provider);
331
- const verifier = requirePasskeyVerifier(args.verifier);
332
- const clientDataJSON = decodeBase64urlIgnorePadding(requireStringParam(params.clientDataJSON, "clientDataJSON"));
333
- const clientData = parseClientDataJSON(clientDataJSON);
334
- verifyClientDataType(clientData, ClientDataType.Get, "webauthn.get");
335
- verifyOrigin(clientData, rp);
336
- await verifyAndConsumeChallenge(clientData, ctx, verifier);
337
- const credentialId = params.credentialId;
338
- if (credentialId == null) throw convexError("PASSKEY_UNKNOWN_CREDENTIAL", "Missing credential ID");
339
- let passkey;
340
- try {
341
- passkey = await queryPasskeyByCredentialId(ctx, credentialId);
342
- } catch {
343
- throw convexError("PASSKEY_UNKNOWN_CREDENTIAL", "Unknown passkey credential.");
344
- }
345
- if (passkey === null) throw convexError("PASSKEY_UNKNOWN_CREDENTIAL", "Unknown credential");
346
- const authenticatorDataBytes = decodeBase64urlIgnorePadding(requireStringParam(params.authenticatorData, "authenticatorData"));
347
- const authenticatorData = parseAuthenticatorData(authenticatorDataBytes);
348
- const signatureBytes = decodeBase64urlIgnorePadding(requireStringParam(params.signature, "signature"));
349
- const messageHash = sha256(createAssertionSignatureMessage(authenticatorDataBytes, clientDataJSON));
350
- verifyRpId(authenticatorData, rp.rpId);
351
- verifyUserFlags(authenticatorData, rp);
352
- verifyAssertionSignature(passkey, signatureBytes, messageHash);
353
- if (passkey.counter !== 0 && authenticatorData.signatureCounter !== 0 && authenticatorData.signatureCounter <= passkey.counter) throw convexError("PASSKEY_COUNTER_ERROR", "Authenticator counter did not increase — possible credential cloning detected.");
354
- try {
355
- await mutatePasskeyUpdateCounter(ctx, passkey._id, authenticatorData.signatureCounter, Date.now());
356
- } catch (error) {
357
- throw asConvexError(error, "INTERNAL_ERROR", "Failed to update passkey counter.");
358
- }
359
- let signInResult;
360
- try {
361
- signInResult = await callSignIn(ctx, {
362
- userId: passkey.userId,
363
- generateTokens: true
364
- });
365
- } catch (error) {
366
- throw asConvexError(error, "INTERNAL_ERROR", "Failed to finalize passkey sign-in.");
367
- }
368
- return {
369
- kind: "signedIn",
370
- session: signInResult
371
- };
382
+ verify: async () => {
383
+ const isRegistration = typeof params.attestationObject === "string" && params.attestationObject.length > 0;
384
+ const isAuthentication = typeof params.signature === "string" && params.signature.length > 0;
385
+ if (isRegistration && !isAuthentication) return await handleRegisterVerify();
386
+ if (isAuthentication && !isRegistration) return await handleAuthVerify();
387
+ throw convexError("PASSKEY_INVALID_VERIFY", "`verify` flow requires either `attestationObject` (to complete a `register`) or `signature` + `credentialId` (to complete a `signIn`).");
372
388
  }
373
389
  }[dispatch.flow];
374
390
  if (!handler) throw convexError("PASSKEY_MISSING_FLOW", `Unknown passkey flow: ${dispatch.flow}`);
@@ -239,10 +239,17 @@ function convexSiteIssuerFromCloudUrl(value) {
239
239
  parsed.hostname = parsed.hostname.slice(0, -13) + ".convex.site";
240
240
  return normalizeIssuer(parsed.toString());
241
241
  }
242
+ function appendAuthIssuerPrefix(value) {
243
+ const issuer = normalizeIssuer(value);
244
+ return issuer.endsWith("/auth") ? issuer : `${issuer}/auth`;
245
+ }
242
246
  function defaultAcceptedIssuersForUrl(value) {
243
247
  const issuers = [normalizeIssuer(value)];
244
248
  const siteIssuer = convexSiteIssuerFromCloudUrl(value);
245
- if (siteIssuer !== null) issuers.push(siteIssuer);
249
+ if (siteIssuer !== null) {
250
+ issuers.push(siteIssuer);
251
+ issuers.push(appendAuthIssuerPrefix(siteIssuer));
252
+ }
246
253
  return issuers;
247
254
  }
248
255
  /**
@@ -8,15 +8,23 @@ const describeUnknown = (value) => {
8
8
  return JSON.stringify(value) ?? Object.prototype.toString.call(value);
9
9
  };
10
10
  /** @internal */
11
- async function redirectAbsoluteUrl(config, params) {
11
+ async function redirectAbsoluteUrl(ctx, config, params) {
12
12
  if (params.redirectTo === void 0) return requireEnv("SITE_URL").replace(/\/$/, "");
13
13
  if (typeof params.redirectTo !== "string") throw new ConvexError({
14
14
  code: "INVALID_REDIRECT",
15
15
  message: `Expected \`redirectTo\` to be a string, got ${describeUnknown(params.redirectTo)}`
16
16
  });
17
- const redirectCallback = config.callbacks?.redirect ?? defaultRedirectCallback;
17
+ const redirectTo = params.redirectTo;
18
18
  try {
19
- return await redirectCallback({ redirectTo: params.redirectTo });
19
+ const before = config.callbacks?.before;
20
+ if (before !== void 0) {
21
+ const result = await before(ctx, {
22
+ kind: "redirect",
23
+ redirectTo
24
+ });
25
+ if (typeof result === "string") return result;
26
+ }
27
+ return await defaultRedirectCallback({ redirectTo });
20
28
  } catch {
21
29
  throw new ConvexError({
22
30
  code: "INTERNAL_ERROR",
@@ -10,8 +10,13 @@ const REFRESH_TOKEN_REUSE_WINDOW_MS = 10 * 1e3;
10
10
  const refreshTokenExpirationTime = (config, now = Date.now()) => now + (config.session?.inactiveDurationMs ?? readConfigSync(envOptionalNumber("AUTH_SESSION_INACTIVE_DURATION_MS")) ?? DEFAULT_SESSION_INACTIVE_DURATION_MS);
11
11
  /** @internal */
12
12
  const parseRefreshToken = (refreshToken) => {
13
- const [refreshTokenId, sessionId] = refreshToken.split(REFRESH_TOKEN_DIVIDER);
13
+ const parts = refreshToken.split(REFRESH_TOKEN_DIVIDER);
14
14
  const message = `Can't parse refresh token: ${maybeRedact(refreshToken)}`;
15
+ if (parts.length !== 2) throw new ConvexError({
16
+ code: "INVALID_REFRESH_TOKEN",
17
+ message
18
+ });
19
+ const [refreshTokenId, sessionId] = parts;
15
20
  if (refreshTokenId == null || sessionId == null) throw new ConvexError({
16
21
  code: "INVALID_REFRESH_TOKEN",
17
22
  message
@@ -1,13 +1,16 @@
1
1
  import { AuthProviderConfig, ConvexAuthConfig, CorsConfig, Doc, HttpKeyContext, KeyDoc, KeyScope, ScopeChecker, UserOrderBy, UserWhere } from "./types.js";
2
- import { ComponentCtx, ComponentReadCtx } from "./componentContext.js";
2
+ import { ComponentCtx, ComponentReadCtx } from "./component/context.js";
3
3
  import { AuthProfile, SignInParams } from "./payloads.js";
4
4
  import { HttpAuthContext, HttpAuthContextConfig, OptionalHttpAuthContext } from "./http.js";
5
5
  import { createGroupConnectionDomain } from "./sso/domain.js";
6
- import * as convex_values86 from "convex/values";
7
- import * as convex_server80 from "convex/server";
6
+ import { GenericId } from "convex/values";
7
+ import * as convex_server105 from "convex/server";
8
8
  import { GenericActionCtx, GenericDataModel, HttpRouter } from "convex/server";
9
9
 
10
10
  //#region src/server/runtime.d.ts
11
+ type AuthHttpRouteOptions = {
12
+ /** Prefix where auth HTTP routes are mounted, e.g. `/auth`. */prefix?: string;
13
+ };
11
14
  /**
12
15
  * Configure the Convex Auth library. Returns an object with
13
16
  * functions and `auth` helper. You must export the functions
@@ -20,16 +23,16 @@ import { GenericActionCtx, GenericDataModel, HttpRouter } from "convex/server";
20
23
  * export const auth = createAuth(components.auth, {
21
24
  * providers: [],
22
25
  * });
23
- * export const { signIn, signOut, store } = auth;
26
+ * export const signIn = auth.signIn;
27
+ * export const signOut = auth.signOut;
28
+ * export const store = auth.store;
29
+ * export const http = auth.http;
24
30
  * ```
25
31
  *
26
32
  * @returns An object with fields you should reexport from your
27
33
  * `convex/auth.ts` file.
28
34
  */
29
35
  declare function Auth(config_: ConvexAuthConfig): {
30
- /**
31
- * Helper for configuring HTTP actions.
32
- */
33
36
  auth: {
34
37
  user: {
35
38
  get: {
@@ -44,7 +47,7 @@ declare function Auth(config_: ConvexAuthConfig): {
44
47
  order?: "asc" | "desc";
45
48
  }) => Promise<any>;
46
49
  viewer: (ctx: ComponentReadCtx & {
47
- auth: convex_server80.Auth;
50
+ auth: convex_server105.Auth;
48
51
  }) => Promise<Doc<"User"> | null>;
49
52
  update: (ctx: ComponentCtx, userId: string, data: Record<string, unknown>) => Promise<{
50
53
  userId: string;
@@ -70,11 +73,11 @@ declare function Auth(config_: ConvexAuthConfig): {
70
73
  };
71
74
  session: {
72
75
  invalidate: <DataModel extends GenericDataModel>(ctx: GenericActionCtx<DataModel>, args: {
73
- userId: convex_values86.GenericId<"User">;
74
- except?: convex_values86.GenericId<"Session">[];
76
+ userId: GenericId<"User">;
77
+ except?: GenericId<"Session">[];
75
78
  }) => Promise<{
76
- userId: convex_values86.GenericId<"User">;
77
- except: convex_values86.GenericId<"Session">[];
79
+ userId: GenericId<"User">;
80
+ except: GenericId<"Session">[];
78
81
  }>;
79
82
  get: (ctx: ComponentReadCtx, sessionId: string) => Promise<any>;
80
83
  list: (ctx: ComponentReadCtx, opts: {
@@ -143,7 +146,7 @@ declare function Auth(config_: ConvexAuthConfig): {
143
146
  };
144
147
  provider: {
145
148
  signIn: (<DataModel extends GenericDataModel>(ctx: GenericActionCtx<DataModel>, providerConfig: AuthProviderConfig, args: {
146
- accountId?: convex_values86.GenericId<"Account">;
149
+ accountId?: GenericId<"Account">;
147
150
  params?: SignInParams;
148
151
  }) => Promise<{
149
152
  userId: string;
@@ -397,7 +400,7 @@ declare function Auth(config_: ConvexAuthConfig): {
397
400
  } & {
398
401
  sso: ReturnType<typeof createGroupConnectionDomain>;
399
402
  } & {
400
- http: {
403
+ request: {
401
404
  /**
402
405
  * Register core HTTP routes for JWT verification and OAuth sign-in.
403
406
  *
@@ -405,26 +408,39 @@ declare function Auth(config_: ConvexAuthConfig): {
405
408
  * import { httpRouter } from "convex/server";
406
409
  * import { auth } from "./auth";
407
410
  *
408
- * const http = httpRouter();
409
- *
410
- * auth.http.add(http);
411
- *
412
- * export default http;
411
+ * export default auth.http();
413
412
  * ```
414
413
  *
415
414
  * The following routes are handled always:
416
415
  *
417
416
  * - `/.well-known/openid-configuration`
418
417
  * - `/.well-known/jwks.json`
418
+ * - `/.well-known/webauthn` (returns 404 unless `WEBAUTHN_ALT_ORIGINS` or
419
+ * `SECONDARY_URL` is set)
419
420
  *
420
421
  * The following routes are handled if OAuth is configured:
421
422
  *
422
- * - `/api/auth/signin/*`
423
- * - `/api/auth/callback/*`
423
+ * - `/signin/*`
424
+ * - `/callback/*`
424
425
  *
425
426
  * @param http your HTTP router
427
+ * @param options.prefix where to mount auth protocol routes, e.g. `/auth`
426
428
  */
427
- add: (http: HttpRouter) => void;
429
+ add: (http: HttpRouter, options?: AuthHttpRouteOptions) => void;
430
+ /**
431
+ * Create a Convex HTTP router with auth protocol routes already mounted.
432
+ *
433
+ * Defaults to the `/auth` prefix. Use {@link request.add add} instead when
434
+ * you need to compose auth routes with app-specific HTTP routes in the same
435
+ * router.
436
+ *
437
+ * ```ts
438
+ * import { auth } from "./auth";
439
+ *
440
+ * export default auth.http();
441
+ * ```
442
+ */
443
+ router: (options?: AuthHttpRouteOptions) => HttpRouter;
428
444
  /**
429
445
  * Resolve mixed HTTP auth for a raw `httpAction`.
430
446
  *
@@ -439,7 +455,7 @@ declare function Auth(config_: ConvexAuthConfig): {
439
455
  * path: "/api/data",
440
456
  * method: "GET",
441
457
  * handler: httpAction(async (ctx, request) => {
442
- * const authContext = await auth.http.context(ctx, request);
458
+ * const authContext = await auth.request.context(ctx, request);
443
459
  * return Response.json({
444
460
  * userId: authContext.userId,
445
461
  * source: authContext.source,
@@ -451,22 +467,22 @@ declare function Auth(config_: ConvexAuthConfig): {
451
467
  context: {
452
468
  <TResolve extends Record<string, unknown> = Record<string, never>, TCtx extends {
453
469
  auth: {
454
- getUserIdentity: () => Promise<convex_server80.UserIdentity | null>;
470
+ getUserIdentity: () => Promise<convex_server105.UserIdentity | null>;
455
471
  };
456
472
  } & ComponentReadCtx = {
457
473
  auth: {
458
- getUserIdentity: () => Promise<convex_server80.UserIdentity | null>;
474
+ getUserIdentity: () => Promise<convex_server105.UserIdentity | null>;
459
475
  };
460
476
  } & ComponentReadCtx>(ctx: TCtx, request: Request, config: HttpAuthContextConfig<TResolve, TCtx> & {
461
477
  optional: true;
462
478
  }): Promise<OptionalHttpAuthContext & TResolve>;
463
479
  <TResolve extends Record<string, unknown> = Record<string, never>, TCtx extends {
464
480
  auth: {
465
- getUserIdentity: () => Promise<convex_server80.UserIdentity | null>;
481
+ getUserIdentity: () => Promise<convex_server105.UserIdentity | null>;
466
482
  };
467
483
  } & ComponentReadCtx = {
468
484
  auth: {
469
- getUserIdentity: () => Promise<convex_server80.UserIdentity | null>;
485
+ getUserIdentity: () => Promise<convex_server105.UserIdentity | null>;
470
486
  };
471
487
  } & ComponentReadCtx>(ctx: TCtx, request: Request, config?: HttpAuthContextConfig<TResolve, TCtx>): Promise<HttpAuthContext & TResolve>;
472
488
  };
@@ -483,7 +499,7 @@ declare function Auth(config_: ConvexAuthConfig): {
483
499
  * are merged and the response is passed through.
484
500
  *
485
501
  * ```ts
486
- * const handler = auth.http.action(async (ctx, request) => {
502
+ * const handler = auth.request.action(async (ctx, request) => {
487
503
  * const data = await ctx.runQuery(api.data.get, { userId: ctx.key.userId });
488
504
  * return { data };
489
505
  * });
@@ -500,13 +516,13 @@ declare function Auth(config_: ConvexAuthConfig): {
500
516
  action: string;
501
517
  };
502
518
  cors?: CorsConfig;
503
- }) => convex_server80.PublicHttpAction;
519
+ }) => convex_server105.PublicHttpAction;
504
520
  /**
505
521
  * Register a Bearer-authenticated route **and** its OPTIONS preflight
506
522
  * in a single call.
507
523
  *
508
524
  * ```ts
509
- * auth.http.route(http, {
525
+ * auth.request.route(http, {
510
526
  * path: "/api/messages",
511
527
  * method: "POST",
512
528
  * handler: async (ctx, request) => {
@@ -546,7 +562,7 @@ declare function Auth(config_: ConvexAuthConfig): {
546
562
  *
547
563
  * Also used for refreshing the session.
548
564
  */
549
- signIn: convex_server80.RegisteredAction<"public", {
565
+ signIn: convex_server105.RegisteredAction<"public", {
550
566
  provider?: string | undefined;
551
567
  verifier?: string | undefined;
552
568
  params?: Record<string, string | number | boolean | (string | number | boolean | null)[] | Record<string, string | number | boolean | (string | number | boolean | null)[] | null> | null> | undefined;
@@ -556,12 +572,12 @@ declare function Auth(config_: ConvexAuthConfig): {
556
572
  /**
557
573
  * Action called by the client to invalidate the current session.
558
574
  */
559
- signOut: convex_server80.RegisteredAction<"public", {}, Promise<void>>;
575
+ signOut: convex_server105.RegisteredAction<"public", {}, Promise<void>>;
560
576
  /**
561
577
  * Internal mutation used by the library to read and write
562
578
  * to the database during signin and signout.
563
579
  */
564
- store: convex_server80.RegisteredMutation<"internal", {
580
+ store: convex_server105.RegisteredMutation<"internal", {
565
581
  args: {
566
582
  sessionId?: string | undefined;
567
583
  type: "signIn";
@@ -604,11 +620,11 @@ declare function Auth(config_: ConvexAuthConfig): {
604
620
  sessionIndex?: string | undefined;
605
621
  } | undefined;
606
622
  } | undefined;
607
- profile: Record<string, string | number | boolean | (string | number | boolean | null)[] | Record<string, string | number | boolean | (string | number | boolean | null)[] | null> | null>;
608
623
  type: "userOAuth";
609
624
  provider: string;
610
625
  providerAccountId: string;
611
626
  signature: string;
627
+ profile: Record<string, string | number | boolean | (string | number | boolean | null)[] | Record<string, string | number | boolean | (string | number | boolean | null)[] | null> | null>;
612
628
  } | {
613
629
  email?: string | undefined;
614
630
  phone?: string | undefined;
@@ -621,9 +637,9 @@ declare function Auth(config_: ConvexAuthConfig): {
621
637
  } | {
622
638
  shouldLinkViaEmail?: boolean | undefined;
623
639
  shouldLinkViaPhone?: boolean | undefined;
624
- profile: Record<string, string | number | boolean | (string | number | boolean | null)[] | Record<string, string | number | boolean | (string | number | boolean | null)[] | null> | null>;
625
640
  type: "createAccountFromCredentials";
626
641
  provider: string;
642
+ profile: Record<string, string | number | boolean | (string | number | boolean | null)[] | Record<string, string | number | boolean | (string | number | boolean | null)[] | null> | null>;
627
643
  account: {
628
644
  secret?: string | undefined;
629
645
  id: string;
@@ -657,7 +673,13 @@ declare function Auth(config_: ConvexAuthConfig): {
657
673
  type: "invalidateSessions";
658
674
  userId: string;
659
675
  };
660
- }, Promise<unknown>>;
676
+ }, Promise<unknown>>; /** App-side HTTP protocol delegate retained for generated API compatibility. */
677
+ http: ((options?: AuthHttpRouteOptions) => HttpRouter) & {
678
+ isConvexFunction: true;
679
+ isAction: true;
680
+ } & {
681
+ isPublic: true;
682
+ };
661
683
  };
662
684
  //#endregion
663
685
  export { Auth };