cauthy-auth 0.30.0 → 0.32.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.
Files changed (46) hide show
  1. package/README.md +50 -5
  2. package/dist/{cauthy-BXgsZ-Um.d.mts → cauthy-2jtP2LVQ.d.mts} +1 -1
  3. package/dist/{cauthy-CHENs452.d.ts → cauthy-CKfvvv_i.d.ts} +1 -1
  4. package/dist/cli.js +8 -5
  5. package/dist/client.d.mts +47 -6
  6. package/dist/client.d.ts +47 -6
  7. package/dist/client.js +16 -2
  8. package/dist/client.js.map +1 -1
  9. package/dist/client.mjs +16 -2
  10. package/dist/client.mjs.map +1 -1
  11. package/dist/express.d.mts +2 -2
  12. package/dist/express.d.ts +2 -2
  13. package/dist/fastify.d.mts +2 -2
  14. package/dist/fastify.d.ts +2 -2
  15. package/dist/hono.d.mts +2 -2
  16. package/dist/hono.d.ts +2 -2
  17. package/dist/index.d.mts +2 -2
  18. package/dist/index.d.ts +2 -2
  19. package/dist/index.js +64 -21
  20. package/dist/index.js.map +1 -1
  21. package/dist/index.mjs +64 -21
  22. package/dist/index.mjs.map +1 -1
  23. package/dist/next.d.mts +2 -2
  24. package/dist/next.d.ts +2 -2
  25. package/dist/react.d.mts +339 -31
  26. package/dist/react.d.ts +339 -31
  27. package/dist/react.js +616 -225
  28. package/dist/react.js.map +1 -1
  29. package/dist/react.mjs +610 -230
  30. package/dist/react.mjs.map +1 -1
  31. package/dist/styles.css +8 -0
  32. package/dist/svelte.d.mts +2 -2
  33. package/dist/svelte.d.ts +2 -2
  34. package/dist/svelte.js +16 -2
  35. package/dist/svelte.js.map +1 -1
  36. package/dist/svelte.mjs +16 -2
  37. package/dist/svelte.mjs.map +1 -1
  38. package/dist/{system-0mHrdAgO.d.mts → system-BrrJsrFW.d.mts} +14 -0
  39. package/dist/{system-BIYbS7h2.d.ts → system-BvvoNs2y.d.ts} +14 -0
  40. package/dist/vue.d.mts +2 -2
  41. package/dist/vue.d.ts +2 -2
  42. package/dist/vue.js +16 -2
  43. package/dist/vue.js.map +1 -1
  44. package/dist/vue.mjs +16 -2
  45. package/dist/vue.mjs.map +1 -1
  46. package/package.json +2 -1
package/dist/index.mjs CHANGED
@@ -691,6 +691,8 @@ function createSystem(given = {}) {
691
691
  const envKey = env("CAUTHY_SYSTEM_KEY");
692
692
  const key = given.key ?? (envKey ? { privateKey: envKey, keyId: env("CAUTHY_SYSTEM_KEY_ID") ?? "" } : void 0);
693
693
  const ownSystem = given.system ?? env("CAUTHY_SYSTEM") ?? "";
694
+ const acceptInviteUrl = given.acceptInviteUrl ?? env("CAUTHY_ACCEPT_INVITE_URL") ?? "";
695
+ const inviteHeaders = /^https?:\/\//.test(acceptInviteUrl) ? { "x-cauthy-client-id": clientId, "x-cauthy-link-to": acceptInviteUrl } : {};
694
696
  const doFetch = (...args) => (given.fetch ?? fetch)(...args);
695
697
  const tokenEndpoint = `${issuer}/v1/oauth/token`;
696
698
  function configured() {
@@ -733,10 +735,10 @@ function createSystem(given = {}) {
733
735
  asking = void 0;
734
736
  });
735
737
  }
736
- async function call(method, path, body) {
738
+ async function call(method, path, body, extra = {}) {
737
739
  const send = async () => doFetch(`${issuer}${path}`, {
738
740
  method,
739
- headers: { authorization: `Bearer ${await token()}`, ...body === void 0 ? {} : { "content-type": "application/json" } },
741
+ headers: { authorization: `Bearer ${await token()}`, ...extra, ...body === void 0 ? {} : { "content-type": "application/json" } },
740
742
  body: body === void 0 ? void 0 : JSON.stringify(body)
741
743
  });
742
744
  let res = await send();
@@ -747,7 +749,7 @@ function createSystem(given = {}) {
747
749
  if (!res.ok) await fail(res, `${method} ${path}`);
748
750
  return res.status === 204 ? void 0 : res.json();
749
751
  }
750
- const data = async (method, path, body) => (await call(method, path, body))?.data;
752
+ const data = async (method, path, body, extra) => (await call(method, path, body, extra))?.data;
751
753
  const id = encodeURIComponent;
752
754
  return {
753
755
  token,
@@ -784,7 +786,8 @@ function createSystem(given = {}) {
784
786
  return toMember(await data(
785
787
  "POST",
786
788
  `/v1/organizations/${id(orgId)}/members`,
787
- { role: m.role, user_id: m.userId, email: m.email, name: m.name, locale: m.locale, client_id: clientId }
789
+ { role: m.role, user_id: m.userId, email: m.email, name: m.name, locale: m.locale, client_id: clientId },
790
+ inviteHeaders
788
791
  ));
789
792
  },
790
793
  async setRole(orgId, userId, role) {
@@ -795,7 +798,7 @@ function createSystem(given = {}) {
795
798
  }
796
799
  },
797
800
  async invite(person) {
798
- const u = await data("POST", "/v1/users", { ...person, client_id: clientId });
801
+ const u = await data("POST", "/v1/users", { ...person, client_id: clientId }, inviteHeaders);
799
802
  return { id: u.id, email: u.email };
800
803
  },
801
804
  theme: {
@@ -1130,13 +1133,16 @@ function createCauthy(given = {}) {
1130
1133
  const againCookie = `${cookieName}_again`;
1131
1134
  const stepCookie = `${cookieName}_step`;
1132
1135
  const doFetch = (...args) => (given.fetch ?? fetch)(...args);
1136
+ const iconOf = iconFor(issuer);
1133
1137
  const key = keyOf(secret);
1134
1138
  const pages = {
1135
1139
  signIn: given.pages?.signIn ? localPath(given.pages.signIn, "/") : void 0,
1136
1140
  resetPassword: given.pages?.resetPassword ? localPath(given.pages.resetPassword, "/") : void 0,
1137
- verifyEmail: given.pages?.verifyEmail ? localPath(given.pages.verifyEmail, "/") : void 0
1141
+ verifyEmail: given.pages?.verifyEmail ? localPath(given.pages.verifyEmail, "/") : void 0,
1142
+ acceptInvite: given.pages?.acceptInvite ? localPath(given.pages.acceptInvite, "/") : void 0
1138
1143
  };
1139
- const ownSystem = createSystem({ issuer, clientId, clientSecret, key: given.systemKey, system: system || void 0, fetch: given.fetch });
1144
+ const acceptInviteUrl = baseURL && pages.acceptInvite ? `${withoutTrailingSlashes(baseURL)}${pages.acceptInvite}` : void 0;
1145
+ const ownSystem = createSystem({ issuer, clientId, clientSecret, key: given.systemKey, system: system || void 0, acceptInviteUrl, fetch: given.fetch });
1140
1146
  const originOf = (request) => {
1141
1147
  if (baseURL) return withoutTrailingSlashes(baseURL);
1142
1148
  const url = new URL(request.url);
@@ -1563,6 +1569,14 @@ function createCauthy(given = {}) {
1563
1569
  for (const c of [...await write(request, s, readCookies(request.headers.get("cookie"))), ...extra]) h.append("set-cookie", c);
1564
1570
  return json({ status: "signed_in", session: await toPublic(toSession(s)), ...more }, 200, h);
1565
1571
  }
1572
+ async function loggedIn(request, data) {
1573
+ if (data?.mfa_required === true) {
1574
+ const step = { kind: "mfa", token: String(data.mfa_token ?? ""), returnTo: afterSignIn };
1575
+ const how = data.mfa_method === "email" ? { method: "email" } : {};
1576
+ return json({ status: "mfa_required", ...how }, 200, new Headers({ "set-cookie": writeCookie(stepCookie, await seal(step, await key), attrs(request, STEP_SECONDS)) }));
1577
+ }
1578
+ return signedIn(request, data);
1579
+ }
1566
1580
  let lookCache = null;
1567
1581
  let policyCache = null;
1568
1582
  const keepPolicy = (settings) => {
@@ -1636,7 +1650,9 @@ function createCauthy(given = {}) {
1636
1650
  "/me/organizations/members/invite",
1637
1651
  "/me/organizations/rename",
1638
1652
  "/me/organizations/archive",
1639
- "/me/organizations/delete"
1653
+ "/me/organizations/delete",
1654
+ "/invitation",
1655
+ "/invitation/accept"
1640
1656
  ].includes(route) || route.startsWith("/sign-in/social/") || route.startsWith("/callback/") || route.startsWith("/me/identities/link/") || route.startsWith("/me/upgrade/social/") || route === "/sign-in/sso" || route === "/sign-in/sso/discover" || route === "/sso/callback";
1641
1657
  if (!own) return null;
1642
1658
  if (tenant === "") {
@@ -1658,17 +1674,21 @@ function createCauthy(given = {}) {
1658
1674
  ]);
1659
1675
  const list = Array.isArray(providers.data) ? providers.data : [];
1660
1676
  const password = keepPolicy(settings);
1661
- const here = place.data?.here === true;
1677
+ const passkeys = settings.data?.allow_passkeys !== false;
1678
+ const here = passkeys && place.data?.here === true;
1662
1679
  return json({
1663
- providers: list.map((p) => ({ id: String(p.provider ?? p.id ?? ""), name: String(p.label ?? p.name ?? p.provider ?? "") })).filter((p) => p.id !== ""),
1680
+ providers: list.map((p) => ({ id: String(p.provider ?? p.id ?? ""), name: String(p.label ?? p.name ?? p.provider ?? ""), ...iconOf(p) })).filter((p) => p.id !== ""),
1681
+ // Whether the workspace signs people in with a password at all. A
1682
+ // Cauthy from before the setting says nothing of it: then it does.
1683
+ passwordSignIn: settings.data?.allow_password !== false,
1664
1684
  signUp: settings.data?.allow_signup !== false,
1665
1685
  // The application's system makes an organization per sign-up: the form asks the company's name.
1666
1686
  ...settings.data?.signup?.organization?.ask === true ? { organization: { ask: true, required: settings.data.signup.organization.required === true } } : {},
1667
1687
  // A sign-in link needs a page of the application to open.
1668
1688
  magicLink: settings.data?.allow_magic_link === true && pages.signIn !== void 0,
1669
- passkey: place.error ? true : here || place.data?.on_cauthy === true,
1689
+ passkey: passkeys && (place.error ? true : here || place.data?.on_cauthy === true),
1670
1690
  passkeyHere: here,
1671
- passkeyOnCauthy: place.error ? true : place.data?.on_cauthy === true,
1691
+ passkeyOnCauthy: passkeys && (place.error ? true : place.data?.on_cauthy === true),
1672
1692
  // A company's sign-in, found by the person's work address.
1673
1693
  sso: Array.isArray(sso.data) && sso.data.some((c) => c?.discoverable === true),
1674
1694
  // The terms a sign-up accepts and the consents it answers, when the workspace asks any.
@@ -1678,6 +1698,14 @@ function createCauthy(given = {}) {
1678
1698
  ...password ? { password } : {}
1679
1699
  });
1680
1700
  }
1701
+ if (route === "/invitation" && !post) {
1702
+ const token2 = (url.searchParams.get("token") ?? "").trim();
1703
+ if (token2 === "" || token2.length > 512) return problem(422, "invalid_token", "This invitation is not valid, or it has expired.");
1704
+ const res = await ask(request, "GET", `/v1/auth/invitation?token=${encodeURIComponent(token2)}`);
1705
+ if (res.error) return problem(res.status, res.error.code, res.error.message);
1706
+ const organization = typeof res.data?.organization === "string" && res.data.organization !== "" ? { organization: res.data.organization } : {};
1707
+ return json({ status: "ok", invitation: { email: String(res.data?.email ?? ""), workspace: String(res.data?.workspace ?? ""), ...organization } });
1708
+ }
1681
1709
  if (route === "/sign-in/sso" && !post) {
1682
1710
  const returnTo = localPath(url.searchParams.get("return_to"), afterSignIn);
1683
1711
  const failed2 = (code) => redirect(`${returnTo}${returnTo.includes("?") ? "&" : "?"}auth_error=${encodeURIComponent(code)}`);
@@ -1907,12 +1935,7 @@ function createCauthy(given = {}) {
1907
1935
  if (bad) return invalid(bad);
1908
1936
  const res = await ask(request, "POST", "/v1/auth/login", { email: String(b.email).trim(), password: b.password });
1909
1937
  if (res.error) return problem(res.status, res.error.code, res.error.message);
1910
- if (res.data?.mfa_required === true) {
1911
- const step = { kind: "mfa", token: String(res.data.mfa_token ?? ""), returnTo: afterSignIn };
1912
- const how = res.data.mfa_method === "email" ? { method: "email" } : {};
1913
- return json({ status: "mfa_required", ...how }, 200, new Headers({ "set-cookie": writeCookie(stepCookie, await seal(step, await key), attrs(request, STEP_SECONDS)) }));
1914
- }
1915
- return signedIn(request, res.data);
1938
+ return loggedIn(request, res.data);
1916
1939
  }
1917
1940
  if (route === "/sign-in/mfa") {
1918
1941
  const bad = checkCode(b.code);
@@ -2133,13 +2156,13 @@ function createCauthy(given = {}) {
2133
2156
  if (bad) return invalid(bad);
2134
2157
  const role = typeof b.role === "string" ? b.role : "";
2135
2158
  if (role === "") return problem(400, "invalid_role", "Choose a role.", "role", mine.headers);
2136
- const res = await as(base, {
2159
+ const res = await ask(request, "POST", base, {
2137
2160
  email: String(b.email).trim(),
2138
2161
  role,
2139
2162
  name: typeof b.name === "string" ? b.name.trim() : "",
2140
2163
  client_id: clientId,
2141
2164
  ...typeof b.locale === "string" && b.locale ? { locale: b.locale } : {}
2142
- });
2165
+ }, pages.acceptInvite, mine.token);
2143
2166
  if (res.error) return refused(res, res.error.code === "unknown_role" ? "role" : "email");
2144
2167
  return json({ status: "added", member: orgMemberOf(res.data) }, 200, mine.headers);
2145
2168
  }
@@ -2159,7 +2182,7 @@ function createCauthy(given = {}) {
2159
2182
  return json({ status: "removed", userId: user }, 200, mine.headers);
2160
2183
  }
2161
2184
  if (route === "/me/organizations/members/invite") {
2162
- const res = await as(`${base}/${user}/invite`, { client_id: clientId, ...typeof b.locale === "string" && b.locale ? { locale: b.locale } : {} });
2185
+ const res = await ask(request, "POST", `${base}/${user}/invite`, { client_id: clientId, ...typeof b.locale === "string" && b.locale ? { locale: b.locale } : {} }, pages.acceptInvite, mine.token);
2163
2186
  if (res.error) return refused(res);
2164
2187
  return json({ status: "sent", userId: user }, 200, mine.headers);
2165
2188
  }
@@ -2198,6 +2221,14 @@ function createCauthy(given = {}) {
2198
2221
  if (res.data?.access_token) return signedIn(request, res.data);
2199
2222
  return json({ status: "verified" });
2200
2223
  }
2224
+ if (route === "/invitation/accept") {
2225
+ if (!isToken(b.token)) return problem(422, "invalid_token", "This invitation is not valid, or it has expired.");
2226
+ const bad = await newPasswordProblem(request, b.password);
2227
+ if (bad) return invalid(bad);
2228
+ const res = await ask(request, "POST", "/v1/auth/invitation/accept", { token: String(b.token), password: b.password });
2229
+ if (res.error) return problem(res.status, res.error.code, res.error.message, res.error.code === "weak_password" ? "password" : void 0, void 0, res.error.reasons);
2230
+ return loggedIn(request, res.data);
2231
+ }
2201
2232
  if (route === "/sign-in/passkey/begin") {
2202
2233
  const email = typeof b.email === "string" && checkEmail(b.email) === null ? b.email.trim() : "";
2203
2234
  const res = await ask(request, "POST", "/v1/auth/webauthn/login/begin", email !== "" ? { email } : {});
@@ -2355,6 +2386,18 @@ function createCauthy(given = {}) {
2355
2386
  options: { issuer, clientId, basePath, afterSignIn, afterSignOut, cookieName }
2356
2387
  };
2357
2388
  }
2389
+ function iconFor(issuer) {
2390
+ return (p) => {
2391
+ const raw = typeof p?.icon_url === "string" ? p.icon_url.trim() : "";
2392
+ if (raw === "") return {};
2393
+ try {
2394
+ const url = new URL(raw.startsWith("/") && !raw.startsWith("//") ? `${issuer}${raw}` : raw);
2395
+ return url.protocol === "https:" || url.protocol === "http:" ? { iconUrl: url.href } : {};
2396
+ } catch {
2397
+ return {};
2398
+ }
2399
+ };
2400
+ }
2358
2401
  function legalOf(raw) {
2359
2402
  const documents = Array.isArray(raw?.documents) ? raw.documents : [];
2360
2403
  const purposes = Array.isArray(raw?.consent_purposes) ? raw.consent_purposes : [];