hazo_auth 10.4.10 → 10.4.13
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/README.md +4 -0
- package/SETUP_CHECKLIST.md +2 -1
- package/cli-src/cli/generate.ts +4 -0
- package/cli-src/cli/validate.ts +45 -0
- package/cli-src/lib/oauth_preflight.server.ts +29 -2
- package/cli-src/lib/validate_session_secret.server.ts +83 -0
- package/dist/cli/generate.d.ts.map +1 -1
- package/dist/cli/generate.js +4 -0
- package/dist/cli/validate.d.ts.map +1 -1
- package/dist/cli/validate.js +43 -0
- package/dist/lib/oauth_preflight.server.d.ts.map +1 -1
- package/dist/lib/oauth_preflight.server.js +32 -3
- package/dist/lib/validate_session_secret.server.d.ts +20 -0
- package/dist/lib/validate_session_secret.server.d.ts.map +1 -0
- package/dist/lib/validate_session_secret.server.js +72 -0
- package/dist/server/routes/user_management_users.d.ts +1 -1
- package/dist/server-lib.d.ts +1 -0
- package/dist/server-lib.d.ts.map +1 -1
- package/dist/server-lib.js +1 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
A reusable authentication UI component package powered by Next.js, TailwindCSS, and shadcn. It integrates `hazo_config` for configuration management and `hazo_connect` for data access, enabling future components to stay aligned with platform conventions.
|
|
4
4
|
|
|
5
|
+
### What's New in v10.4.13
|
|
6
|
+
|
|
7
|
+
- **`validate_session_secret_config()`** exported from `hazo_auth/server-lib` — hard startup validator that throws `HazoConfigError` (code `HAZO_AUTH_CONFIG`) when `JWT_SECRET` is unset or shorter than 32 chars. Call it from a Next.js `instrumentation.ts` `register()` hook to fail boot loudly instead of hitting the silent split-brain a bad/missing secret otherwise causes (edge proxy bounces to `/login` while server-side auth falls back to unsigned cookies and still considers the user authenticated).
|
|
8
|
+
|
|
5
9
|
### What's New in v10.4.5
|
|
6
10
|
|
|
7
11
|
- **Pre-fill login credentials** — `LoginPage`, `LoginClientWrapper`, and `LoginLayout` now accept a `default_values` / `defaultValues` prop (`{ email?: string; password?: string }`) to pre-populate the login form. Useful for demo and test environments (gate with `process.env.DEMO_EMAIL` etc.).
|
package/SETUP_CHECKLIST.md
CHANGED
|
@@ -424,9 +424,10 @@ from_name = Your App Name
|
|
|
424
424
|
**Checklist:**
|
|
425
425
|
- [ ] `.env.local` file created
|
|
426
426
|
- [ ] `HAZO_AUTH_COOKIE_PREFIX` set (REQUIRED - must match config file)
|
|
427
|
-
- [ ] `JWT_SECRET` set (required for JWT session tokens)
|
|
427
|
+
- [ ] `JWT_SECRET` set (required for JWT session tokens, >= 32 chars)
|
|
428
428
|
- [ ] `ZEPTOMAIL_API_KEY` set (or email will not work)
|
|
429
429
|
- [ ] `from_email` configured in `hazo_notify_config.ini`
|
|
430
|
+
- [ ] Call `validate_session_secret_config()` (from `hazo_auth/server-lib`) in your `instrumentation.ts` `register()` hook — hard-fails boot with a descriptive banner if `JWT_SECRET` is missing or too short, instead of the silent split-brain (logged-in on `/login` but bounced on every protected route) that a bad secret otherwise causes.
|
|
430
431
|
|
|
431
432
|
---
|
|
432
433
|
|
package/cli-src/cli/generate.ts
CHANGED
|
@@ -64,6 +64,10 @@ const ROUTES: RouteDefinition[] = [
|
|
|
64
64
|
{ name: "nextauth_post", path: "api/auth/[...nextauth]", method: "POST", export_name: "nextauthPOST" },
|
|
65
65
|
{ name: "oauth_google_callback", path: "api/hazo_auth/oauth/google/callback", method: "GET", export_name: "oauthGoogleCallbackGET" },
|
|
66
66
|
{ name: "set_password", path: "api/hazo_auth/set_password", method: "POST", export_name: "setPasswordPOST" },
|
|
67
|
+
// Static assets (default auth-page images served from the package's dist/assets/images).
|
|
68
|
+
// Without this route the default image_src (/api/hazo_auth/assets/login_default.jpg) 404s
|
|
69
|
+
// and login/register/etc. render with an empty image panel.
|
|
70
|
+
{ name: "assets", path: "api/hazo_auth/assets/[name]", method: "GET", export_name: "assetGET" },
|
|
67
71
|
];
|
|
68
72
|
|
|
69
73
|
const PAGES: PageDefinition[] = [
|
package/cli-src/cli/validate.ts
CHANGED
|
@@ -310,6 +310,43 @@ function check_env_vars(): CheckResult[] {
|
|
|
310
310
|
const GOOGLE_NEXTAUTH_CALLBACK_PATH = "/api/auth/callback/google";
|
|
311
311
|
const FACEBOOK_NEXTAUTH_CALLBACK_PATH = "/api/auth/callback/facebook";
|
|
312
312
|
|
|
313
|
+
/**
|
|
314
|
+
* The edge proxy (Edge Runtime, no filesystem) reads the cookie prefix from the
|
|
315
|
+
* HAZO_AUTH_COOKIE_PREFIX env var, while the server reads cookie_prefix from the
|
|
316
|
+
* ini. If they differ — or the env var is unset — the edge gate can't find the
|
|
317
|
+
* session cookie and silently bounces authenticated users back to /login. This
|
|
318
|
+
* check catches that split before it wastes an afternoon.
|
|
319
|
+
*/
|
|
320
|
+
function check_cookie_prefix(project_root: string): CheckResult[] {
|
|
321
|
+
const hazo_config = read_ini_file(path.join(project_root, "config", "hazo_auth_config.ini"));
|
|
322
|
+
const ini_prefix = (hazo_config?.["hazo_auth__cookies"]?.["cookie_prefix"] ?? "").trim();
|
|
323
|
+
const env_prefix = (process.env.HAZO_AUTH_COOKIE_PREFIX ?? "").trim();
|
|
324
|
+
|
|
325
|
+
if (!ini_prefix) {
|
|
326
|
+
// Already reported as a fail by check_config_values; nothing to compare.
|
|
327
|
+
return [];
|
|
328
|
+
}
|
|
329
|
+
if (!env_prefix) {
|
|
330
|
+
return [
|
|
331
|
+
{
|
|
332
|
+
name: "Cookie prefix (env ↔ ini)",
|
|
333
|
+
status: "fail",
|
|
334
|
+
message: `HAZO_AUTH_COOKIE_PREFIX env var not set. The edge proxy throws without it and bounces authenticated users to /login. Set HAZO_AUTH_COOKIE_PREFIX=${ini_prefix} to match cookie_prefix in hazo_auth_config.ini.`,
|
|
335
|
+
},
|
|
336
|
+
];
|
|
337
|
+
}
|
|
338
|
+
if (env_prefix !== ini_prefix) {
|
|
339
|
+
return [
|
|
340
|
+
{
|
|
341
|
+
name: "Cookie prefix (env ↔ ini)",
|
|
342
|
+
status: "fail",
|
|
343
|
+
message: `Mismatch: HAZO_AUTH_COOKIE_PREFIX="${env_prefix}" but ini cookie_prefix="${ini_prefix}". They must be identical or the edge gate can't find the session cookie. Make them equal.`,
|
|
344
|
+
},
|
|
345
|
+
];
|
|
346
|
+
}
|
|
347
|
+
return [{ name: "Cookie prefix (env ↔ ini)", status: "pass", message: `"${env_prefix}" (matches)` }];
|
|
348
|
+
}
|
|
349
|
+
|
|
313
350
|
function read_oauth_origin(): { origin: string; resolved: boolean } {
|
|
314
351
|
const nextauth_url = process.env.NEXTAUTH_URL;
|
|
315
352
|
if (nextauth_url && nextauth_url.trim().length > 0) {
|
|
@@ -850,6 +887,14 @@ export function run_validation(): ValidationSummary {
|
|
|
850
887
|
all_results.push(...env_results);
|
|
851
888
|
console.log();
|
|
852
889
|
|
|
890
|
+
const cookie_prefix_results = check_cookie_prefix(project_root);
|
|
891
|
+
if (cookie_prefix_results.length > 0) {
|
|
892
|
+
console.log("\x1b[1m🍪 Cookie Prefix\x1b[0m");
|
|
893
|
+
cookie_prefix_results.forEach(print_result);
|
|
894
|
+
all_results.push(...cookie_prefix_results);
|
|
895
|
+
console.log();
|
|
896
|
+
}
|
|
897
|
+
|
|
853
898
|
console.log("\x1b[1m🔑 OAuth Providers\x1b[0m");
|
|
854
899
|
const oauth_results = check_oauth(project_root);
|
|
855
900
|
oauth_results.forEach(print_result);
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import "server-only";
|
|
4
4
|
|
|
5
5
|
import { get_oauth_config } from "./oauth_config.server.js";
|
|
6
|
+
import { get_cookies_config } from "./cookies_config.server.js";
|
|
6
7
|
import { googleRedirectUri, facebookRedirectUri } from "./oauth_routes.js";
|
|
7
8
|
import { create_app_logger } from "./app_logger.js";
|
|
8
9
|
|
|
@@ -49,6 +50,30 @@ export function getOAuthPreflightReport(): OAuthPreflightReport {
|
|
|
49
50
|
const oauth = get_oauth_config();
|
|
50
51
|
const redirectUris: OAuthPreflightReport["redirectUris"] = [];
|
|
51
52
|
|
|
53
|
+
// Cookie prefix: env (read by the edge proxy) must match the ini (read by the
|
|
54
|
+
// server). A mismatch — or an unset env var — makes the edge gate throw and
|
|
55
|
+
// silently bounce authenticated users to /login.
|
|
56
|
+
try {
|
|
57
|
+
const ini_prefix = (get_cookies_config().cookie_prefix ?? "").trim();
|
|
58
|
+
const env_prefix = (process.env.HAZO_AUTH_COOKIE_PREFIX ?? "").trim();
|
|
59
|
+
if (ini_prefix && !env_prefix) {
|
|
60
|
+
checks.push({
|
|
61
|
+
name: "Cookie prefix",
|
|
62
|
+
status: "fail",
|
|
63
|
+
message: `HAZO_AUTH_COOKIE_PREFIX env var not set. The edge proxy throws without it and bounces authenticated users to /login. Set HAZO_AUTH_COOKIE_PREFIX=${ini_prefix} (matching cookie_prefix in hazo_auth_config.ini).`,
|
|
64
|
+
});
|
|
65
|
+
} else if (ini_prefix && env_prefix && env_prefix !== ini_prefix) {
|
|
66
|
+
checks.push({
|
|
67
|
+
name: "Cookie prefix",
|
|
68
|
+
status: "fail",
|
|
69
|
+
message: `Mismatch: HAZO_AUTH_COOKIE_PREFIX="${env_prefix}" vs ini cookie_prefix="${ini_prefix}". They must be identical or the edge gate can't find the session cookie.`,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
} catch {
|
|
73
|
+
// get_cookies_config throws when cookie_prefix is absent from the ini; that
|
|
74
|
+
// missing-config case is reported elsewhere (validate CLI / server boot).
|
|
75
|
+
}
|
|
76
|
+
|
|
52
77
|
// NEXTAUTH_URL — the source of the redirect URI.
|
|
53
78
|
if (resolved) {
|
|
54
79
|
checks.push({ name: "NEXTAUTH_URL", status: "pass", message: origin });
|
|
@@ -152,10 +177,10 @@ export function logOAuthPreflight(): OAuthPreflightReport | null {
|
|
|
152
177
|
_logged_once = true;
|
|
153
178
|
|
|
154
179
|
const report = getOAuthPreflightReport();
|
|
155
|
-
if (report.redirectUris.length === 0) return report; // No OAuth providers enabled.
|
|
156
|
-
|
|
157
180
|
const logger = create_app_logger();
|
|
158
181
|
|
|
182
|
+
// Always surface failing/warning checks (e.g. cookie-prefix mismatch), even
|
|
183
|
+
// when no OAuth provider is enabled and there are no redirect URIs to print.
|
|
159
184
|
for (const check of report.checks) {
|
|
160
185
|
if (check.status === "fail") {
|
|
161
186
|
logger.error("oauth_preflight_check_failed", { check: check.name, detail: check.message });
|
|
@@ -164,6 +189,8 @@ export function logOAuthPreflight(): OAuthPreflightReport | null {
|
|
|
164
189
|
}
|
|
165
190
|
}
|
|
166
191
|
|
|
192
|
+
if (report.redirectUris.length === 0) return report; // No OAuth providers — nothing to register.
|
|
193
|
+
|
|
167
194
|
// Highlighted, copy-pasteable block — the single thing that prevents
|
|
168
195
|
// redirect_uri_mismatch. console (not logger) so it renders verbatim.
|
|
169
196
|
const lines: string[] = [
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// file_description: startup validator for the JWT session signing secret — hard-fails boot with a descriptive banner if JWT_SECRET is missing or too short
|
|
2
|
+
// section: server-only-guard
|
|
3
|
+
import "server-only";
|
|
4
|
+
|
|
5
|
+
// section: imports
|
|
6
|
+
import { HazoConfigError } from "hazo_core";
|
|
7
|
+
|
|
8
|
+
// section: constants
|
|
9
|
+
/**
|
|
10
|
+
* Minimum acceptable length for JWT_SECRET. jose/HS256 accepts shorter keys,
|
|
11
|
+
* but anything under 32 chars is trivially brute-forceable for a session
|
|
12
|
+
* signing secret. Matches the threshold the validate CLI enforces.
|
|
13
|
+
*/
|
|
14
|
+
const MIN_JWT_SECRET_LEN = 32;
|
|
15
|
+
|
|
16
|
+
// section: validate
|
|
17
|
+
/**
|
|
18
|
+
* Validates the JWT session signing secret at startup.
|
|
19
|
+
*
|
|
20
|
+
* Throws HazoConfigError with a descriptive banner if JWT_SECRET is unset or
|
|
21
|
+
* shorter than 32 chars. Call this in your instrumentation `register()` hook to
|
|
22
|
+
* hard-fail boot instead of the silent failure mode it otherwise causes:
|
|
23
|
+
*
|
|
24
|
+
* - The edge proxy validator (`validate_session_cookie`) returns
|
|
25
|
+
* `{ valid: false }` when JWT_SECRET is missing → logged-in users get
|
|
26
|
+
* bounced to /login.
|
|
27
|
+
* - The server resolver (`hazo_get_auth`) falls back to unsigned simple
|
|
28
|
+
* cookies and considers the same user authenticated.
|
|
29
|
+
*
|
|
30
|
+
* The two disagree, so the app looks "logged in" on the login page yet bounces
|
|
31
|
+
* on every protected route. Failing at boot turns that silent split-brain into
|
|
32
|
+
* an obvious, actionable error.
|
|
33
|
+
*/
|
|
34
|
+
export function validate_session_secret_config(): void {
|
|
35
|
+
const jwt_secret = process.env.JWT_SECRET;
|
|
36
|
+
|
|
37
|
+
if (!jwt_secret || jwt_secret.trim().length === 0) {
|
|
38
|
+
console.error("=".repeat(60));
|
|
39
|
+
console.error("FATAL: JWT_SECRET is not set");
|
|
40
|
+
console.error("=".repeat(60));
|
|
41
|
+
console.error("hazo_auth signs session cookies with JWT_SECRET. Without it:");
|
|
42
|
+
console.error(" - the edge proxy rejects every session and bounces");
|
|
43
|
+
console.error(" logged-in users to /login;");
|
|
44
|
+
console.error(" - server-side auth silently falls back to unsigned");
|
|
45
|
+
console.error(" cookies, so the app looks logged in but every");
|
|
46
|
+
console.error(" protected route bounces.");
|
|
47
|
+
console.error("");
|
|
48
|
+
console.error("Fix — add to .env.local:");
|
|
49
|
+
console.error(" JWT_SECRET=<random string, at least 32 chars>");
|
|
50
|
+
console.error("Generate one:");
|
|
51
|
+
console.error(" node -e \"console.log(require('crypto').randomBytes(32).toString('base64'))\"");
|
|
52
|
+
console.error("=".repeat(60));
|
|
53
|
+
|
|
54
|
+
throw new HazoConfigError({
|
|
55
|
+
code: "HAZO_AUTH_CONFIG",
|
|
56
|
+
pkg: "hazo_auth",
|
|
57
|
+
message:
|
|
58
|
+
"JWT_SECRET environment variable is required to sign session cookies. " +
|
|
59
|
+
"Without it the edge proxy bounces authenticated users to /login while " +
|
|
60
|
+
"server-side auth falls back to unsigned cookies. Set JWT_SECRET (>= 32 chars) in .env.local.",
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (jwt_secret.trim().length < MIN_JWT_SECRET_LEN) {
|
|
65
|
+
console.error("=".repeat(60));
|
|
66
|
+
console.error("FATAL: JWT_SECRET is too short");
|
|
67
|
+
console.error("=".repeat(60));
|
|
68
|
+
console.error(
|
|
69
|
+
`JWT_SECRET is ${jwt_secret.trim().length} chars; at least ${MIN_JWT_SECRET_LEN} are required.`,
|
|
70
|
+
);
|
|
71
|
+
console.error("Generate a strong one:");
|
|
72
|
+
console.error(" node -e \"console.log(require('crypto').randomBytes(32).toString('base64'))\"");
|
|
73
|
+
console.error("=".repeat(60));
|
|
74
|
+
|
|
75
|
+
throw new HazoConfigError({
|
|
76
|
+
code: "HAZO_AUTH_CONFIG",
|
|
77
|
+
pkg: "hazo_auth",
|
|
78
|
+
message:
|
|
79
|
+
`JWT_SECRET is too short (${jwt_secret.trim().length} chars). ` +
|
|
80
|
+
`Use at least ${MIN_JWT_SECRET_LEN} characters for the session signing secret.`,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../src/cli/generate.ts"],"names":[],"mappings":"AAqBA,MAAM,MAAM,eAAe,GAAG;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,GAAG,CAAC,EAAE,OAAO,CAAC;CACf,CAAC;
|
|
1
|
+
{"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../src/cli/generate.ts"],"names":[],"mappings":"AAqBA,MAAM,MAAM,eAAe,GAAG;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,GAAG,CAAC,EAAE,OAAO,CAAC;CACf,CAAC;AAqMF,wBAAgB,eAAe,CAAC,OAAO,GAAE,eAAoB,GAAG,IAAI,CA8DnE"}
|
package/dist/cli/generate.js
CHANGED
|
@@ -41,6 +41,10 @@ const ROUTES = [
|
|
|
41
41
|
{ name: "nextauth_post", path: "api/auth/[...nextauth]", method: "POST", export_name: "nextauthPOST" },
|
|
42
42
|
{ name: "oauth_google_callback", path: "api/hazo_auth/oauth/google/callback", method: "GET", export_name: "oauthGoogleCallbackGET" },
|
|
43
43
|
{ name: "set_password", path: "api/hazo_auth/set_password", method: "POST", export_name: "setPasswordPOST" },
|
|
44
|
+
// Static assets (default auth-page images served from the package's dist/assets/images).
|
|
45
|
+
// Without this route the default image_src (/api/hazo_auth/assets/login_default.jpg) 404s
|
|
46
|
+
// and login/register/etc. render with an empty image panel.
|
|
47
|
+
{ name: "assets", path: "api/hazo_auth/assets/[name]", method: "GET", export_name: "assetGET" },
|
|
44
48
|
];
|
|
45
49
|
const PAGES = [
|
|
46
50
|
{ name: "login", path: "hazo_auth/login", component_name: "LoginPage", import_path: "hazo_auth/pages/login" },
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/cli/validate.ts"],"names":[],"mappings":"AAOA,KAAK,WAAW,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAE5C,KAAK,WAAW,GAAG;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,WAAW,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,WAAW,EAAE,CAAC;CACxB,CAAC;
|
|
1
|
+
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/cli/validate.ts"],"names":[],"mappings":"AAOA,KAAK,WAAW,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAE5C,KAAK,WAAW,GAAG;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,WAAW,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,WAAW,EAAE,CAAC;CACxB,CAAC;AA20BF,wBAAgB,cAAc,IAAI,iBAAiB,CA8FlD"}
|
package/dist/cli/validate.js
CHANGED
|
@@ -272,6 +272,42 @@ function check_env_vars() {
|
|
|
272
272
|
// compiles as an isolated tree and must not import the server-only lib.
|
|
273
273
|
const GOOGLE_NEXTAUTH_CALLBACK_PATH = "/api/auth/callback/google";
|
|
274
274
|
const FACEBOOK_NEXTAUTH_CALLBACK_PATH = "/api/auth/callback/facebook";
|
|
275
|
+
/**
|
|
276
|
+
* The edge proxy (Edge Runtime, no filesystem) reads the cookie prefix from the
|
|
277
|
+
* HAZO_AUTH_COOKIE_PREFIX env var, while the server reads cookie_prefix from the
|
|
278
|
+
* ini. If they differ — or the env var is unset — the edge gate can't find the
|
|
279
|
+
* session cookie and silently bounces authenticated users back to /login. This
|
|
280
|
+
* check catches that split before it wastes an afternoon.
|
|
281
|
+
*/
|
|
282
|
+
function check_cookie_prefix(project_root) {
|
|
283
|
+
var _a, _b, _c;
|
|
284
|
+
const hazo_config = read_ini_file(path.join(project_root, "config", "hazo_auth_config.ini"));
|
|
285
|
+
const ini_prefix = ((_b = (_a = hazo_config === null || hazo_config === void 0 ? void 0 : hazo_config["hazo_auth__cookies"]) === null || _a === void 0 ? void 0 : _a["cookie_prefix"]) !== null && _b !== void 0 ? _b : "").trim();
|
|
286
|
+
const env_prefix = ((_c = process.env.HAZO_AUTH_COOKIE_PREFIX) !== null && _c !== void 0 ? _c : "").trim();
|
|
287
|
+
if (!ini_prefix) {
|
|
288
|
+
// Already reported as a fail by check_config_values; nothing to compare.
|
|
289
|
+
return [];
|
|
290
|
+
}
|
|
291
|
+
if (!env_prefix) {
|
|
292
|
+
return [
|
|
293
|
+
{
|
|
294
|
+
name: "Cookie prefix (env ↔ ini)",
|
|
295
|
+
status: "fail",
|
|
296
|
+
message: `HAZO_AUTH_COOKIE_PREFIX env var not set. The edge proxy throws without it and bounces authenticated users to /login. Set HAZO_AUTH_COOKIE_PREFIX=${ini_prefix} to match cookie_prefix in hazo_auth_config.ini.`,
|
|
297
|
+
},
|
|
298
|
+
];
|
|
299
|
+
}
|
|
300
|
+
if (env_prefix !== ini_prefix) {
|
|
301
|
+
return [
|
|
302
|
+
{
|
|
303
|
+
name: "Cookie prefix (env ↔ ini)",
|
|
304
|
+
status: "fail",
|
|
305
|
+
message: `Mismatch: HAZO_AUTH_COOKIE_PREFIX="${env_prefix}" but ini cookie_prefix="${ini_prefix}". They must be identical or the edge gate can't find the session cookie. Make them equal.`,
|
|
306
|
+
},
|
|
307
|
+
];
|
|
308
|
+
}
|
|
309
|
+
return [{ name: "Cookie prefix (env ↔ ini)", status: "pass", message: `"${env_prefix}" (matches)` }];
|
|
310
|
+
}
|
|
275
311
|
function read_oauth_origin() {
|
|
276
312
|
var _a;
|
|
277
313
|
const nextauth_url = process.env.NEXTAUTH_URL;
|
|
@@ -781,6 +817,13 @@ export function run_validation() {
|
|
|
781
817
|
env_results.forEach(print_result);
|
|
782
818
|
all_results.push(...env_results);
|
|
783
819
|
console.log();
|
|
820
|
+
const cookie_prefix_results = check_cookie_prefix(project_root);
|
|
821
|
+
if (cookie_prefix_results.length > 0) {
|
|
822
|
+
console.log("\x1b[1m🍪 Cookie Prefix\x1b[0m");
|
|
823
|
+
cookie_prefix_results.forEach(print_result);
|
|
824
|
+
all_results.push(...cookie_prefix_results);
|
|
825
|
+
console.log();
|
|
826
|
+
}
|
|
784
827
|
console.log("\x1b[1m🔑 OAuth Providers\x1b[0m");
|
|
785
828
|
const oauth_results = check_oauth(project_root);
|
|
786
829
|
oauth_results.forEach(print_result);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oauth_preflight.server.d.ts","sourceRoot":"","sources":["../../src/lib/oauth_preflight.server.ts"],"names":[],"mappings":"AAEA,OAAO,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"oauth_preflight.server.d.ts","sourceRoot":"","sources":["../../src/lib/oauth_preflight.server.ts"],"names":[],"mappings":"AAEA,OAAO,aAAa,CAAC;AAQrB,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAEvD,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,eAAe,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,yEAAyE;IACzE,MAAM,EAAE,MAAM,CAAC;IACf,wEAAwE;IACxE,cAAc,EAAE,OAAO,CAAC;IACxB,uFAAuF;IACvF,YAAY,EAAE;QAAE,QAAQ,EAAE,QAAQ,GAAG,UAAU,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACjE,MAAM,EAAE,cAAc,EAAE,CAAC;CAC1B,CAAC;AAeF;;;;GAIG;AACH,wBAAgB,uBAAuB,IAAI,oBAAoB,CAmH9D;AAKD;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,IAAI,oBAAoB,GAAG,IAAI,CAwC/D"}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// redirect URIs to register, killing the recurring `redirect_uri_mismatch` for new apps.
|
|
3
3
|
import "server-only";
|
|
4
4
|
import { get_oauth_config } from "./oauth_config.server.js";
|
|
5
|
+
import { get_cookies_config } from "./cookies_config.server.js";
|
|
5
6
|
import { googleRedirectUri, facebookRedirectUri } from "./oauth_routes.js";
|
|
6
7
|
import { create_app_logger } from "./app_logger.js";
|
|
7
8
|
// section: helpers
|
|
@@ -22,10 +23,36 @@ function resolve_origin() {
|
|
|
22
23
|
* no DB or network access.
|
|
23
24
|
*/
|
|
24
25
|
export function getOAuthPreflightReport() {
|
|
26
|
+
var _a, _b;
|
|
25
27
|
const checks = [];
|
|
26
28
|
const { origin, resolved } = resolve_origin();
|
|
27
29
|
const oauth = get_oauth_config();
|
|
28
30
|
const redirectUris = [];
|
|
31
|
+
// Cookie prefix: env (read by the edge proxy) must match the ini (read by the
|
|
32
|
+
// server). A mismatch — or an unset env var — makes the edge gate throw and
|
|
33
|
+
// silently bounce authenticated users to /login.
|
|
34
|
+
try {
|
|
35
|
+
const ini_prefix = ((_a = get_cookies_config().cookie_prefix) !== null && _a !== void 0 ? _a : "").trim();
|
|
36
|
+
const env_prefix = ((_b = process.env.HAZO_AUTH_COOKIE_PREFIX) !== null && _b !== void 0 ? _b : "").trim();
|
|
37
|
+
if (ini_prefix && !env_prefix) {
|
|
38
|
+
checks.push({
|
|
39
|
+
name: "Cookie prefix",
|
|
40
|
+
status: "fail",
|
|
41
|
+
message: `HAZO_AUTH_COOKIE_PREFIX env var not set. The edge proxy throws without it and bounces authenticated users to /login. Set HAZO_AUTH_COOKIE_PREFIX=${ini_prefix} (matching cookie_prefix in hazo_auth_config.ini).`,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
else if (ini_prefix && env_prefix && env_prefix !== ini_prefix) {
|
|
45
|
+
checks.push({
|
|
46
|
+
name: "Cookie prefix",
|
|
47
|
+
status: "fail",
|
|
48
|
+
message: `Mismatch: HAZO_AUTH_COOKIE_PREFIX="${env_prefix}" vs ini cookie_prefix="${ini_prefix}". They must be identical or the edge gate can't find the session cookie.`,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
catch (_c) {
|
|
53
|
+
// get_cookies_config throws when cookie_prefix is absent from the ini; that
|
|
54
|
+
// missing-config case is reported elsewhere (validate CLI / server boot).
|
|
55
|
+
}
|
|
29
56
|
// NEXTAUTH_URL — the source of the redirect URI.
|
|
30
57
|
if (resolved) {
|
|
31
58
|
checks.push({ name: "NEXTAUTH_URL", status: "pass", message: origin });
|
|
@@ -45,7 +72,7 @@ export function getOAuthPreflightReport() {
|
|
|
45
72
|
const u = new URL(origin);
|
|
46
73
|
url_port = u.port || (u.protocol === "https:" ? "443" : "80");
|
|
47
74
|
}
|
|
48
|
-
catch (
|
|
75
|
+
catch (_d) {
|
|
49
76
|
url_port = null;
|
|
50
77
|
}
|
|
51
78
|
if (url_port && url_port !== declared_port) {
|
|
@@ -128,9 +155,9 @@ export function logOAuthPreflight() {
|
|
|
128
155
|
return null;
|
|
129
156
|
_logged_once = true;
|
|
130
157
|
const report = getOAuthPreflightReport();
|
|
131
|
-
if (report.redirectUris.length === 0)
|
|
132
|
-
return report; // No OAuth providers enabled.
|
|
133
158
|
const logger = create_app_logger();
|
|
159
|
+
// Always surface failing/warning checks (e.g. cookie-prefix mismatch), even
|
|
160
|
+
// when no OAuth provider is enabled and there are no redirect URIs to print.
|
|
134
161
|
for (const check of report.checks) {
|
|
135
162
|
if (check.status === "fail") {
|
|
136
163
|
logger.error("oauth_preflight_check_failed", { check: check.name, detail: check.message });
|
|
@@ -139,6 +166,8 @@ export function logOAuthPreflight() {
|
|
|
139
166
|
logger.warn("oauth_preflight_check_warning", { check: check.name, detail: check.message });
|
|
140
167
|
}
|
|
141
168
|
}
|
|
169
|
+
if (report.redirectUris.length === 0)
|
|
170
|
+
return report; // No OAuth providers — nothing to register.
|
|
142
171
|
// Highlighted, copy-pasteable block — the single thing that prevents
|
|
143
172
|
// redirect_uri_mismatch. console (not logger) so it renders verbatim.
|
|
144
173
|
const lines = [
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import "server-only";
|
|
2
|
+
/**
|
|
3
|
+
* Validates the JWT session signing secret at startup.
|
|
4
|
+
*
|
|
5
|
+
* Throws HazoConfigError with a descriptive banner if JWT_SECRET is unset or
|
|
6
|
+
* shorter than 32 chars. Call this in your instrumentation `register()` hook to
|
|
7
|
+
* hard-fail boot instead of the silent failure mode it otherwise causes:
|
|
8
|
+
*
|
|
9
|
+
* - The edge proxy validator (`validate_session_cookie`) returns
|
|
10
|
+
* `{ valid: false }` when JWT_SECRET is missing → logged-in users get
|
|
11
|
+
* bounced to /login.
|
|
12
|
+
* - The server resolver (`hazo_get_auth`) falls back to unsigned simple
|
|
13
|
+
* cookies and considers the same user authenticated.
|
|
14
|
+
*
|
|
15
|
+
* The two disagree, so the app looks "logged in" on the login page yet bounces
|
|
16
|
+
* on every protected route. Failing at boot turns that silent split-brain into
|
|
17
|
+
* an obvious, actionable error.
|
|
18
|
+
*/
|
|
19
|
+
export declare function validate_session_secret_config(): void;
|
|
20
|
+
//# sourceMappingURL=validate_session_secret.server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate_session_secret.server.d.ts","sourceRoot":"","sources":["../../src/lib/validate_session_secret.server.ts"],"names":[],"mappings":"AAEA,OAAO,aAAa,CAAC;AAcrB;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,8BAA8B,IAAI,IAAI,CAiDrD"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// file_description: startup validator for the JWT session signing secret — hard-fails boot with a descriptive banner if JWT_SECRET is missing or too short
|
|
2
|
+
// section: server-only-guard
|
|
3
|
+
import "server-only";
|
|
4
|
+
// section: imports
|
|
5
|
+
import { HazoConfigError } from "hazo_core";
|
|
6
|
+
// section: constants
|
|
7
|
+
/**
|
|
8
|
+
* Minimum acceptable length for JWT_SECRET. jose/HS256 accepts shorter keys,
|
|
9
|
+
* but anything under 32 chars is trivially brute-forceable for a session
|
|
10
|
+
* signing secret. Matches the threshold the validate CLI enforces.
|
|
11
|
+
*/
|
|
12
|
+
const MIN_JWT_SECRET_LEN = 32;
|
|
13
|
+
// section: validate
|
|
14
|
+
/**
|
|
15
|
+
* Validates the JWT session signing secret at startup.
|
|
16
|
+
*
|
|
17
|
+
* Throws HazoConfigError with a descriptive banner if JWT_SECRET is unset or
|
|
18
|
+
* shorter than 32 chars. Call this in your instrumentation `register()` hook to
|
|
19
|
+
* hard-fail boot instead of the silent failure mode it otherwise causes:
|
|
20
|
+
*
|
|
21
|
+
* - The edge proxy validator (`validate_session_cookie`) returns
|
|
22
|
+
* `{ valid: false }` when JWT_SECRET is missing → logged-in users get
|
|
23
|
+
* bounced to /login.
|
|
24
|
+
* - The server resolver (`hazo_get_auth`) falls back to unsigned simple
|
|
25
|
+
* cookies and considers the same user authenticated.
|
|
26
|
+
*
|
|
27
|
+
* The two disagree, so the app looks "logged in" on the login page yet bounces
|
|
28
|
+
* on every protected route. Failing at boot turns that silent split-brain into
|
|
29
|
+
* an obvious, actionable error.
|
|
30
|
+
*/
|
|
31
|
+
export function validate_session_secret_config() {
|
|
32
|
+
const jwt_secret = process.env.JWT_SECRET;
|
|
33
|
+
if (!jwt_secret || jwt_secret.trim().length === 0) {
|
|
34
|
+
console.error("=".repeat(60));
|
|
35
|
+
console.error("FATAL: JWT_SECRET is not set");
|
|
36
|
+
console.error("=".repeat(60));
|
|
37
|
+
console.error("hazo_auth signs session cookies with JWT_SECRET. Without it:");
|
|
38
|
+
console.error(" - the edge proxy rejects every session and bounces");
|
|
39
|
+
console.error(" logged-in users to /login;");
|
|
40
|
+
console.error(" - server-side auth silently falls back to unsigned");
|
|
41
|
+
console.error(" cookies, so the app looks logged in but every");
|
|
42
|
+
console.error(" protected route bounces.");
|
|
43
|
+
console.error("");
|
|
44
|
+
console.error("Fix — add to .env.local:");
|
|
45
|
+
console.error(" JWT_SECRET=<random string, at least 32 chars>");
|
|
46
|
+
console.error("Generate one:");
|
|
47
|
+
console.error(" node -e \"console.log(require('crypto').randomBytes(32).toString('base64'))\"");
|
|
48
|
+
console.error("=".repeat(60));
|
|
49
|
+
throw new HazoConfigError({
|
|
50
|
+
code: "HAZO_AUTH_CONFIG",
|
|
51
|
+
pkg: "hazo_auth",
|
|
52
|
+
message: "JWT_SECRET environment variable is required to sign session cookies. " +
|
|
53
|
+
"Without it the edge proxy bounces authenticated users to /login while " +
|
|
54
|
+
"server-side auth falls back to unsigned cookies. Set JWT_SECRET (>= 32 chars) in .env.local.",
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
if (jwt_secret.trim().length < MIN_JWT_SECRET_LEN) {
|
|
58
|
+
console.error("=".repeat(60));
|
|
59
|
+
console.error("FATAL: JWT_SECRET is too short");
|
|
60
|
+
console.error("=".repeat(60));
|
|
61
|
+
console.error(`JWT_SECRET is ${jwt_secret.trim().length} chars; at least ${MIN_JWT_SECRET_LEN} are required.`);
|
|
62
|
+
console.error("Generate a strong one:");
|
|
63
|
+
console.error(" node -e \"console.log(require('crypto').randomBytes(32).toString('base64'))\"");
|
|
64
|
+
console.error("=".repeat(60));
|
|
65
|
+
throw new HazoConfigError({
|
|
66
|
+
code: "HAZO_AUTH_CONFIG",
|
|
67
|
+
pkg: "hazo_auth",
|
|
68
|
+
message: `JWT_SECRET is too short (${jwt_secret.trim().length} chars). ` +
|
|
69
|
+
`Use at least ${MIN_JWT_SECRET_LEN} characters for the session signing secret.`,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -26,7 +26,7 @@ export declare function GET(request: NextRequest): Promise<NextResponse<{
|
|
|
26
26
|
profile_source: {} | null;
|
|
27
27
|
user_type: string | null;
|
|
28
28
|
app_user_data: Record<string, unknown> | null;
|
|
29
|
-
legal_acceptance_status: "current" | "
|
|
29
|
+
legal_acceptance_status: "current" | "outdated" | "none";
|
|
30
30
|
}[];
|
|
31
31
|
}>>;
|
|
32
32
|
/**
|
package/dist/server-lib.d.ts
CHANGED
|
@@ -26,6 +26,7 @@ export { get_branding_config, is_branding_enabled, is_allowed_logo_format, get_m
|
|
|
26
26
|
export type { FirmBrandingConfig } from "./lib/branding_config.server";
|
|
27
27
|
export { create_sqlite_hazo_connect } from "./lib/hazo_connect_setup.js";
|
|
28
28
|
export { validate_hazo_connect_config } from "./lib/validate_hazo_connect_config.server.js";
|
|
29
|
+
export { validate_session_secret_config } from "./lib/validate_session_secret.server.js";
|
|
29
30
|
export { get_hazo_connect_instance, set_hazo_connect_instance, reset_hazo_connect_instance, } from "./lib/hazo_connect_instance.server.js";
|
|
30
31
|
export { create_app_logger } from "./lib/app_logger.js";
|
|
31
32
|
export { sanitize_error_for_user } from "./lib/utils/error_sanitizer.js";
|
package/dist/server-lib.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-lib.d.ts","sourceRoot":"","sources":["../src/server-lib.ts"],"names":[],"mappings":"AAYA,OAAO,aAAa,CAAC;AAGrB,cAAc,kBAAkB,CAAC;AAGjC,cAAc,sBAAsB,CAAC;AACrC,OAAO,EAAE,2BAA2B,EAAE,MAAM,wCAAwC,CAAC;AAGrF,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EAChB,mBAAmB,GACpB,MAAM,mCAAmC,CAAC;AAG3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAAE,0BAA0B,EAAE,MAAM,qCAAqC,CAAC;AACjF,OAAO,EAAE,yBAAyB,EAAE,MAAM,oCAAoC,CAAC;AAC/E,OAAO,EAAE,6BAA6B,EAAE,MAAM,wCAAwC,CAAC;AACvF,OAAO,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACzE,OAAO,EAAE,0BAA0B,EAAE,MAAM,qCAAqC,CAAC;AACjF,OAAO,EAAE,0BAA0B,EAAE,MAAM,qCAAqC,CAAC;AACjF,OAAO,EAAE,2BAA2B,EAAE,MAAM,sCAAsC,CAAC;AACnF,OAAO,EAAE,4BAA4B,EAAE,MAAM,uCAAuC,CAAC;AACrF,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAAE,uBAAuB,EAAE,MAAM,kCAAkC,CAAC;AAC3E,OAAO,EAAE,gCAAgC,EAAE,MAAM,2CAA2C,CAAC;AAC7F,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACzE,OAAO,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,EACL,gBAAgB,EAChB,uBAAuB,EACvB,yBAAyB,GAC1B,MAAM,2BAA2B,CAAC;AACnC,YAAY,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EACL,mBAAmB,EACnB,mBAAmB,EACnB,sBAAsB,EACtB,uBAAuB,GACxB,MAAM,8BAA8B,CAAC;AACtC,YAAY,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAGvE,OAAO,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,4BAA4B,EAAE,MAAM,2CAA2C,CAAC;AACzF,OAAO,EACL,yBAAyB,EACzB,yBAAyB,EACzB,2BAA2B,GAC5B,MAAM,oCAAoC,CAAC;AAG5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAGrD,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AACtE,YAAY,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AAC5E,cAAc,+BAA+B,CAAC;AAG9C,OAAO,EAAE,0BAA0B,EAAE,MAAM,2CAA2C,CAAC;AACvF,YAAY,EAAE,kBAAkB,EAAE,MAAM,2CAA2C,CAAC;AAGpF,OAAO,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AACzF,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACnE,YAAY,EAAE,4BAA4B,EAAE,MAAM,4BAA4B,CAAC;AAG/E,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AACnE,YAAY,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AAK7E,OAAO,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAC1F,YAAY,EACV,oBAAoB,EACpB,cAAc,EACd,eAAe,GAChB,MAAM,8BAA8B,CAAC"}
|
|
1
|
+
{"version":3,"file":"server-lib.d.ts","sourceRoot":"","sources":["../src/server-lib.ts"],"names":[],"mappings":"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"}
|
package/dist/server-lib.js
CHANGED
|
@@ -40,6 +40,7 @@ export { get_branding_config, is_branding_enabled, is_allowed_logo_format, get_m
|
|
|
40
40
|
// section: hazo_connect_exports
|
|
41
41
|
export { create_sqlite_hazo_connect } from "./lib/hazo_connect_setup.js";
|
|
42
42
|
export { validate_hazo_connect_config } from "./lib/validate_hazo_connect_config.server.js";
|
|
43
|
+
export { validate_session_secret_config } from "./lib/validate_session_secret.server.js";
|
|
43
44
|
export { get_hazo_connect_instance, set_hazo_connect_instance, reset_hazo_connect_instance, } from "./lib/hazo_connect_instance.server.js";
|
|
44
45
|
// section: logger_exports
|
|
45
46
|
export { create_app_logger } from "./lib/app_logger.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hazo_auth",
|
|
3
|
-
"version": "10.4.
|
|
3
|
+
"version": "10.4.13",
|
|
4
4
|
"description": "Zero-config authentication UI components for Next.js with RBAC, OAuth, scope-based multi-tenancy, and invitations",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"authentication",
|
|
@@ -408,7 +408,7 @@
|
|
|
408
408
|
"hazo_core": "^1.2.1",
|
|
409
409
|
"hazo_logs": "^2.1.1",
|
|
410
410
|
"hazo_notify": "^6.1.4",
|
|
411
|
-
"hazo_ui": "^4.
|
|
411
|
+
"hazo_ui": "^4.7.0",
|
|
412
412
|
"input-otp": "^1.4.0",
|
|
413
413
|
"jest": "^30.2.0",
|
|
414
414
|
"jest-environment-jsdom": "^30.0.0",
|