cauthy-auth 0.17.0 → 0.19.0

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.
package/dist/react.d.mts CHANGED
@@ -266,11 +266,19 @@ interface AuthMethods {
266
266
  */
267
267
  captchaSiteKey?: string;
268
268
  }
269
+ /**
270
+ * What holds a passkey, as its authenticator says: a security key (a YubiKey),
271
+ * one synced across the person's devices (iCloud Keychain, Google Password
272
+ * Manager), one on a single device (Windows Hello), or unknown (made before
273
+ * Cauthy kept this).
274
+ */
275
+ type PasskeyKind = 'security_key' | 'synced' | 'device' | 'unknown';
269
276
  /** A passkey of the signed-in account. Moments are UTC. */
270
277
  interface Passkey {
271
278
  id: string;
272
279
  /** What the person called it ("My laptop"), or "". */
273
280
  name: string;
281
+ kind: PasskeyKind;
274
282
  createdAt: string;
275
283
  /** When it last signed the person in, or null. */
276
284
  lastUsedAt: string | null;
@@ -444,10 +452,14 @@ interface AccountClient {
444
452
  * Makes a passkey on this device, on this page: the browser asks the person
445
453
  * for their fingerprint, face or screen lock. An account with a password
446
454
  * proves it again first. `cancelled`: the person closed the browser's prompt.
455
+ * `kind` sends the browser straight to one: `'device'`, this device's
456
+ * fingerprint, face or screen lock; `'security_key'`, a security key.
457
+ * Without it, the browser offers all.
447
458
  */
448
459
  addPasskey(form?: {
449
460
  password?: string;
450
461
  name?: string;
462
+ kind?: 'device' | 'security_key';
451
463
  }): Promise<AuthResult<'added', {
452
464
  passkey: Passkey;
453
465
  }>>;
@@ -517,11 +529,14 @@ interface AuthClient {
517
529
  * workspace's passkeys (`methods().passkeyHere` is false), the browser goes
518
530
  * to Cauthy's page for that step alone and comes back signed in, at
519
531
  * `returnTo`: then the answer is `redirected`. `cancelled`: the person
520
- * closed the browser's prompt.
532
+ * closed the browser's prompt. `email`, when the person typed it: the
533
+ * browser is told which passkeys are theirs, so a security key that did
534
+ * not keep its passkey (one made before cauthy-auth 0.18.0) is found too.
521
535
  */
522
536
  passkey(options?: {
523
537
  returnTo?: string;
524
538
  locale?: string;
539
+ email?: string;
525
540
  }): Promise<AuthResult<'signed_in', {
526
541
  session: PublicSession;
527
542
  }> | AuthResult<'redirected'>>;
@@ -684,7 +699,11 @@ interface AuthTexts {
684
699
  passkeysHelp: string;
685
700
  noPasskeys: string;
686
701
  passkeyName: string;
702
+ /** @deprecated Unused since 0.19.0: the account screen offers `addPasskeyDevice` and `addSecurityKey`. */
687
703
  addPasskey: string;
704
+ addPasskeyDevice: string;
705
+ addSecurityKey: string;
706
+ passkeyKinds: Record<'security_key' | 'synced' | 'device', string>;
688
707
  removePasskey: string;
689
708
  passkeyAdded: string;
690
709
  passkeyUnnamed: string;
@@ -853,4 +872,4 @@ declare function useSession(): SessionContext;
853
872
  */
854
873
  declare function useAuth(): AuthClient & Pick<SessionContext, 'session' | 'status' | 'refresh'>;
855
874
 
856
- export { Account, type AccountClient, type Account$1 as AccountDetails, type AccountProps, type AccountSession, type AuthClient, type AuthError, type AuthFormProps, type AuthMethods, type AuthResult, type AuthTexts, CauthyProvider, type CauthyProviderProps, type ConnectedAgent, ForgotPassword, GoogleOneTap, type GoogleOneTapProps, type JsonValue, type LinkedIdentity, type Passkey, type PermissionOf, type Policy, type PublicSession, ResetPassword, type RoleOf, type SecondStep, type SessionContext, type SessionOrganization, type SessionUser, SignIn, SignUp, VerifyEmail, can, canAutofillPasskeys, canUsePasskeys, createAuthClient, definePolicy, useAuth, useSession };
875
+ export { Account, type AccountClient, type Account$1 as AccountDetails, type AccountProps, type AccountSession, type AuthClient, type AuthError, type AuthFormProps, type AuthMethods, type AuthResult, type AuthTexts, CauthyProvider, type CauthyProviderProps, type ConnectedAgent, ForgotPassword, GoogleOneTap, type GoogleOneTapProps, type JsonValue, type LinkedIdentity, type Passkey, type PasskeyKind, type PermissionOf, type Policy, type PublicSession, ResetPassword, type RoleOf, type SecondStep, type SessionContext, type SessionOrganization, type SessionUser, SignIn, SignUp, VerifyEmail, can, canAutofillPasskeys, canUsePasskeys, createAuthClient, definePolicy, useAuth, useSession };
package/dist/react.d.ts CHANGED
@@ -266,11 +266,19 @@ interface AuthMethods {
266
266
  */
267
267
  captchaSiteKey?: string;
268
268
  }
269
+ /**
270
+ * What holds a passkey, as its authenticator says: a security key (a YubiKey),
271
+ * one synced across the person's devices (iCloud Keychain, Google Password
272
+ * Manager), one on a single device (Windows Hello), or unknown (made before
273
+ * Cauthy kept this).
274
+ */
275
+ type PasskeyKind = 'security_key' | 'synced' | 'device' | 'unknown';
269
276
  /** A passkey of the signed-in account. Moments are UTC. */
270
277
  interface Passkey {
271
278
  id: string;
272
279
  /** What the person called it ("My laptop"), or "". */
273
280
  name: string;
281
+ kind: PasskeyKind;
274
282
  createdAt: string;
275
283
  /** When it last signed the person in, or null. */
276
284
  lastUsedAt: string | null;
@@ -444,10 +452,14 @@ interface AccountClient {
444
452
  * Makes a passkey on this device, on this page: the browser asks the person
445
453
  * for their fingerprint, face or screen lock. An account with a password
446
454
  * proves it again first. `cancelled`: the person closed the browser's prompt.
455
+ * `kind` sends the browser straight to one: `'device'`, this device's
456
+ * fingerprint, face or screen lock; `'security_key'`, a security key.
457
+ * Without it, the browser offers all.
447
458
  */
448
459
  addPasskey(form?: {
449
460
  password?: string;
450
461
  name?: string;
462
+ kind?: 'device' | 'security_key';
451
463
  }): Promise<AuthResult<'added', {
452
464
  passkey: Passkey;
453
465
  }>>;
@@ -517,11 +529,14 @@ interface AuthClient {
517
529
  * workspace's passkeys (`methods().passkeyHere` is false), the browser goes
518
530
  * to Cauthy's page for that step alone and comes back signed in, at
519
531
  * `returnTo`: then the answer is `redirected`. `cancelled`: the person
520
- * closed the browser's prompt.
532
+ * closed the browser's prompt. `email`, when the person typed it: the
533
+ * browser is told which passkeys are theirs, so a security key that did
534
+ * not keep its passkey (one made before cauthy-auth 0.18.0) is found too.
521
535
  */
522
536
  passkey(options?: {
523
537
  returnTo?: string;
524
538
  locale?: string;
539
+ email?: string;
525
540
  }): Promise<AuthResult<'signed_in', {
526
541
  session: PublicSession;
527
542
  }> | AuthResult<'redirected'>>;
@@ -684,7 +699,11 @@ interface AuthTexts {
684
699
  passkeysHelp: string;
685
700
  noPasskeys: string;
686
701
  passkeyName: string;
702
+ /** @deprecated Unused since 0.19.0: the account screen offers `addPasskeyDevice` and `addSecurityKey`. */
687
703
  addPasskey: string;
704
+ addPasskeyDevice: string;
705
+ addSecurityKey: string;
706
+ passkeyKinds: Record<'security_key' | 'synced' | 'device', string>;
688
707
  removePasskey: string;
689
708
  passkeyAdded: string;
690
709
  passkeyUnnamed: string;
@@ -853,4 +872,4 @@ declare function useSession(): SessionContext;
853
872
  */
854
873
  declare function useAuth(): AuthClient & Pick<SessionContext, 'session' | 'status' | 'refresh'>;
855
874
 
856
- export { Account, type AccountClient, type Account$1 as AccountDetails, type AccountProps, type AccountSession, type AuthClient, type AuthError, type AuthFormProps, type AuthMethods, type AuthResult, type AuthTexts, CauthyProvider, type CauthyProviderProps, type ConnectedAgent, ForgotPassword, GoogleOneTap, type GoogleOneTapProps, type JsonValue, type LinkedIdentity, type Passkey, type PermissionOf, type Policy, type PublicSession, ResetPassword, type RoleOf, type SecondStep, type SessionContext, type SessionOrganization, type SessionUser, SignIn, SignUp, VerifyEmail, can, canAutofillPasskeys, canUsePasskeys, createAuthClient, definePolicy, useAuth, useSession };
875
+ export { Account, type AccountClient, type Account$1 as AccountDetails, type AccountProps, type AccountSession, type AuthClient, type AuthError, type AuthFormProps, type AuthMethods, type AuthResult, type AuthTexts, CauthyProvider, type CauthyProviderProps, type ConnectedAgent, ForgotPassword, GoogleOneTap, type GoogleOneTapProps, type JsonValue, type LinkedIdentity, type Passkey, type PasskeyKind, type PermissionOf, type Policy, type PublicSession, ResetPassword, type RoleOf, type SecondStep, type SessionContext, type SessionOrganization, type SessionUser, SignIn, SignUp, VerifyEmail, can, canAutofillPasskeys, canUsePasskeys, createAuthClient, definePolicy, useAuth, useSession };
package/dist/react.js CHANGED
@@ -309,7 +309,8 @@ function createAuthClient(options = {}) {
309
309
  async passkey(o) {
310
310
  const m = await methods();
311
311
  if (m.passkeyHere && canUsePasskeys()) {
312
- const r = await ceremony("/sign-in/passkey/begin", "/sign-in/passkey/finish", {}, getPasskey);
312
+ const email = o?.email?.trim() ?? "";
313
+ const r = await ceremony("/sign-in/passkey/begin", "/sign-in/passkey/finish", email !== "" && checkEmail(email) === null ? { email } : {}, getPasskey);
313
314
  if (r.ok || r.error.code !== "passkey_unavailable" || !m.passkeyOnCauthy) return r;
314
315
  } else if (!m.passkeyOnCauthy) {
315
316
  return { ok: false, error: { code: "passkey_unavailable", message: "Passkeys cannot be used here." } };
@@ -438,7 +439,7 @@ function createAuthClient(options = {}) {
438
439
  },
439
440
  addPasskey(f = {}) {
440
441
  if (!canUsePasskeys()) return Promise.resolve({ ok: false, error: { code: "passkey_unavailable", message: "This browser cannot make passkeys." } });
441
- return ceremony("/me/passkeys/add/begin", "/me/passkeys/add/finish", { password: f.password ?? "" }, makePasskey, { name: f.name ?? "" });
442
+ return ceremony("/me/passkeys/add/begin", "/me/passkeys/add/finish", { password: f.password ?? "", ...f.kind ? { kind: f.kind } : {} }, makePasskey, { name: f.name ?? "" });
442
443
  },
443
444
  removePasskey: (id) => post("/me/passkeys/remove", { id }, null)
444
445
  },
@@ -579,6 +580,9 @@ var TEXTS = {
579
580
  passkeyName: "A name for this device (optional)",
580
581
  addPasskey: "Add a passkey on this device",
581
582
  removePasskey: "Remove",
583
+ addPasskeyDevice: "Add this device (fingerprint or face)",
584
+ addSecurityKey: "Add a security key",
585
+ passkeyKinds: { security_key: "Security key", synced: "Synced across your devices", device: "On this device only" },
582
586
  passkeyAdded: "The passkey was added. Next time, sign in with it.",
583
587
  passkeyUnnamed: "Passkey",
584
588
  sessions: "Where you are signed in",
@@ -691,6 +695,9 @@ var TEXTS = {
691
695
  passkeyName: "Un nombre para este dispositivo (opcional)",
692
696
  addPasskey: "Agregar una llave en este dispositivo",
693
697
  removePasskey: "Quitar",
698
+ addPasskeyDevice: "Agregar este dispositivo (huella o rostro)",
699
+ addSecurityKey: "Agregar una llave f\xEDsica",
700
+ passkeyKinds: { security_key: "Llave f\xEDsica", synced: "Sincronizada entre tus dispositivos", device: "Solo en un dispositivo" },
694
701
  passkeyAdded: "La llave de acceso qued\xF3 agregada. La pr\xF3xima vez, entra con ella.",
695
702
  passkeyUnnamed: "Llave de acceso",
696
703
  sessions: "D\xF3nde tienes la sesi\xF3n abierta",
@@ -976,7 +983,7 @@ function SignIn(props) {
976
983
  autofill.current?.abort();
977
984
  f.setBusy(true);
978
985
  f.setError(null);
979
- const r = await auth.signIn.passkey({ returnTo: props.returnTo, locale: props.locale });
986
+ const r = await auth.signIn.passkey({ returnTo: props.returnTo, locale: props.locale, email });
980
987
  if (r.ok && r.status === "redirected") return;
981
988
  f.setBusy(false);
982
989
  if (!r.ok) setOffer((n) => n + 1);
@@ -1266,9 +1273,9 @@ function PasskeysPart({ props, account, accountUrl, when }) {
1266
1273
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", { className: f.cx("link"), href: accountUrl, children: f.t.managePasskeys })
1267
1274
  ] });
1268
1275
  }
1269
- const add = async (e) => {
1270
- e.preventDefault();
1271
- const r = await run(() => auth.account.addPasskey({ name, password }));
1276
+ const add = async (e, kind = "device") => {
1277
+ e?.preventDefault();
1278
+ const r = await run(() => auth.account.addPasskey({ name, password, kind }));
1272
1279
  if (!r.ok) {
1273
1280
  if (r.error.code === "cancelled") f.setError(null);
1274
1281
  return;
@@ -1288,6 +1295,7 @@ function PasskeysPart({ props, account, accountUrl, when }) {
1288
1295
  general && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { role: "alert", className: f.cx("error"), children: f.say(general) }),
1289
1296
  list.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: f.cx("notice"), children: f.t.noPasskeys }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: f.cx("sessions"), children: list.map((p) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { className: f.cx("session"), children: [
1290
1297
  p.name || f.t.passkeyUnnamed,
1298
+ p.kind !== "unknown" ? ` \xB7 ${f.t.passkeyKinds[p.kind]}` : "",
1291
1299
  " \xB7 ",
1292
1300
  when(p.createdAt),
1293
1301
  " ",
@@ -1295,7 +1303,8 @@ function PasskeysPart({ props, account, accountUrl, when }) {
1295
1303
  ] }, p.id)) }),
1296
1304
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { f, name: "name", type: "text", label: f.t.passkeyName, value: name, autoComplete: "off", onChange: setName }),
1297
1305
  account.hasPassword && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { f, name: "password", type: "password", label: f.t.currentPassword, value: password, autoComplete: "current-password", required: true, onChange: setPassword }),
1298
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.addPasskey }),
1306
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.addPasskeyDevice }),
1307
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => void add(null, "security_key"), children: f.t.addSecurityKey }),
1299
1308
  done && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { role: "status", className: f.cx("notice"), children: done })
1300
1309
  ] });
1301
1310
  }