cauthy-auth 0.18.0 → 0.20.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/client.d.mts CHANGED
@@ -100,12 +100,34 @@ interface AuthMethods {
100
100
  * forms show it themselves.
101
101
  */
102
102
  captchaSiteKey?: string;
103
+ /**
104
+ * Whether the workspace signs some people in through their company's SSO,
105
+ * found by their work address (`signIn.ssoDiscover`, `signIn.sso`).
106
+ */
107
+ sso: boolean;
108
+ }
109
+ /** A company's sign-in (an SSO connection of the workspace). */
110
+ interface SSOConnection {
111
+ /** What `signIn.sso({ connection })` takes. */
112
+ id: string;
113
+ /** The company's name, for "Continue with …". */
114
+ name: string;
115
+ /** The address can sign in no other way: a password, link or provider answers `sso_required`. */
116
+ enforced: boolean;
103
117
  }
118
+ /**
119
+ * What holds a passkey, as its authenticator says: a security key (a YubiKey),
120
+ * one synced across the person's devices (iCloud Keychain, Google Password
121
+ * Manager), one on a single device (Windows Hello), or unknown (made before
122
+ * Cauthy kept this).
123
+ */
124
+ type PasskeyKind = 'security_key' | 'synced' | 'device' | 'unknown';
104
125
  /** A passkey of the signed-in account. Moments are UTC. */
105
126
  interface Passkey {
106
127
  id: string;
107
128
  /** What the person called it ("My laptop"), or "". */
108
129
  name: string;
130
+ kind: PasskeyKind;
109
131
  createdAt: string;
110
132
  /** When it last signed the person in, or null. */
111
133
  lastUsedAt: string | null;
@@ -279,10 +301,14 @@ interface AccountClient {
279
301
  * Makes a passkey on this device, on this page: the browser asks the person
280
302
  * for their fingerprint, face or screen lock. An account with a password
281
303
  * proves it again first. `cancelled`: the person closed the browser's prompt.
304
+ * `kind` sends the browser straight to one: `'device'`, this device's
305
+ * fingerprint, face or screen lock; `'security_key'`, a security key.
306
+ * Without it, the browser offers all.
282
307
  */
283
308
  addPasskey(form?: {
284
309
  password?: string;
285
310
  name?: string;
311
+ kind?: 'device' | 'security_key';
286
312
  }): Promise<AuthResult<'added', {
287
313
  passkey: Passkey;
288
314
  }>>;
@@ -400,6 +426,38 @@ interface AuthClient {
400
426
  social(provider: string, options?: {
401
427
  returnTo?: string;
402
428
  }): void;
429
+ /**
430
+ * Which company's sign-in a work address uses, if any (`found`), or
431
+ * `none`. It says so of the address's domain, never whether the address
432
+ * has an account.
433
+ */
434
+ ssoDiscover(form: {
435
+ email: string;
436
+ }): Promise<AuthResult<'found', {
437
+ connection: SSOConnection;
438
+ }> | AuthResult<'none'>>;
439
+ /**
440
+ * Sends the browser to the person's company (found by `email`, or named
441
+ * by `connection`); it comes back signed in, at `returnTo`. A sign-in the
442
+ * company refused comes back with `?auth_error=`. Any other way of
443
+ * signing in answers `sso_required` for an address its company holds to
444
+ * SSO: send it here then.
445
+ */
446
+ sso(target: {
447
+ email: string;
448
+ } | {
449
+ connection: string;
450
+ }, options?: {
451
+ returnTo?: string;
452
+ }): void;
453
+ /** Where `sso` sends the browser, for a plain link. */
454
+ ssoUrl(target: {
455
+ email: string;
456
+ } | {
457
+ connection: string;
458
+ }, options?: {
459
+ returnTo?: string;
460
+ }): string;
403
461
  /** Where `social` sends the browser, for a plain link. */
404
462
  socialUrl(provider: string, options?: {
405
463
  returnTo?: string;
@@ -458,4 +516,4 @@ interface AuthClientOptions {
458
516
  }
459
517
  declare function createAuthClient(options?: AuthClientOptions): AuthClient;
460
518
 
461
- export { type Account, type AccountClient, type AccountSession, type AuthClient, type AuthClientOptions, type AuthError, AuthField, type AuthMethods, type AuthResult, type ConnectedAgent, type LinkedIdentity, type Passkey, type SecondStep, type SessionState, type SessionStore, type SessionStoreOptions, canAutofillPasskeys, canUsePasskeys, createAuthClient, createSessionStore };
519
+ export { type Account, type AccountClient, type AccountSession, type AuthClient, type AuthClientOptions, type AuthError, AuthField, type AuthMethods, type AuthResult, type ConnectedAgent, type LinkedIdentity, type Passkey, type PasskeyKind, type SSOConnection, type SecondStep, type SessionState, type SessionStore, type SessionStoreOptions, canAutofillPasskeys, canUsePasskeys, createAuthClient, createSessionStore };
package/dist/client.d.ts CHANGED
@@ -100,12 +100,34 @@ interface AuthMethods {
100
100
  * forms show it themselves.
101
101
  */
102
102
  captchaSiteKey?: string;
103
+ /**
104
+ * Whether the workspace signs some people in through their company's SSO,
105
+ * found by their work address (`signIn.ssoDiscover`, `signIn.sso`).
106
+ */
107
+ sso: boolean;
108
+ }
109
+ /** A company's sign-in (an SSO connection of the workspace). */
110
+ interface SSOConnection {
111
+ /** What `signIn.sso({ connection })` takes. */
112
+ id: string;
113
+ /** The company's name, for "Continue with …". */
114
+ name: string;
115
+ /** The address can sign in no other way: a password, link or provider answers `sso_required`. */
116
+ enforced: boolean;
103
117
  }
118
+ /**
119
+ * What holds a passkey, as its authenticator says: a security key (a YubiKey),
120
+ * one synced across the person's devices (iCloud Keychain, Google Password
121
+ * Manager), one on a single device (Windows Hello), or unknown (made before
122
+ * Cauthy kept this).
123
+ */
124
+ type PasskeyKind = 'security_key' | 'synced' | 'device' | 'unknown';
104
125
  /** A passkey of the signed-in account. Moments are UTC. */
105
126
  interface Passkey {
106
127
  id: string;
107
128
  /** What the person called it ("My laptop"), or "". */
108
129
  name: string;
130
+ kind: PasskeyKind;
109
131
  createdAt: string;
110
132
  /** When it last signed the person in, or null. */
111
133
  lastUsedAt: string | null;
@@ -279,10 +301,14 @@ interface AccountClient {
279
301
  * Makes a passkey on this device, on this page: the browser asks the person
280
302
  * for their fingerprint, face or screen lock. An account with a password
281
303
  * proves it again first. `cancelled`: the person closed the browser's prompt.
304
+ * `kind` sends the browser straight to one: `'device'`, this device's
305
+ * fingerprint, face or screen lock; `'security_key'`, a security key.
306
+ * Without it, the browser offers all.
282
307
  */
283
308
  addPasskey(form?: {
284
309
  password?: string;
285
310
  name?: string;
311
+ kind?: 'device' | 'security_key';
286
312
  }): Promise<AuthResult<'added', {
287
313
  passkey: Passkey;
288
314
  }>>;
@@ -400,6 +426,38 @@ interface AuthClient {
400
426
  social(provider: string, options?: {
401
427
  returnTo?: string;
402
428
  }): void;
429
+ /**
430
+ * Which company's sign-in a work address uses, if any (`found`), or
431
+ * `none`. It says so of the address's domain, never whether the address
432
+ * has an account.
433
+ */
434
+ ssoDiscover(form: {
435
+ email: string;
436
+ }): Promise<AuthResult<'found', {
437
+ connection: SSOConnection;
438
+ }> | AuthResult<'none'>>;
439
+ /**
440
+ * Sends the browser to the person's company (found by `email`, or named
441
+ * by `connection`); it comes back signed in, at `returnTo`. A sign-in the
442
+ * company refused comes back with `?auth_error=`. Any other way of
443
+ * signing in answers `sso_required` for an address its company holds to
444
+ * SSO: send it here then.
445
+ */
446
+ sso(target: {
447
+ email: string;
448
+ } | {
449
+ connection: string;
450
+ }, options?: {
451
+ returnTo?: string;
452
+ }): void;
453
+ /** Where `sso` sends the browser, for a plain link. */
454
+ ssoUrl(target: {
455
+ email: string;
456
+ } | {
457
+ connection: string;
458
+ }, options?: {
459
+ returnTo?: string;
460
+ }): string;
403
461
  /** Where `social` sends the browser, for a plain link. */
404
462
  socialUrl(provider: string, options?: {
405
463
  returnTo?: string;
@@ -458,4 +516,4 @@ interface AuthClientOptions {
458
516
  }
459
517
  declare function createAuthClient(options?: AuthClientOptions): AuthClient;
460
518
 
461
- export { type Account, type AccountClient, type AccountSession, type AuthClient, type AuthClientOptions, type AuthError, AuthField, type AuthMethods, type AuthResult, type ConnectedAgent, type LinkedIdentity, type Passkey, type SecondStep, type SessionState, type SessionStore, type SessionStoreOptions, canAutofillPasskeys, canUsePasskeys, createAuthClient, createSessionStore };
519
+ export { type Account, type AccountClient, type AccountSession, type AuthClient, type AuthClientOptions, type AuthError, AuthField, type AuthMethods, type AuthResult, type ConnectedAgent, type LinkedIdentity, type Passkey, type PasskeyKind, type SSOConnection, type SecondStep, type SessionState, type SessionStore, type SessionStoreOptions, canAutofillPasskeys, canUsePasskeys, createAuthClient, createSessionStore };
package/dist/client.js CHANGED
@@ -345,6 +345,11 @@ function createAuthClient(options = {}) {
345
345
  }
346
346
  const linkUrl = (provider, o = {}) => `${base}/me/identities/link/${encodeURIComponent(provider)}${o.returnTo ? `?return_to=${encodeURIComponent(o.returnTo)}` : ""}`;
347
347
  const socialUrl = (provider, o = {}) => `${base}/sign-in/social/${encodeURIComponent(provider)}${o.returnTo ? `?return_to=${encodeURIComponent(o.returnTo)}` : ""}`;
348
+ const ssoUrl = (target, o = {}) => {
349
+ const q = new URLSearchParams("connection" in target ? { connection: target.connection } : { email: target.email.trim() });
350
+ if (o.returnTo) q.set("return_to", o.returnTo);
351
+ return `${base}/sign-in/sso?${q}`;
352
+ };
348
353
  const passkeyUrl = (o = {}) => {
349
354
  const q = new URLSearchParams({ method: "passkey" });
350
355
  if (o.returnTo) q.set("return_to", o.returnTo);
@@ -356,11 +361,11 @@ function createAuthClient(options = {}) {
356
361
  const res = await doFetch(`${base}/methods`, { credentials: "same-origin", headers: { accept: "application/json" } });
357
362
  if (res.ok) {
358
363
  const m = await res.json();
359
- return { providers: [], signUp: true, magicLink: false, passkey: false, ...m, passkeyHere: m.passkeyHere === true, passkeyOnCauthy: m.passkeyOnCauthy ?? m.passkey === true };
364
+ return { providers: [], signUp: true, magicLink: false, passkey: false, ...m, passkeyHere: m.passkeyHere === true, passkeyOnCauthy: m.passkeyOnCauthy ?? m.passkey === true, sso: m.sso === true };
360
365
  }
361
366
  } catch {
362
367
  }
363
- return { providers: [], signUp: true, magicLink: false, passkey: false, passkeyHere: false, passkeyOnCauthy: false };
368
+ return { providers: [], signUp: true, magicLink: false, passkey: false, passkeyHere: false, passkeyOnCauthy: false, sso: false };
364
369
  }
365
370
  async function ceremony(begin, finish, form, run, more = {}) {
366
371
  const begun = await post(begin, form, null);
@@ -458,6 +463,11 @@ function createAuthClient(options = {}) {
458
463
  socialUrl,
459
464
  social(provider, o) {
460
465
  window.location.assign(socialUrl(provider, o));
466
+ },
467
+ ssoDiscover: (f) => post("/sign-in/sso/discover", { email: f.email.trim() }, checkEmail(f.email)),
468
+ ssoUrl,
469
+ sso(target, o) {
470
+ window.location.assign(ssoUrl(target, o));
461
471
  }
462
472
  },
463
473
  signUp: {
@@ -516,7 +526,7 @@ function createAuthClient(options = {}) {
516
526
  },
517
527
  addPasskey(f = {}) {
518
528
  if (!canUsePasskeys()) return Promise.resolve({ ok: false, error: { code: "passkey_unavailable", message: "This browser cannot make passkeys." } });
519
- return ceremony("/me/passkeys/add/begin", "/me/passkeys/add/finish", { password: f.password ?? "" }, makePasskey, { name: f.name ?? "" });
529
+ return ceremony("/me/passkeys/add/begin", "/me/passkeys/add/finish", { password: f.password ?? "", ...f.kind ? { kind: f.kind } : {} }, makePasskey, { name: f.name ?? "" });
520
530
  },
521
531
  removePasskey: (id) => post("/me/passkeys/remove", { id }, null)
522
532
  },