cauthy-auth 0.19.0 → 0.22.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 (43) hide show
  1. package/dist/{cauthy-Bn3iv50y.d.ts → cauthy-DGAy45G2.d.ts} +1 -1
  2. package/dist/{cauthy-C29HCvag.d.mts → cauthy-XkIbG5gE.d.mts} +1 -1
  3. package/dist/client.d.mts +157 -2
  4. package/dist/client.d.ts +157 -2
  5. package/dist/client.js +37 -2
  6. package/dist/client.js.map +1 -1
  7. package/dist/client.mjs +37 -2
  8. package/dist/client.mjs.map +1 -1
  9. package/dist/express.d.mts +2 -2
  10. package/dist/express.d.ts +2 -2
  11. package/dist/fastify.d.mts +2 -2
  12. package/dist/fastify.d.ts +2 -2
  13. package/dist/hono.d.mts +2 -2
  14. package/dist/hono.d.ts +2 -2
  15. package/dist/index.d.mts +2 -2
  16. package/dist/index.d.ts +2 -2
  17. package/dist/index.js +181 -6
  18. package/dist/index.js.map +1 -1
  19. package/dist/index.mjs +181 -6
  20. package/dist/index.mjs.map +1 -1
  21. package/dist/next.d.mts +2 -2
  22. package/dist/next.d.ts +2 -2
  23. package/dist/react.d.mts +192 -1
  24. package/dist/react.d.ts +192 -1
  25. package/dist/react.js +279 -23
  26. package/dist/react.js.map +1 -1
  27. package/dist/react.mjs +278 -23
  28. package/dist/react.mjs.map +1 -1
  29. package/dist/svelte.d.mts +3 -3
  30. package/dist/svelte.d.ts +3 -3
  31. package/dist/svelte.js +37 -2
  32. package/dist/svelte.js.map +1 -1
  33. package/dist/svelte.mjs +37 -2
  34. package/dist/svelte.mjs.map +1 -1
  35. package/dist/{system-ZD_Wa8Bm.d.mts → system-BxMsSIu1.d.mts} +2 -0
  36. package/dist/{system-DhRr_WxR.d.ts → system-DTIeDXDP.d.ts} +2 -0
  37. package/dist/vue.d.mts +3 -3
  38. package/dist/vue.d.ts +3 -3
  39. package/dist/vue.js +37 -2
  40. package/dist/vue.js.map +1 -1
  41. package/dist/vue.mjs +37 -2
  42. package/dist/vue.mjs.map +1 -1
  43. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -789,7 +789,8 @@ function createCauthy(given = {}) {
789
789
  emailVerified: b.email_verified === true,
790
790
  restricted: b.restricted === true,
791
791
  ...typeof b.email_verify_by === "string" ? { emailVerifyBy: b.email_verify_by } : {},
792
- ...typeof b.locale === "string" && b.locale !== "" ? { locale: b.locale } : {}
792
+ ...typeof b.locale === "string" && b.locale !== "" ? { locale: b.locale } : {},
793
+ ...b.anonymous === true ? { isAnonymous: true } : {}
793
794
  }
794
795
  };
795
796
  } catch {
@@ -998,6 +999,32 @@ function createCauthy(given = {}) {
998
999
  createdAt: String(d?.created_at ?? ""),
999
1000
  lastUsedAt: d?.last_used_at ? String(d.last_used_at) : null
1000
1001
  });
1002
+ const UUID = /^[0-9a-f-]{36}$/i;
1003
+ const seatOf = (d) => ({
1004
+ id: String(d?.id ?? ""),
1005
+ system: String(d?.system ?? ""),
1006
+ name: String(d?.name ?? ""),
1007
+ kind: String(d?.kind ?? ""),
1008
+ role: String(d?.role ?? ""),
1009
+ can: { readMembers: d?.can?.read_members === true, manageMembers: d?.can?.manage_members === true }
1010
+ });
1011
+ const orgMemberOf = (d) => ({
1012
+ userId: String(d?.user_id ?? ""),
1013
+ email: String(d?.email ?? ""),
1014
+ name: String(d?.name ?? ""),
1015
+ role: String(d?.role ?? ""),
1016
+ status: String(d?.status ?? ""),
1017
+ invited: d?.invited === true,
1018
+ manager: d?.manager === true,
1019
+ you: d?.you === true,
1020
+ since: String(d?.since ?? "")
1021
+ });
1022
+ const orgRoleOf = (d) => ({
1023
+ role: String(d?.role ?? ""),
1024
+ name: String(d?.name ?? ""),
1025
+ description: String(d?.description ?? ""),
1026
+ manager: d?.manager === true
1027
+ });
1001
1028
  const agentOf = (d) => ({
1002
1029
  id: String(d?.id ?? ""),
1003
1030
  name: String(d?.agent?.name ?? ""),
@@ -1133,8 +1160,17 @@ function createCauthy(given = {}) {
1133
1160
  "/me/passkeys/add/finish",
1134
1161
  "/me/passkeys/remove",
1135
1162
  "/me/agents",
1136
- "/me/agents/disconnect"
1137
- ].includes(route) || route.startsWith("/sign-in/social/") || route.startsWith("/callback/") || route.startsWith("/me/identities/link/");
1163
+ "/me/agents/disconnect",
1164
+ "/sign-in/anonymous",
1165
+ "/me/upgrade",
1166
+ "/me/organizations",
1167
+ "/me/organizations/members",
1168
+ "/me/organizations/roles",
1169
+ "/me/organizations/members/add",
1170
+ "/me/organizations/members/role",
1171
+ "/me/organizations/members/remove",
1172
+ "/me/organizations/members/invite"
1173
+ ].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";
1138
1174
  if (!own) return null;
1139
1175
  if (tenant === "") {
1140
1176
  return problem(500, "not_configured", "cauthy-auth: tenant (CAUTHY_TENANT) is required for the application's own sign-in screens");
@@ -1147,10 +1183,11 @@ function createCauthy(given = {}) {
1147
1183
  return json(lookCache.look);
1148
1184
  }
1149
1185
  if (route === "/methods" && !post) {
1150
- const [providers, settings, place] = await Promise.all([
1186
+ const [providers, settings, place, sso] = await Promise.all([
1151
1187
  ask(request, "GET", "/v1/auth/social/providers"),
1152
1188
  ask(request, "GET", "/v1/auth/settings"),
1153
- ask(request, "GET", `/v1/auth/webauthn/place?origin=${encodeURIComponent(originOf(request))}`)
1189
+ ask(request, "GET", `/v1/auth/webauthn/place?origin=${encodeURIComponent(originOf(request))}`),
1190
+ ask(request, "GET", "/v1/auth/sso/connections")
1154
1191
  ]);
1155
1192
  const list = Array.isArray(providers.data) ? providers.data : [];
1156
1193
  const here = place.data?.here === true;
@@ -1162,9 +1199,46 @@ function createCauthy(given = {}) {
1162
1199
  passkey: place.error ? true : here || place.data?.on_cauthy === true,
1163
1200
  passkeyHere: here,
1164
1201
  passkeyOnCauthy: place.error ? true : place.data?.on_cauthy === true,
1202
+ // A company's sign-in, found by the person's work address.
1203
+ sso: Array.isArray(sso.data) && sso.data.some((c) => c?.discoverable === true),
1165
1204
  ...settings.data?.captcha_enabled === true && settings.data?.captcha_site_key ? { captchaSiteKey: String(settings.data.captcha_site_key) } : {}
1166
1205
  });
1167
1206
  }
1207
+ if (route === "/sign-in/sso" && !post) {
1208
+ const returnTo = localPath(url.searchParams.get("return_to"), afterSignIn);
1209
+ const failed2 = (code) => redirect(`${returnTo}${returnTo.includes("?") ? "&" : "?"}auth_error=${encodeURIComponent(code)}`);
1210
+ const email = (url.searchParams.get("email") ?? "").trim();
1211
+ const connection = (url.searchParams.get("connection") ?? "").trim();
1212
+ if (email === "" && connection === "") return failed2("sso_not_found");
1213
+ const verifier = random(48);
1214
+ const challenge = b64url(new Uint8Array(await crypto.subtle.digest("SHA-256", new TextEncoder().encode(verifier))));
1215
+ const callback2 = `${basePath}/sso/callback`;
1216
+ const started = await ask(request, "POST", "/v1/auth/sso/start", {
1217
+ ...connection ? { connection } : { email },
1218
+ redirect_uri: `${originOf(request)}${callback2}`,
1219
+ code_challenge: challenge
1220
+ }, callback2);
1221
+ if (started.error || typeof started.data?.redirect_url !== "string") return failed2(started.error?.code ?? "sso_unavailable");
1222
+ const step = { kind: "sso", token: verifier, returnTo };
1223
+ return redirect(started.data.redirect_url, [writeCookie(stepCookie, await seal(step, await key), attrs(request, STEP_SECONDS))]);
1224
+ }
1225
+ if (route === "/sso/callback" && !post) {
1226
+ const sealed = readCookies(request.headers.get("cookie")).get(stepCookie);
1227
+ const step = sealed ? await unseal(sealed, await key) : null;
1228
+ const clear = writeCookie(stepCookie, "", attrs(request, 0));
1229
+ const back = step?.returnTo ?? afterSignIn;
1230
+ const failedTo = (code2) => redirect(`${back}${back.includes("?") ? "&" : "?"}auth_error=${encodeURIComponent(code2)}`, [clear]);
1231
+ if (step === null || step.kind !== "sso") return failedTo("state_mismatch");
1232
+ const refused = url.searchParams.get("error");
1233
+ if (refused) return failedTo(refused);
1234
+ const code = url.searchParams.get("code");
1235
+ if (!code) return failedTo("sso_failed");
1236
+ const done = await ask(request, "POST", "/v1/auth/sso/token", { code, redirect_uri: `${originOf(request)}${basePath}/sso/callback`, code_verifier: step.token });
1237
+ if (done.error) return failedTo(done.error.code);
1238
+ const s = await stored(done.data);
1239
+ if (s === null) return failedTo("unavailable");
1240
+ return redirect(back, [...await write(request, s, readCookies(request.headers.get("cookie"))), clear]);
1241
+ }
1168
1242
  if (route.startsWith("/sign-in/social/") && !post) {
1169
1243
  const provider = providerIn(route.slice("/sign-in/social/".length));
1170
1244
  if (!PROVIDER_ID.test(provider)) return new Response("Not found", { status: 404 });
@@ -1184,10 +1258,19 @@ function createCauthy(given = {}) {
1184
1258
  const clear = writeCookie(stepCookie, "", attrs(request, 0));
1185
1259
  const back = step?.returnTo ?? afterSignIn;
1186
1260
  const failedTo = (code2) => redirect(`${back}${back.includes("?") ? "&" : "?"}auth_error=${encodeURIComponent(code2)}`, [clear]);
1187
- if (step === null || step.kind !== "social" && step.kind !== "link" || step.provider !== provider || url.searchParams.get("state") !== step.token) return failedTo("state_mismatch");
1261
+ if (step === null || step.kind !== "social" && step.kind !== "link" && step.kind !== "upgrade" || step.provider !== provider || url.searchParams.get("state") !== step.token) return failedTo("state_mismatch");
1188
1262
  const code = url.searchParams.get("code");
1189
1263
  if (!code) return failedTo(url.searchParams.get("error") === "access_denied" ? "cancelled" : "provider_refused");
1190
1264
  const q = new URLSearchParams({ code, state: step.token, redirect_uri: `${originOf(request)}${basePath}/callback/${provider}` });
1265
+ if (step.kind === "upgrade") {
1266
+ const mine = await signedInAs(request);
1267
+ if ("response" in mine) return failedTo("unauthenticated");
1268
+ const done2 = await ask(request, "GET", `/v1/auth/anonymous/upgrade/${provider}/callback?${q}`, void 0, void 0, mine.token);
1269
+ if (done2.error) return failedTo(done2.error.code);
1270
+ const s2 = await stored(done2.data);
1271
+ if (s2 === null) return failedTo("unavailable");
1272
+ return redirect(back, [...await write(request, s2, readCookies(request.headers.get("cookie"))), clear]);
1273
+ }
1191
1274
  if (step.kind === "link") {
1192
1275
  const mine = await signedInAs(request);
1193
1276
  if ("response" in mine) return failedTo("unauthenticated");
@@ -1203,6 +1286,19 @@ function createCauthy(given = {}) {
1203
1286
  if (s === null) return failedTo("unavailable");
1204
1287
  return redirect(back, [...await write(request, s, readCookies(request.headers.get("cookie"))), clear]);
1205
1288
  }
1289
+ if (route.startsWith("/me/upgrade/social/") && !post) {
1290
+ const provider = providerIn(route.slice("/me/upgrade/social/".length));
1291
+ if (!PROVIDER_ID.test(provider)) return new Response("Not found", { status: 404 });
1292
+ const returnTo = localPath(url.searchParams.get("return_to"), afterSignIn);
1293
+ const failed2 = (code) => redirect(`${returnTo}${returnTo.includes("?") ? "&" : "?"}auth_error=${encodeURIComponent(code)}`);
1294
+ const mine = await signedInAs(request);
1295
+ if ("response" in mine) return failed2("unauthenticated");
1296
+ const callback2 = `${basePath}/callback/${provider}`;
1297
+ const started = await ask(request, "GET", `/v1/auth/anonymous/upgrade/${provider}?redirect_uri=${encodeURIComponent(`${originOf(request)}${callback2}`)}`, void 0, callback2, mine.token);
1298
+ if (started.error || typeof started.data?.redirect_url !== "string") return failed2(started.error?.code ?? "provider_unavailable");
1299
+ const step = { kind: "upgrade", token: String(started.data.state ?? ""), provider, returnTo };
1300
+ return redirect(started.data.redirect_url, [...mine.headers.getSetCookie(), writeCookie(stepCookie, await seal(step, await key), attrs(request, STEP_SECONDS))]);
1301
+ }
1206
1302
  if (route.startsWith("/me/identities/link/") && !post) {
1207
1303
  const provider = providerIn(route.slice("/me/identities/link/".length));
1208
1304
  if (!PROVIDER_ID.test(provider)) return new Response("Not found", { status: 404 });
@@ -1240,6 +1336,24 @@ function createCauthy(given = {}) {
1240
1336
  const list = Array.isArray(res.data) ? res.data : [];
1241
1337
  return json({ agents: list.map(agentOf) }, 200, mine.headers);
1242
1338
  }
1339
+ if ((route === "/me/organizations" || route === "/me/organizations/members" || route === "/me/organizations/roles") && !post) {
1340
+ const mine = await signedInAs(request);
1341
+ if ("response" in mine) return mine.response;
1342
+ let path = "/v1/auth/me/organizations";
1343
+ if (route !== "/me/organizations") {
1344
+ const id = url.searchParams.get("id") ?? "";
1345
+ if (!UUID.test(id)) return problem(400, "invalid_organization", "Say which organization.", void 0, mine.headers);
1346
+ path += `/${id}/${route.endsWith("/roles") ? "roles" : "members"}`;
1347
+ } else if (url.searchParams.get("system")) {
1348
+ path += `?system=${encodeURIComponent(url.searchParams.get("system"))}`;
1349
+ }
1350
+ const res = await ask(request, "GET", path, void 0, void 0, mine.token);
1351
+ if (res.error) return problem(res.status, res.error.code, res.error.message, void 0, mine.headers);
1352
+ const list = Array.isArray(res.data) ? res.data : [];
1353
+ if (route === "/me/organizations") return json({ organizations: list.map(seatOf) }, 200, mine.headers);
1354
+ if (route === "/me/organizations/roles") return json({ roles: list.map(orgRoleOf) }, 200, mine.headers);
1355
+ return json({ members: list.map(orgMemberOf) }, 200, mine.headers);
1356
+ }
1243
1357
  if (route === "/me/mfa/factors" && !post) {
1244
1358
  const mine = await signedInAs(request);
1245
1359
  if ("response" in mine) return mine.response;
@@ -1274,6 +1388,20 @@ function createCauthy(given = {}) {
1274
1388
  }
1275
1389
  const b = await body(request);
1276
1390
  if (b === null) return problem(400, "bad_request", "Send the form as JSON.");
1391
+ if (route === "/sign-in/sso/discover") {
1392
+ const bad = checkEmail(b.email);
1393
+ if (bad) return invalid(bad);
1394
+ const res = await ask(request, "POST", "/v1/auth/sso/discover", { email: String(b.email).trim() });
1395
+ if (res.error) return problem(res.status, res.error.code, res.error.message);
1396
+ const c = res.data?.connection;
1397
+ return json(c ? { status: "found", connection: { id: String(c.slug ?? ""), name: String(c.display_name ?? ""), enforced: c.enforced === true } } : { status: "none" });
1398
+ }
1399
+ if (route === "/sign-in/anonymous") {
1400
+ if (!post) return new Response("Method not allowed", { status: 405, headers: { allow: "POST" } });
1401
+ const res = await ask(request, "POST", "/v1/auth/anonymous", {});
1402
+ if (res.error) return problem(res.status, res.error.code, res.error.message);
1403
+ return signedIn(request, res.data);
1404
+ }
1277
1405
  if (route === "/sign-in/email") {
1278
1406
  const bad = firstProblem(checkEmail(b.email), checkPassword(b.password));
1279
1407
  if (bad) return invalid(bad);
@@ -1437,6 +1565,53 @@ function createCauthy(given = {}) {
1437
1565
  if (res.error) return refused(res);
1438
1566
  return json({ status: "removed", id }, 200, mine.headers);
1439
1567
  }
1568
+ if (route === "/me/upgrade") {
1569
+ const bad = firstProblem(checkName(b.name), checkEmail(b.email), checkNewPassword(b.password));
1570
+ if (bad) return invalid(bad);
1571
+ const res = await as("/v1/auth/anonymous/upgrade", { email: String(b.email).trim(), password: b.password, display_name: typeof b.name === "string" ? b.name.trim() : "" });
1572
+ if (res.error) return refused(res, res.error.code === "weak_password" ? "password" : "email");
1573
+ return signedIn(request, res.data);
1574
+ }
1575
+ if (route.startsWith("/me/organizations/members/")) {
1576
+ const org = typeof b.organizationId === "string" ? b.organizationId : "";
1577
+ if (!UUID.test(org)) return problem(400, "invalid_organization", "Say which organization.", void 0, mine.headers);
1578
+ const base = `/v1/auth/me/organizations/${org}/members`;
1579
+ if (route === "/me/organizations/members/add") {
1580
+ const bad = checkEmail(b.email);
1581
+ if (bad) return invalid(bad);
1582
+ const role = typeof b.role === "string" ? b.role : "";
1583
+ if (role === "") return problem(400, "invalid_role", "Choose a role.", "role", mine.headers);
1584
+ const res = await as(base, {
1585
+ email: String(b.email).trim(),
1586
+ role,
1587
+ name: typeof b.name === "string" ? b.name.trim() : "",
1588
+ client_id: clientId,
1589
+ ...typeof b.locale === "string" && b.locale ? { locale: b.locale } : {}
1590
+ });
1591
+ if (res.error) return refused(res, res.error.code === "unknown_role" ? "role" : "email");
1592
+ return json({ status: "added", member: orgMemberOf(res.data) }, 200, mine.headers);
1593
+ }
1594
+ const user = typeof b.userId === "string" ? b.userId : "";
1595
+ if (!UUID.test(user)) return problem(400, "invalid_member", "Say which member.", void 0, mine.headers);
1596
+ if (route === "/me/organizations/members/role") {
1597
+ const role = typeof b.role === "string" ? b.role : "";
1598
+ if (role === "") return problem(400, "invalid_role", "Choose a role.", "role", mine.headers);
1599
+ const res = await as(`${base}/${user}`, { role }, "PUT");
1600
+ if (res.error) return refused(res, "role");
1601
+ return json({ status: "changed", userId: user, role }, 200, mine.headers);
1602
+ }
1603
+ if (route === "/me/organizations/members/remove") {
1604
+ const res = await as(`${base}/${user}`, void 0, "DELETE");
1605
+ if (res.error) return refused(res);
1606
+ orgCache.delete(mine.token);
1607
+ return json({ status: "removed", userId: user }, 200, mine.headers);
1608
+ }
1609
+ if (route === "/me/organizations/members/invite") {
1610
+ const res = await as(`${base}/${user}/invite`, { client_id: clientId, ...typeof b.locale === "string" && b.locale ? { locale: b.locale } : {} });
1611
+ if (res.error) return refused(res);
1612
+ return json({ status: "sent", userId: user }, 200, mine.headers);
1613
+ }
1614
+ }
1440
1615
  if (route === "/me/agents/disconnect") {
1441
1616
  const id = typeof b.id === "string" ? b.id : "";
1442
1617
  if (!/^[0-9a-f-]{36}$/i.test(id)) return problem(400, "invalid_agent", "Say which agent to disconnect.", void 0, mine.headers);