cauthy-auth 0.22.0 → 0.24.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/index.mjs CHANGED
@@ -652,7 +652,6 @@ async function verifyWebhook(request, options = {}) {
652
652
  try {
653
653
  const verified = await jwtVerify(signature, options.jwks ?? keysOf(issuer), {
654
654
  algorithms: ["RS256"],
655
- issuer,
656
655
  audience,
657
656
  typ: "cauthy-webhook+jwt",
658
657
  requiredClaims: ["exp", "iat", "jti", "body_sha256"],
@@ -663,6 +662,9 @@ async function verifyWebhook(request, options = {}) {
663
662
  } catch (err) {
664
663
  throw new CauthyWebhookError(err instanceof Error ? err.message : "bad signature");
665
664
  }
665
+ if (claims.iss !== issuer && claims.domain_iss !== issuer) {
666
+ throw new CauthyWebhookError('unexpected "iss" claim value');
667
+ }
666
668
  const now = Math.floor((options.now ?? /* @__PURE__ */ new Date()).getTime() / 1e3);
667
669
  if (typeof claims.iat !== "number" || claims.iat > now + 30) throw new CauthyWebhookError("signed in the future");
668
670
  const digest = new Uint8Array(await crypto.subtle.digest("SHA-256", raw));
@@ -1143,6 +1145,9 @@ function createCauthy(given = {}) {
1143
1145
  "/me/mfa/phone/remove",
1144
1146
  "/sign-in/mfa/methods",
1145
1147
  "/sign-in/mfa/send",
1148
+ "/sign-in/mfa/push",
1149
+ "/sign-in/mfa/push/events",
1150
+ "/sign-in/mfa/push/finish",
1146
1151
  "/me/sessions",
1147
1152
  "/me/sessions/end",
1148
1153
  "/me/email",
@@ -1372,6 +1377,28 @@ function createCauthy(given = {}) {
1372
1377
  }
1373
1378
  return json({ account: accountOf(res.data) }, 200, mine.headers);
1374
1379
  }
1380
+ if (route === "/sign-in/mfa/push/events" && !post) {
1381
+ const sealed = readCookies(request.headers.get("cookie")).get(stepCookie);
1382
+ const step = sealed ? await unseal(sealed, await key) : null;
1383
+ if (step === null || step.kind !== "mfa") return problem(400, "step_expired", "Sign in again: the code was asked for too long ago.");
1384
+ let upstream;
1385
+ try {
1386
+ upstream = await doFetch(`${issuer}/v1/auth/mfa/push/events`, {
1387
+ headers: { "x-tenant-key": tenant, "x-mfa-token": step.token, accept: "text/event-stream" },
1388
+ signal: request.signal
1389
+ });
1390
+ } catch {
1391
+ return problem(503, "unavailable", "Cauthy could not be reached.");
1392
+ }
1393
+ if (!upstream.ok || !upstream.body) {
1394
+ const b2 = await upstream.json().catch(() => null);
1395
+ return problem(upstream.status, String(b2?.errors?.[0]?.code ?? "error"), String(b2?.errors?.[0]?.message ?? "The request could not be completed."));
1396
+ }
1397
+ return new Response(upstream.body, {
1398
+ status: 200,
1399
+ headers: { "content-type": "text/event-stream", "cache-control": "no-cache, no-store", "x-accel-buffering": "no" }
1400
+ });
1401
+ }
1375
1402
  if (!post) return new Response("Method not allowed", { status: 405, headers: { allow: "POST" } });
1376
1403
  if (!ownRequest(request)) return problem(403, "cross_site", "This request did not come from this application.");
1377
1404
  if (route === "/sign-out") {
@@ -1423,6 +1450,19 @@ function createCauthy(given = {}) {
1423
1450
  if (res.error) return problem(res.status, res.error.code, res.error.message, "code");
1424
1451
  return signedIn(request, res.data, [writeCookie(stepCookie, "", attrs(request, 0))]);
1425
1452
  }
1453
+ if (route === "/sign-in/mfa/push" || route === "/sign-in/mfa/push/finish") {
1454
+ const sealed = readCookies(request.headers.get("cookie")).get(stepCookie);
1455
+ const step = sealed ? await unseal(sealed, await key) : null;
1456
+ if (step === null || step.kind !== "mfa") return problem(400, "step_expired", "Sign in again: the code was asked for too long ago.");
1457
+ if (route === "/sign-in/mfa/push") {
1458
+ const res2 = await ask(request, "POST", "/v1/auth/mfa/push", { mfa_token: step.token });
1459
+ if (res2.error) return problem(res2.status, res2.error.code, res2.error.message);
1460
+ return json({ status: "sent", number: Number(res2.data?.number ?? 0) });
1461
+ }
1462
+ const res = await ask(request, "POST", "/v1/auth/mfa/challenge", { mfa_token: step.token, push: true });
1463
+ if (res.error) return problem(res.status, res.error.code, res.error.message);
1464
+ return signedIn(request, res.data, [writeCookie(stepCookie, "", attrs(request, 0))]);
1465
+ }
1426
1466
  if (route === "/sign-in/mfa/methods" || route === "/sign-in/mfa/send") {
1427
1467
  const sealed = readCookies(request.headers.get("cookie")).get(stepCookie);
1428
1468
  const step = sealed ? await unseal(sealed, await key) : null;
@@ -1431,7 +1471,13 @@ function createCauthy(given = {}) {
1431
1471
  const res2 = await ask(request, "POST", "/v1/auth/mfa/methods", { mfa_token: step.token });
1432
1472
  if (res2.error) return problem(res2.status, res2.error.code, res2.error.message);
1433
1473
  const p = res2.data?.phone;
1434
- return json({ status: "ok", totp: res2.data?.totp === true, phone: p ? { number: String(p.number ?? ""), channel: String(p.channel ?? "sms") } : null });
1474
+ const push = res2.data?.push;
1475
+ return json({
1476
+ status: "ok",
1477
+ totp: res2.data?.totp === true,
1478
+ phone: p ? { number: String(p.number ?? ""), channel: String(p.channel ?? "sms") } : null,
1479
+ push: push ? { devices: Number(push.devices ?? 0) } : null
1480
+ });
1435
1481
  }
1436
1482
  const res = await ask(request, "POST", "/v1/auth/mfa/send", { mfa_token: step.token });
1437
1483
  if (res.error) return problem(res.status, res.error.code, res.error.message);