hazo_auth 4.5.7 → 4.6.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 (37) hide show
  1. package/README.md +16 -0
  2. package/SETUP_CHECKLIST.md +16 -0
  3. package/cli-src/lib/auth/auth_utils.server.ts +9 -10
  4. package/cli-src/lib/auth/dev_lock_validator.edge.ts +5 -4
  5. package/cli-src/lib/auth/hazo_get_auth.server.ts +6 -5
  6. package/cli-src/lib/auth/server_auth.ts +3 -2
  7. package/cli-src/lib/auth/session_token_validator.edge.ts +4 -2
  8. package/cli-src/lib/cookies_config.edge.ts +55 -0
  9. package/cli-src/lib/cookies_config.server.ts +93 -0
  10. package/dist/app/api/hazo_auth/login/route.d.ts.map +1 -1
  11. package/dist/app/api/hazo_auth/login/route.js +8 -17
  12. package/dist/app/api/hazo_auth/logout/route.d.ts.map +1 -1
  13. package/dist/app/api/hazo_auth/logout/route.js +9 -13
  14. package/dist/app/api/hazo_auth/update_user/route.d.ts.map +1 -1
  15. package/dist/app/api/hazo_auth/update_user/route.js +6 -3
  16. package/dist/components/layouts/shared/components/profile_pic_menu.d.ts.map +1 -1
  17. package/dist/components/layouts/shared/components/profile_pic_menu.js +49 -43
  18. package/dist/lib/auth/auth_utils.server.d.ts.map +1 -1
  19. package/dist/lib/auth/auth_utils.server.js +9 -10
  20. package/dist/lib/auth/dev_lock_validator.edge.d.ts +2 -1
  21. package/dist/lib/auth/dev_lock_validator.edge.d.ts.map +1 -1
  22. package/dist/lib/auth/dev_lock_validator.edge.js +5 -4
  23. package/dist/lib/auth/hazo_get_auth.server.d.ts.map +1 -1
  24. package/dist/lib/auth/hazo_get_auth.server.js +5 -4
  25. package/dist/lib/auth/server_auth.d.ts.map +1 -1
  26. package/dist/lib/auth/server_auth.js +3 -2
  27. package/dist/lib/auth/session_token_validator.edge.d.ts +1 -0
  28. package/dist/lib/auth/session_token_validator.edge.d.ts.map +1 -1
  29. package/dist/lib/auth/session_token_validator.edge.js +4 -2
  30. package/dist/lib/cookies_config.edge.d.ts +33 -0
  31. package/dist/lib/cookies_config.edge.d.ts.map +1 -0
  32. package/dist/lib/cookies_config.edge.js +48 -0
  33. package/dist/lib/cookies_config.server.d.ts +42 -0
  34. package/dist/lib/cookies_config.server.d.ts.map +1 -0
  35. package/dist/lib/cookies_config.server.js +71 -0
  36. package/hazo_auth_config.example.ini +15 -0
  37. package/package.json +1 -1
package/README.md CHANGED
@@ -382,6 +382,22 @@ HAZO_AUTH_GOOGLE_CLIENT_SECRET=your_google_client_secret
382
382
 
383
383
  See [Google OAuth Setup](#google-oauth-setup) for detailed instructions.
384
384
 
385
+ **For Cookie Customization (optional):**
386
+ ```env
387
+ # Cookie prefix (prevents conflicts when running multiple apps on localhost)
388
+ HAZO_AUTH_COOKIE_PREFIX=myapp_
389
+
390
+ # Cookie domain (optional, for cross-subdomain sharing)
391
+ HAZO_AUTH_COOKIE_DOMAIN=.example.com
392
+ ```
393
+
394
+ These environment variables are required for Edge Runtime (middleware) when using cookie customization. Also set in `hazo_auth_config.ini`:
395
+ ```ini
396
+ [hazo_auth__cookies]
397
+ cookie_prefix = myapp_
398
+ cookie_domain = .example.com
399
+ ```
400
+
385
401
  **Important:** The configuration files must be located in your project root directory (where `process.cwd()` points to), not inside `node_modules`. The package reads configuration from `process.cwd()` at runtime, so storing them elsewhere (including `node_modules/hazo_auth`) will break runtime access.
386
402
 
387
403
  ---
@@ -197,6 +197,10 @@ HAZO_CONNECT_POSTGREST_API_KEY=your_postgrest_api_key_here
197
197
  # Required for JWT authentication
198
198
  JWT_SECRET=your_secure_random_string_at_least_32_characters
199
199
  # Note: JWT_SECRET is required for JWT session token functionality (Edge-compatible proxy/middleware authentication)
200
+
201
+ # Optional: Cookie customization (prevents conflicts when running multiple apps)
202
+ HAZO_AUTH_COOKIE_PREFIX=myapp_
203
+ HAZO_AUTH_COOKIE_DOMAIN=
200
204
  ```
201
205
 
202
206
  **Generate a secure JWT secret:**
@@ -204,6 +208,18 @@ JWT_SECRET=your_secure_random_string_at_least_32_characters
204
208
  openssl rand -base64 32
205
209
  ```
206
210
 
211
+ **Cookie Customization (Optional):**
212
+ If you're running multiple apps that use hazo_auth on localhost (different ports), set `HAZO_AUTH_COOKIE_PREFIX` to prevent cookie conflicts. For example:
213
+ - App 1 (port 3000): `HAZO_AUTH_COOKIE_PREFIX=app1_`
214
+ - App 2 (port 3001): `HAZO_AUTH_COOKIE_PREFIX=app2_`
215
+
216
+ Also configure in `hazo_auth_config.ini`:
217
+ ```ini
218
+ [hazo_auth__cookies]
219
+ cookie_prefix = myapp_
220
+ cookie_domain =
221
+ ```
222
+
207
223
  ### Step 2.2: Configure email settings
208
224
 
209
225
  Edit `hazo_notify_config.ini`:
@@ -4,6 +4,7 @@ import { NextRequest, NextResponse } from "next/server";
4
4
  import { get_hazo_connect_instance } from "../hazo_connect_instance.server.js";
5
5
  import { createCrudService } from "hazo_connect/server";
6
6
  import { map_db_source_to_ui } from "../services/profile_picture_source_mapper.js";
7
+ import { get_cookie_name, get_cookie_options, BASE_COOKIE_NAMES } from "../cookies_config.server.js";
7
8
 
8
9
  // section: types
9
10
  export type AuthUser = {
@@ -24,19 +25,17 @@ export type AuthResult =
24
25
 
25
26
  // section: helpers
26
27
  /**
27
- * Clears authentication cookies from response
28
+ * Clears authentication cookies from response (with configurable prefix and domain)
28
29
  * @param response - NextResponse object to clear cookies from
29
30
  * @returns The response with cleared cookies
30
31
  */
31
32
  function clear_auth_cookies(response: NextResponse): NextResponse {
32
- response.cookies.set("hazo_auth_user_email", "", {
33
- expires: new Date(0),
34
- path: "/",
35
- });
36
- response.cookies.set("hazo_auth_user_id", "", {
33
+ const clear_cookie_options = get_cookie_options({
37
34
  expires: new Date(0),
38
35
  path: "/",
39
36
  });
37
+ response.cookies.set(get_cookie_name(BASE_COOKIE_NAMES.USER_EMAIL), "", clear_cookie_options);
38
+ response.cookies.set(get_cookie_name(BASE_COOKIE_NAMES.USER_ID), "", clear_cookie_options);
40
39
  return response;
41
40
  }
42
41
 
@@ -48,8 +47,8 @@ function clear_auth_cookies(response: NextResponse): NextResponse {
48
47
  * @returns AuthResult with user info or authenticated: false
49
48
  */
50
49
  export async function get_authenticated_user(request: NextRequest): Promise<AuthResult> {
51
- const user_id = request.cookies.get("hazo_auth_user_id")?.value;
52
- const user_email = request.cookies.get("hazo_auth_user_email")?.value;
50
+ const user_id = request.cookies.get(get_cookie_name(BASE_COOKIE_NAMES.USER_ID))?.value;
51
+ const user_email = request.cookies.get(get_cookie_name(BASE_COOKIE_NAMES.USER_EMAIL))?.value;
53
52
 
54
53
  if (!user_id || !user_email) {
55
54
  return { authenticated: false };
@@ -132,8 +131,8 @@ export async function get_authenticated_user_with_response(request: NextRequest)
132
131
  auth_result: AuthResult;
133
132
  response?: NextResponse;
134
133
  }> {
135
- const user_id = request.cookies.get("hazo_auth_user_id")?.value;
136
- const user_email = request.cookies.get("hazo_auth_user_email")?.value;
134
+ const user_id = request.cookies.get(get_cookie_name(BASE_COOKIE_NAMES.USER_ID))?.value;
135
+ const user_email = request.cookies.get(get_cookie_name(BASE_COOKIE_NAMES.USER_EMAIL))?.value;
137
136
 
138
137
  if (!user_id || !user_email) {
139
138
  return { auth_result: { authenticated: false } };
@@ -2,9 +2,9 @@
2
2
  // Uses Web Crypto API which works in Edge Runtime (no Node.js crypto module)
3
3
  // section: imports
4
4
  import type { NextRequest } from "next/server";
5
+ import { get_cookie_name_edge, BASE_COOKIE_NAMES } from "../cookies_config.edge.js";
5
6
 
6
7
  // section: constants
7
- const COOKIE_NAME = "hazo_auth_dev_lock";
8
8
  const SEPARATOR = "|";
9
9
 
10
10
  // section: types
@@ -105,7 +105,7 @@ export async function validate_dev_lock_cookie(
105
105
  return { valid: false };
106
106
  }
107
107
 
108
- const cookie = request.cookies.get(COOKIE_NAME)?.value;
108
+ const cookie = request.cookies.get(get_cookie_name_edge(BASE_COOKIE_NAMES.DEV_LOCK))?.value;
109
109
 
110
110
  if (!cookie) {
111
111
  return { valid: false };
@@ -162,10 +162,11 @@ export function validate_dev_lock_password(password: string): boolean {
162
162
  }
163
163
 
164
164
  /**
165
- * Gets the dev lock cookie name
165
+ * Gets the dev lock cookie name (with configurable prefix)
166
166
  * Exported for use in API routes when setting the cookie
167
+ * Uses HAZO_AUTH_COOKIE_PREFIX env var for configurable prefix
167
168
  * @returns Cookie name string
168
169
  */
169
170
  export function get_dev_lock_cookie_name(): string {
170
- return COOKIE_NAME;
171
+ return get_cookie_name_edge(BASE_COOKIE_NAMES.DEV_LOCK);
171
172
  }
@@ -17,6 +17,7 @@ import { check_user_scope_access, get_user_scopes, type UserScope } from "../ser
17
17
  import { is_valid_scope_level, type ScopeLevel } from "../services/scope_service.js";
18
18
  import { is_multi_tenancy_enabled, get_multi_tenancy_config } from "../multi_tenancy_config.server.js";
19
19
  import { get_org_cache, type OrgCacheEntry } from "./org_cache.js";
20
+ import { get_cookie_name, BASE_COOKIE_NAMES } from "../cookies_config.server.js";
20
21
 
21
22
  // section: helpers
22
23
 
@@ -407,13 +408,13 @@ export async function hazo_get_auth(
407
408
  );
408
409
  const rate_limiter = get_rate_limiter();
409
410
 
410
- // Fast path: Check for authentication cookies
411
+ // Fast path: Check for authentication cookies (with configurable prefix)
411
412
  // Priority: 1. JWT session token (new), 2. Simple cookies (backward compatibility)
412
413
  let user_id: string | undefined;
413
414
  let user_email: string | undefined;
414
-
415
+
415
416
  // Check for JWT session token first
416
- const session_token = request.cookies.get("hazo_auth_session")?.value;
417
+ const session_token = request.cookies.get(get_cookie_name(BASE_COOKIE_NAMES.SESSION))?.value;
417
418
  if (session_token) {
418
419
  try {
419
420
  const token_result = await validate_session_token(session_token);
@@ -435,8 +436,8 @@ export async function hazo_get_auth(
435
436
 
436
437
  // Fall back to simple cookies if JWT not present or invalid (backward compatibility)
437
438
  if (!user_id || !user_email) {
438
- user_id = request.cookies.get("hazo_auth_user_id")?.value;
439
- user_email = request.cookies.get("hazo_auth_user_email")?.value;
439
+ user_id = request.cookies.get(get_cookie_name(BASE_COOKIE_NAMES.USER_ID))?.value;
440
+ user_email = request.cookies.get(get_cookie_name(BASE_COOKIE_NAMES.USER_EMAIL))?.value;
440
441
  }
441
442
 
442
443
  if (!user_id || !user_email) {
@@ -4,6 +4,7 @@ import { cookies } from "next/headers";
4
4
  import { get_hazo_connect_instance } from "../hazo_connect_instance.server.js";
5
5
  import { createCrudService } from "hazo_connect/server";
6
6
  import { map_db_source_to_ui } from "../services/profile_picture_source_mapper.js";
7
+ import { get_cookie_name, BASE_COOKIE_NAMES } from "../cookies_config.server.js";
7
8
 
8
9
  // section: types
9
10
  export type ServerAuthUser = {
@@ -30,8 +31,8 @@ export type ServerAuthResult =
30
31
  */
31
32
  export async function get_server_auth_user(): Promise<ServerAuthResult> {
32
33
  const cookie_store = await cookies();
33
- const user_id = cookie_store.get("hazo_auth_user_id")?.value;
34
- const user_email = cookie_store.get("hazo_auth_user_email")?.value;
34
+ const user_id = cookie_store.get(get_cookie_name(BASE_COOKIE_NAMES.USER_ID))?.value;
35
+ const user_email = cookie_store.get(get_cookie_name(BASE_COOKIE_NAMES.USER_EMAIL))?.value;
35
36
 
36
37
  if (!user_id || !user_email) {
37
38
  return { authenticated: false };
@@ -3,6 +3,7 @@
3
3
  // section: imports
4
4
  import { jwtVerify } from "jose";
5
5
  import type { NextRequest } from "next/server";
6
+ import { get_cookie_name_edge, BASE_COOKIE_NAMES } from "../cookies_config.edge.js";
6
7
 
7
8
  // section: types
8
9
  export type ValidateSessionCookieResult = {
@@ -35,6 +36,7 @@ function get_jwt_secret(): Uint8Array | null {
35
36
  * Validates session cookie from NextRequest (Edge-compatible)
36
37
  * Extracts hazo_auth_session cookie and validates JWT signature and expiry
37
38
  * Works in Edge Runtime (Next.js proxy/middleware)
39
+ * Uses HAZO_AUTH_COOKIE_PREFIX env var for configurable cookie name
38
40
  * @param request - NextRequest object
39
41
  * @returns Validation result with user_id and email if valid
40
42
  */
@@ -42,8 +44,8 @@ export async function validate_session_cookie(
42
44
  request: NextRequest,
43
45
  ): Promise<ValidateSessionCookieResult> {
44
46
  try {
45
- // Extract session cookie
46
- const session_cookie = request.cookies.get("hazo_auth_session")?.value;
47
+ // Extract session cookie (with configurable prefix from env var)
48
+ const session_cookie = request.cookies.get(get_cookie_name_edge(BASE_COOKIE_NAMES.SESSION))?.value;
47
49
 
48
50
  if (!session_cookie) {
49
51
  return { valid: false };
@@ -0,0 +1,55 @@
1
+ // file_description: Edge-compatible cookie configuration helper
2
+ // Uses environment variables since Edge runtime can't read config files
3
+
4
+ // section: constants
5
+ // Base cookie names (without prefix)
6
+ export const BASE_COOKIE_NAMES = {
7
+ USER_ID: "hazo_auth_user_id",
8
+ USER_EMAIL: "hazo_auth_user_email",
9
+ SESSION: "hazo_auth_session",
10
+ DEV_LOCK: "hazo_auth_dev_lock",
11
+ } as const;
12
+
13
+ // section: main_functions
14
+ /**
15
+ * Gets the cookie prefix from environment variable
16
+ * For Edge runtime, use HAZO_AUTH_COOKIE_PREFIX env var
17
+ * @returns Cookie prefix string (empty string if not set)
18
+ */
19
+ export function get_cookie_prefix_edge(): string {
20
+ return process.env.HAZO_AUTH_COOKIE_PREFIX || "";
21
+ }
22
+
23
+ /**
24
+ * Gets the cookie domain from environment variable
25
+ * For Edge runtime, use HAZO_AUTH_COOKIE_DOMAIN env var
26
+ * @returns Cookie domain string (empty string if not set)
27
+ */
28
+ export function get_cookie_domain_edge(): string {
29
+ return process.env.HAZO_AUTH_COOKIE_DOMAIN || "";
30
+ }
31
+
32
+ /**
33
+ * Gets the full cookie name with prefix applied (Edge-compatible)
34
+ * @param base_name - Base cookie name from BASE_COOKIE_NAMES
35
+ * @returns Full cookie name with prefix
36
+ */
37
+ export function get_cookie_name_edge(base_name: string): string {
38
+ const prefix = get_cookie_prefix_edge();
39
+ return `${prefix}${base_name}`;
40
+ }
41
+
42
+ /**
43
+ * Gets cookie options with domain if configured (Edge-compatible)
44
+ * @param options - Base cookie options
45
+ * @returns Cookie options with domain added if configured
46
+ */
47
+ export function get_cookie_options_edge<T extends Record<string, unknown>>(options: T): T & { domain?: string } {
48
+ const domain = get_cookie_domain_edge();
49
+
50
+ if (domain) {
51
+ return { ...options, domain };
52
+ }
53
+
54
+ return options;
55
+ }
@@ -0,0 +1,93 @@
1
+ // file_description: server-only helper to read cookie configuration from hazo_auth_config.ini
2
+
3
+ import { read_config_section } from "./config/config_loader.server.js";
4
+
5
+ // section: types
6
+ export type CookiesConfig = {
7
+ /** Prefix for all hazo_auth cookies (e.g., "myapp_" results in "myapp_hazo_auth_session") */
8
+ cookie_prefix: string;
9
+ /** Optional domain for cookies (e.g., ".example.com" for cross-subdomain) */
10
+ cookie_domain: string;
11
+ };
12
+
13
+ // section: defaults
14
+ const DEFAULT_CONFIG: CookiesConfig = {
15
+ cookie_prefix: "",
16
+ cookie_domain: "",
17
+ };
18
+
19
+ // section: constants
20
+ const SECTION_NAME = "hazo_auth__cookies";
21
+
22
+ // Base cookie names (without prefix)
23
+ export const BASE_COOKIE_NAMES = {
24
+ USER_ID: "hazo_auth_user_id",
25
+ USER_EMAIL: "hazo_auth_user_email",
26
+ SESSION: "hazo_auth_session",
27
+ DEV_LOCK: "hazo_auth_dev_lock",
28
+ } as const;
29
+
30
+ // section: main_function
31
+ /**
32
+ * Reads cookie configuration from hazo_auth_config.ini file
33
+ * Falls back to defaults if hazo_auth_config.ini is not found or section is missing
34
+ * @returns CookiesConfig object with all cookie settings
35
+ */
36
+ export function get_cookies_config(): CookiesConfig {
37
+ const section = read_config_section(SECTION_NAME);
38
+
39
+ if (!section) {
40
+ return DEFAULT_CONFIG;
41
+ }
42
+
43
+ return {
44
+ cookie_prefix: section.cookie_prefix || DEFAULT_CONFIG.cookie_prefix,
45
+ cookie_domain: section.cookie_domain || DEFAULT_CONFIG.cookie_domain,
46
+ };
47
+ }
48
+
49
+ /**
50
+ * Gets the full cookie name with prefix applied
51
+ * @param base_name - Base cookie name from BASE_COOKIE_NAMES
52
+ * @returns Full cookie name with prefix
53
+ */
54
+ export function get_cookie_name(base_name: string): string {
55
+ const config = get_cookies_config();
56
+ return `${config.cookie_prefix}${base_name}`;
57
+ }
58
+
59
+ /**
60
+ * Gets cookie options with domain if configured
61
+ * @param options - Base cookie options
62
+ * @returns Cookie options with domain added if configured
63
+ */
64
+ export function get_cookie_options<T extends Record<string, unknown>>(options: T): T & { domain?: string } {
65
+ const config = get_cookies_config();
66
+
67
+ if (config.cookie_domain) {
68
+ return { ...options, domain: config.cookie_domain };
69
+ }
70
+
71
+ return options;
72
+ }
73
+
74
+ // Cached config for performance (module-level cache)
75
+ let cached_config: CookiesConfig | null = null;
76
+
77
+ /**
78
+ * Gets cached cookie configuration for performance-critical paths
79
+ * @returns CookiesConfig object
80
+ */
81
+ export function get_cached_cookies_config(): CookiesConfig {
82
+ if (!cached_config) {
83
+ cached_config = get_cookies_config();
84
+ }
85
+ return cached_config;
86
+ }
87
+
88
+ /**
89
+ * Clears the cached config (useful for testing)
90
+ */
91
+ export function clear_cookies_config_cache(): void {
92
+ cached_config = null;
93
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../../src/app/api/hazo_auth/login/route.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAUxD,wBAAsB,IAAI,CAAC,OAAO,EAAE,WAAW;;;;;;;;;IAgM9C"}
1
+ {"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../../src/app/api/hazo_auth/login/route.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAWxD,wBAAsB,IAAI,CAAC,OAAO,EAAE,WAAW;;;;;;;;;IAuL9C"}
@@ -8,6 +8,7 @@ import { createCrudService } from "hazo_connect/server";
8
8
  import { get_filename, get_line_number } from "../../../../lib/utils/api_route_helpers";
9
9
  import { get_login_config } from "../../../../lib/login_config.server";
10
10
  import { create_session_token } from "../../../../lib/services/session_token_service";
11
+ import { get_cookie_name, get_cookie_options, BASE_COOKIE_NAMES } from "../../../../lib/cookies_config.server";
11
12
  // section: api_handler
12
13
  export async function POST(request) {
13
14
  const logger = create_app_logger();
@@ -110,31 +111,21 @@ export async function POST(request) {
110
111
  name: user_name,
111
112
  redirectUrl,
112
113
  }, { status: 200 });
113
- // Set authentication cookies
114
- response.cookies.set("hazo_auth_user_id", user_id, {
114
+ // Set authentication cookies (with configurable prefix and domain)
115
+ const base_cookie_options = {
115
116
  httpOnly: true,
116
117
  secure: process.env.NODE_ENV === "production",
117
118
  sameSite: "lax",
118
119
  path: "/",
119
120
  maxAge: 60 * 60 * 24 * 30, // 30 days
120
- });
121
- response.cookies.set("hazo_auth_user_email", email, {
122
- httpOnly: true,
123
- secure: process.env.NODE_ENV === "production",
124
- sameSite: "lax",
125
- path: "/",
126
- maxAge: 60 * 60 * 24 * 30, // 30 days
127
- });
121
+ };
122
+ const cookie_options = get_cookie_options(base_cookie_options);
123
+ response.cookies.set(get_cookie_name(BASE_COOKIE_NAMES.USER_ID), user_id, cookie_options);
124
+ response.cookies.set(get_cookie_name(BASE_COOKIE_NAMES.USER_EMAIL), email, cookie_options);
128
125
  // Create and set JWT session token (for Edge-compatible proxy/middleware)
129
126
  try {
130
127
  const session_token = await create_session_token(user_id, email);
131
- response.cookies.set("hazo_auth_session", session_token, {
132
- httpOnly: true,
133
- secure: process.env.NODE_ENV === "production",
134
- sameSite: "lax",
135
- path: "/",
136
- maxAge: 60 * 60 * 24 * 30, // 30 days
137
- });
128
+ response.cookies.set(get_cookie_name(BASE_COOKIE_NAMES.SESSION), session_token, cookie_options);
138
129
  }
139
130
  catch (token_error) {
140
131
  // Log error but don't fail login if token creation fails
@@ -1 +1 @@
1
- {"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../../src/app/api/hazo_auth/logout/route.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAOxD,wBAAsB,IAAI,CAAC,OAAO,EAAE,WAAW;;;;;IAkH9C"}
1
+ {"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../../src/app/api/hazo_auth/logout/route.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAQxD,wBAAsB,IAAI,CAAC,OAAO,EAAE,WAAW;;;;;IA8G9C"}
@@ -5,33 +5,29 @@ import { create_app_logger } from "../../../../lib/app_logger";
5
5
  import { get_filename, get_line_number } from "../../../../lib/utils/api_route_helpers";
6
6
  import { get_auth_cache } from "../../../../lib/auth/auth_cache";
7
7
  import { get_auth_utility_config } from "../../../../lib/auth_utility_config.server";
8
+ import { get_cookie_name, get_cookie_options, BASE_COOKIE_NAMES } from "../../../../lib/cookies_config.server";
8
9
  // section: api_handler
9
10
  export async function POST(request) {
10
11
  var _a, _b;
11
12
  const logger = create_app_logger();
12
13
  try {
13
- // Get user info from cookie before clearing
14
- const user_email = (_a = request.cookies.get("hazo_auth_user_email")) === null || _a === void 0 ? void 0 : _a.value;
15
- const user_id = (_b = request.cookies.get("hazo_auth_user_id")) === null || _b === void 0 ? void 0 : _b.value;
14
+ // Get user info from cookie before clearing (using configurable cookie names)
15
+ const user_email = (_a = request.cookies.get(get_cookie_name(BASE_COOKIE_NAMES.USER_EMAIL))) === null || _a === void 0 ? void 0 : _a.value;
16
+ const user_id = (_b = request.cookies.get(get_cookie_name(BASE_COOKIE_NAMES.USER_ID))) === null || _b === void 0 ? void 0 : _b.value;
16
17
  // Clear authentication cookies
17
18
  const response = NextResponse.json({
18
19
  success: true,
19
20
  message: "Logout successful",
20
21
  }, { status: 200 });
21
- // Clear cookies by setting them to expire in the past
22
- response.cookies.set("hazo_auth_user_email", "", {
23
- expires: new Date(0),
24
- path: "/",
25
- });
26
- response.cookies.set("hazo_auth_user_id", "", {
22
+ // Clear cookies by setting them to expire in the past (with configurable domain)
23
+ const clear_cookie_options = get_cookie_options({
27
24
  expires: new Date(0),
28
25
  path: "/",
29
26
  });
27
+ response.cookies.set(get_cookie_name(BASE_COOKIE_NAMES.USER_EMAIL), "", clear_cookie_options);
28
+ response.cookies.set(get_cookie_name(BASE_COOKIE_NAMES.USER_ID), "", clear_cookie_options);
30
29
  // Clear JWT session token cookie
31
- response.cookies.set("hazo_auth_session", "", {
32
- expires: new Date(0),
33
- path: "/",
34
- });
30
+ response.cookies.set(get_cookie_name(BASE_COOKIE_NAMES.SESSION), "", clear_cookie_options);
35
31
  // Clear NextAuth session cookies (for OAuth users)
36
32
  response.cookies.set("next-auth.session-token", "", {
37
33
  expires: new Date(0),
@@ -1 +1 @@
1
- {"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../../src/app/api/hazo_auth/update_user/route.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAQxD,wBAAsB,KAAK,CAAC,OAAO,EAAE,WAAW;;;;;;IAkH/C"}
1
+ {"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../../src/app/api/hazo_auth/update_user/route.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AASxD,wBAAsB,KAAK,CAAC,OAAO,EAAE,WAAW;;;;;;IAoH/C"}
@@ -6,6 +6,7 @@ import { create_app_logger } from "../../../../lib/app_logger";
6
6
  import { update_user_profile } from "../../../../lib/services/user_update_service";
7
7
  import { get_filename, get_line_number } from "../../../../lib/utils/api_route_helpers";
8
8
  import { require_auth } from "../../../../lib/auth/auth_utils.server";
9
+ import { get_cookie_name, get_cookie_options, BASE_COOKIE_NAMES } from "../../../../lib/cookies_config.server";
9
10
  // section: api_handler
10
11
  export async function PATCH(request) {
11
12
  const logger = create_app_logger();
@@ -69,15 +70,17 @@ export async function PATCH(request) {
69
70
  message: "Profile updated successfully",
70
71
  email_changed: result.email_changed,
71
72
  }, { status: 200 });
72
- // If email changed, update the cookie (match login route cookie settings)
73
+ // If email changed, update the cookie (match login route cookie settings, with configurable prefix and domain)
73
74
  if (result.email_changed && email) {
74
- response.cookies.set("hazo_auth_user_email", email, {
75
+ const base_cookie_options = {
75
76
  httpOnly: true,
76
77
  secure: process.env.NODE_ENV === "production",
77
78
  sameSite: "lax",
78
79
  path: "/",
79
80
  maxAge: 60 * 60 * 24 * 30, // 30 days
80
- });
81
+ };
82
+ const cookie_options = get_cookie_options(base_cookie_options);
83
+ response.cookies.set(get_cookie_name(BASE_COOKIE_NAMES.USER_EMAIL), email, cookie_options);
81
84
  }
82
85
  return response;
83
86
  }
@@ -1 +1 @@
1
- {"version":3,"file":"profile_pic_menu.d.ts","sourceRoot":"","sources":["../../../../../src/components/layouts/shared/components/profile_pic_menu.tsx"],"names":[],"mappings":"AA6BA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gDAAgD,CAAC;AAI7F,MAAM,MAAM,mBAAmB,GAAG;IAChC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iBAAiB,CAAC,EAAE,sBAAsB,EAAE,CAAC;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,SAAS,GAAG,IAAI,GAAG,IAAI,CAAC;IACtC,OAAO,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;IACjC,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B,CAAC;AAGF;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,EAC7B,kBAA0B,EAC1B,aAAyB,EACzB,aAAyB,EACzB,aAAqC,EACrC,UAA+B,EAC/B,aAAwC,EACxC,WAAW,EACX,iBAAsB,EACtB,SAAS,EACT,WAAuB,EACvB,OAAoB,EACpB,mBAA+B,GAChC,EAAE,mBAAmB,2CAuarB"}
1
+ {"version":3,"file":"profile_pic_menu.d.ts","sourceRoot":"","sources":["../../../../../src/components/layouts/shared/components/profile_pic_menu.tsx"],"names":[],"mappings":"AAqCA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gDAAgD,CAAC;AAI7F,MAAM,MAAM,mBAAmB,GAAG;IAChC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iBAAiB,CAAC,EAAE,sBAAsB,EAAE,CAAC;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,SAAS,GAAG,IAAI,GAAG,IAAI,CAAC;IACtC,OAAO,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;IACjC,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B,CAAC;AAGF;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,EAC7B,kBAA0B,EAC1B,aAAyB,EACzB,aAAyB,EACzB,aAAqC,EACrC,UAA+B,EAC/B,aAAwC,EACxC,WAAW,EACX,iBAAsB,EACtB,SAAS,EACT,WAAuB,EACvB,OAAoB,EACpB,mBAA+B,GAChC,EAAE,mBAAmB,2CA6erB"}
@@ -10,8 +10,10 @@ import Link from "next/link";
10
10
  import { Avatar, AvatarImage, AvatarFallback } from "../../../ui/avatar";
11
11
  import { Button } from "../../../ui/button";
12
12
  import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, } from "../../../ui/dropdown-menu";
13
+ import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, } from "../../../ui/dialog";
14
+ import { RolesMatrix } from "../../user_management/components/roles_matrix";
13
15
  import { SidebarGroup, SidebarGroupLabel, SidebarMenu, SidebarMenuItem, SidebarMenuButton, } from "../../../ui/sidebar";
14
- import { Settings, LogOut } from "lucide-react";
16
+ import { Settings, LogOut, Shield } from "lucide-react";
15
17
  import { toast } from "sonner";
16
18
  import { use_auth_status, trigger_auth_status_refresh } from "../hooks/use_auth_status";
17
19
  import { useHazoAuthConfig } from "../../../../contexts/hazo_auth_provider";
@@ -30,6 +32,8 @@ export function ProfilePicMenu({ show_single_button = false, sign_up_label = "Si
30
32
  const router = useRouter();
31
33
  const authStatus = use_auth_status();
32
34
  const [isLoggingOut, setIsLoggingOut] = useState(false);
35
+ const [shiftKeyHeld, setShiftKeyHeld] = useState(false);
36
+ const [showPermissionsDialog, setShowPermissionsDialog] = useState(false);
33
37
  // Use provided logout_path or default to context-based path
34
38
  const effectiveLogoutPath = logout_path || `${apiBasePath}/logout`;
35
39
  // Get initials from name or email
@@ -161,48 +165,50 @@ export function ProfilePicMenu({ show_single_button = false, sign_up_label = "Si
161
165
  // Authenticated - render based on variant
162
166
  if (variant === "sidebar") {
163
167
  // Sidebar variant: show profile picture and name only, clicking opens dropdown
164
- return (_jsxs(SidebarGroup, { className: `cls_profile_pic_menu_sidebar ${className || ""}`, children: [_jsx(SidebarGroupLabel, { className: "cls_profile_pic_menu_sidebar_label", children: sidebar_group_label }), _jsx(SidebarMenu, { className: "cls_profile_pic_menu_sidebar_menu", children: _jsx(SidebarMenuItem, { className: "cls_profile_pic_menu_sidebar_user_info", children: _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx("button", { className: "cls_profile_pic_menu_sidebar_trigger w-full focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary rounded-md", "aria-label": "Profile menu", children: _jsxs("div", { className: "cls_profile_pic_menu_sidebar_user flex items-center gap-3 px-2 py-2 hover:bg-sidebar-accent rounded-md transition-colors", children: [_jsxs(Avatar, { className: `cls_profile_pic_menu_avatar ${avatarSizeClasses[avatar_size]} cursor-pointer`, children: [_jsx(AvatarImage, { src: authStatus.profile_picture_url, alt: authStatus.name ? `Profile picture of ${authStatus.name}` : "Profile picture", className: "cls_profile_pic_menu_image" }), _jsx(AvatarFallback, { className: "cls_profile_pic_menu_fallback bg-[var(--hazo-bg-emphasis)] text-[var(--hazo-text-muted)]", children: getInitials() })] }), authStatus.name && (_jsx("span", { className: "cls_profile_pic_menu_sidebar_user_name text-sm font-medium text-sidebar-foreground truncate", children: authStatus.name }))] }) }) }), _jsx(DropdownMenuContent, { align: "end", className: "cls_profile_pic_menu_dropdown w-56", children: menuItems.map((item) => {
165
- if (item.type === "separator") {
166
- return _jsx(DropdownMenuSeparator, { className: "cls_profile_pic_menu_separator" }, item.id);
167
- }
168
- if (item.type === "info") {
169
- return (_jsx("div", { className: "cls_profile_pic_menu_info", children: item.value && (_jsx("div", { className: "cls_profile_pic_menu_info_value px-2 py-1.5 text-sm text-foreground", children: item.value })) }, item.id));
170
- }
171
- if (item.type === "link") {
172
- // Special handling for logout
173
- if (item.id === "default_logout") {
174
- return (_jsxs(DropdownMenuItem, { onClick: handleLogout, disabled: isLoggingOut, className: "cls_profile_pic_menu_logout cursor-pointer text-destructive focus:text-destructive", children: [_jsx(LogOut, { className: "mr-2 h-4 w-4" }), isLoggingOut ? "Logging out..." : item.label] }, item.id));
175
- }
176
- // Special handling for settings
177
- if (item.id === "default_settings") {
178
- return (_jsx(DropdownMenuItem, { asChild: true, className: "cls_profile_pic_menu_settings cursor-pointer", children: _jsxs(Link, { href: item.href || settings_path, children: [_jsx(Settings, { className: "mr-2 h-4 w-4" }), item.label] }) }, item.id));
179
- }
180
- // Generic link handling
181
- return (_jsx(DropdownMenuItem, { asChild: true, className: "cls_profile_pic_menu_link cursor-pointer", children: _jsx(Link, { href: item.href || "#", children: item.label }) }, item.id));
182
- }
183
- return null;
184
- }) })] }) }) })] }));
168
+ return (_jsxs(SidebarGroup, { className: `cls_profile_pic_menu_sidebar ${className || ""}`, children: [_jsx(SidebarGroupLabel, { className: "cls_profile_pic_menu_sidebar_label", children: sidebar_group_label }), _jsx(SidebarMenu, { className: "cls_profile_pic_menu_sidebar_menu", children: _jsxs(SidebarMenuItem, { className: "cls_profile_pic_menu_sidebar_user_info", children: [_jsxs(DropdownMenu, { onOpenChange: (open) => { if (!open)
169
+ setShiftKeyHeld(false); }, children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx("button", { className: "cls_profile_pic_menu_sidebar_trigger w-full focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary rounded-md", "aria-label": "Profile menu", onClick: (e) => setShiftKeyHeld(e.shiftKey), children: _jsxs("div", { className: "cls_profile_pic_menu_sidebar_user flex items-center gap-3 px-2 py-2 hover:bg-sidebar-accent rounded-md transition-colors", children: [_jsxs(Avatar, { className: `cls_profile_pic_menu_avatar ${avatarSizeClasses[avatar_size]} cursor-pointer`, children: [_jsx(AvatarImage, { src: authStatus.profile_picture_url, alt: authStatus.name ? `Profile picture of ${authStatus.name}` : "Profile picture", className: "cls_profile_pic_menu_image" }), _jsx(AvatarFallback, { className: "cls_profile_pic_menu_fallback bg-[var(--hazo-bg-emphasis)] text-[var(--hazo-text-muted)]", children: getInitials() })] }), authStatus.name && (_jsx("span", { className: "cls_profile_pic_menu_sidebar_user_name text-sm font-medium text-sidebar-foreground truncate", children: authStatus.name }))] }) }) }), _jsxs(DropdownMenuContent, { align: "end", className: "cls_profile_pic_menu_dropdown w-56", children: [menuItems.map((item) => {
170
+ if (item.type === "separator") {
171
+ return _jsx(DropdownMenuSeparator, { className: "cls_profile_pic_menu_separator" }, item.id);
172
+ }
173
+ if (item.type === "info") {
174
+ return (_jsx("div", { className: "cls_profile_pic_menu_info", children: item.value && (_jsx("div", { className: "cls_profile_pic_menu_info_value px-2 py-1.5 text-sm text-foreground", children: item.value })) }, item.id));
175
+ }
176
+ if (item.type === "link") {
177
+ // Special handling for logout
178
+ if (item.id === "default_logout") {
179
+ return (_jsxs(DropdownMenuItem, { onClick: handleLogout, disabled: isLoggingOut, className: "cls_profile_pic_menu_logout cursor-pointer text-destructive focus:text-destructive", children: [_jsx(LogOut, { className: "mr-2 h-4 w-4" }), isLoggingOut ? "Logging out..." : item.label] }, item.id));
180
+ }
181
+ // Special handling for settings
182
+ if (item.id === "default_settings") {
183
+ return (_jsx(DropdownMenuItem, { asChild: true, className: "cls_profile_pic_menu_settings cursor-pointer", children: _jsxs(Link, { href: item.href || settings_path, children: [_jsx(Settings, { className: "mr-2 h-4 w-4" }), item.label] }) }, item.id));
184
+ }
185
+ // Generic link handling
186
+ return (_jsx(DropdownMenuItem, { asChild: true, className: "cls_profile_pic_menu_link cursor-pointer", children: _jsx(Link, { href: item.href || "#", children: item.label }) }, item.id));
187
+ }
188
+ return null;
189
+ }), shiftKeyHeld && (_jsxs(_Fragment, { children: [_jsx(DropdownMenuSeparator, { className: "cls_profile_pic_menu_separator" }), _jsxs(DropdownMenuItem, { onClick: () => setShowPermissionsDialog(true), className: "cls_profile_pic_menu_permissions cursor-pointer", children: [_jsx(Shield, { className: "mr-2 h-4 w-4" }), "My Permissions"] })] }))] })] }), _jsx(Dialog, { open: showPermissionsDialog, onOpenChange: setShowPermissionsDialog, children: _jsxs(DialogContent, { className: "cls_profile_pic_menu_permissions_dialog max-w-2xl max-h-[80vh] flex flex-col", children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: "My Permissions" }), _jsx(DialogDescription, { children: "Your assigned roles and their permissions" })] }), _jsx("div", { className: "flex-1 overflow-y-auto", children: _jsx(RolesMatrix, { user_id: authStatus.user_id, add_button_enabled: false, role_name_selection_enabled: false, permissions_read_only: true, show_save_cancel: false }) })] }) })] }) })] }));
185
190
  }
186
191
  // Default dropdown variant: show profile picture with dropdown menu
187
- return (_jsx("div", { className: `cls_profile_pic_menu ${className || ""}`, children: _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx("button", { className: "cls_profile_pic_menu_trigger focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary rounded-full", "aria-label": "Profile menu", children: _jsxs(Avatar, { className: `cls_profile_pic_menu_avatar ${avatarSizeClasses[avatar_size]} cursor-pointer`, children: [_jsx(AvatarImage, { src: authStatus.profile_picture_url, alt: authStatus.name ? `Profile picture of ${authStatus.name}` : "Profile picture", className: "cls_profile_pic_menu_image" }), _jsx(AvatarFallback, { className: "cls_profile_pic_menu_fallback bg-[var(--hazo-bg-emphasis)] text-[var(--hazo-text-muted)]", children: getInitials() })] }) }) }), _jsx(DropdownMenuContent, { align: "end", className: "cls_profile_pic_menu_dropdown w-56", children: menuItems.map((item) => {
188
- if (item.type === "separator") {
189
- return _jsx(DropdownMenuSeparator, { className: "cls_profile_pic_menu_separator" }, item.id);
190
- }
191
- if (item.type === "info") {
192
- return (_jsx("div", { className: "cls_profile_pic_menu_info", children: item.value && (_jsx("div", { className: "cls_profile_pic_menu_info_value px-2 py-1.5 text-sm text-foreground", children: item.value })) }, item.id));
193
- }
194
- if (item.type === "link") {
195
- // Special handling for logout
196
- if (item.id === "default_logout") {
197
- return (_jsxs(DropdownMenuItem, { onClick: handleLogout, disabled: isLoggingOut, className: "cls_profile_pic_menu_logout cursor-pointer text-destructive focus:text-destructive", children: [_jsx(LogOut, { className: "mr-2 h-4 w-4" }), isLoggingOut ? "Logging out..." : item.label] }, item.id));
198
- }
199
- // Special handling for settings
200
- if (item.id === "default_settings") {
201
- return (_jsx(DropdownMenuItem, { asChild: true, className: "cls_profile_pic_menu_settings cursor-pointer", children: _jsxs(Link, { href: item.href || settings_path, children: [_jsx(Settings, { className: "mr-2 h-4 w-4" }), item.label] }) }, item.id));
202
- }
203
- // Generic link handling
204
- return (_jsx(DropdownMenuItem, { asChild: true, className: "cls_profile_pic_menu_link cursor-pointer", children: _jsx(Link, { href: item.href || "#", children: item.label }) }, item.id));
205
- }
206
- return null;
207
- }) })] }) }));
192
+ return (_jsxs("div", { className: `cls_profile_pic_menu ${className || ""}`, children: [_jsxs(DropdownMenu, { onOpenChange: (open) => { if (!open)
193
+ setShiftKeyHeld(false); }, children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx("button", { className: "cls_profile_pic_menu_trigger focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary rounded-full", "aria-label": "Profile menu", onClick: (e) => setShiftKeyHeld(e.shiftKey), children: _jsxs(Avatar, { className: `cls_profile_pic_menu_avatar ${avatarSizeClasses[avatar_size]} cursor-pointer`, children: [_jsx(AvatarImage, { src: authStatus.profile_picture_url, alt: authStatus.name ? `Profile picture of ${authStatus.name}` : "Profile picture", className: "cls_profile_pic_menu_image" }), _jsx(AvatarFallback, { className: "cls_profile_pic_menu_fallback bg-[var(--hazo-bg-emphasis)] text-[var(--hazo-text-muted)]", children: getInitials() })] }) }) }), _jsxs(DropdownMenuContent, { align: "end", className: "cls_profile_pic_menu_dropdown w-56", children: [menuItems.map((item) => {
194
+ if (item.type === "separator") {
195
+ return _jsx(DropdownMenuSeparator, { className: "cls_profile_pic_menu_separator" }, item.id);
196
+ }
197
+ if (item.type === "info") {
198
+ return (_jsx("div", { className: "cls_profile_pic_menu_info", children: item.value && (_jsx("div", { className: "cls_profile_pic_menu_info_value px-2 py-1.5 text-sm text-foreground", children: item.value })) }, item.id));
199
+ }
200
+ if (item.type === "link") {
201
+ // Special handling for logout
202
+ if (item.id === "default_logout") {
203
+ return (_jsxs(DropdownMenuItem, { onClick: handleLogout, disabled: isLoggingOut, className: "cls_profile_pic_menu_logout cursor-pointer text-destructive focus:text-destructive", children: [_jsx(LogOut, { className: "mr-2 h-4 w-4" }), isLoggingOut ? "Logging out..." : item.label] }, item.id));
204
+ }
205
+ // Special handling for settings
206
+ if (item.id === "default_settings") {
207
+ return (_jsx(DropdownMenuItem, { asChild: true, className: "cls_profile_pic_menu_settings cursor-pointer", children: _jsxs(Link, { href: item.href || settings_path, children: [_jsx(Settings, { className: "mr-2 h-4 w-4" }), item.label] }) }, item.id));
208
+ }
209
+ // Generic link handling
210
+ return (_jsx(DropdownMenuItem, { asChild: true, className: "cls_profile_pic_menu_link cursor-pointer", children: _jsx(Link, { href: item.href || "#", children: item.label }) }, item.id));
211
+ }
212
+ return null;
213
+ }), shiftKeyHeld && (_jsxs(_Fragment, { children: [_jsx(DropdownMenuSeparator, { className: "cls_profile_pic_menu_separator" }), _jsxs(DropdownMenuItem, { onClick: () => setShowPermissionsDialog(true), className: "cls_profile_pic_menu_permissions cursor-pointer", children: [_jsx(Shield, { className: "mr-2 h-4 w-4" }), "My Permissions"] })] }))] })] }), _jsx(Dialog, { open: showPermissionsDialog, onOpenChange: setShowPermissionsDialog, children: _jsxs(DialogContent, { className: "cls_profile_pic_menu_permissions_dialog max-w-2xl max-h-[80vh] flex flex-col", children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: "My Permissions" }), _jsx(DialogDescription, { children: "Your assigned roles and their permissions" })] }), _jsx("div", { className: "flex-1 overflow-y-auto", children: _jsx(RolesMatrix, { user_id: authStatus.user_id, add_button_enabled: false, role_name_selection_enabled: false, permissions_read_only: true, show_save_cancel: false }) })] }) })] }));
208
214
  }
@@ -1 +1 @@
1
- {"version":3,"file":"auth_utils.server.d.ts","sourceRoot":"","sources":["../../../src/lib/auth/auth_utils.server.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAMxD,MAAM,MAAM,QAAQ,GAAG;IACrB,aAAa,EAAE,IAAI,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,OAAO,CAAC;IACxB,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,cAAc,CAAC,EAAE,QAAQ,GAAG,SAAS,GAAG,UAAU,GAAG,QAAQ,CAAC;CAC/D,CAAC;AAEF,MAAM,MAAM,UAAU,GAClB,QAAQ,GACR;IAAE,aAAa,EAAE,KAAK,CAAA;CAAE,CAAC;AAqB7B;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CA8CtF;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,CAG7E;AAED;;;;;;GAMG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC,CAQ1E;AAED;;;;;GAKG;AACH,wBAAsB,oCAAoC,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC;IACxF,WAAW,EAAE,UAAU,CAAC;IACxB,QAAQ,CAAC,EAAE,YAAY,CAAC;CACzB,CAAC,CA6DD"}
1
+ {"version":3,"file":"auth_utils.server.d.ts","sourceRoot":"","sources":["../../../src/lib/auth/auth_utils.server.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAOxD,MAAM,MAAM,QAAQ,GAAG;IACrB,aAAa,EAAE,IAAI,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,OAAO,CAAC;IACxB,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,cAAc,CAAC,EAAE,QAAQ,GAAG,SAAS,GAAG,UAAU,GAAG,QAAQ,CAAC;CAC/D,CAAC;AAEF,MAAM,MAAM,UAAU,GAClB,QAAQ,GACR;IAAE,aAAa,EAAE,KAAK,CAAA;CAAE,CAAC;AAmB7B;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CA8CtF;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,CAG7E;AAED;;;;;;GAMG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC,CAQ1E;AAED;;;;;GAKG;AACH,wBAAsB,oCAAoC,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC;IACxF,WAAW,EAAE,UAAU,CAAC;IACxB,QAAQ,CAAC,EAAE,YAAY,CAAC;CACzB,CAAC,CA6DD"}
@@ -4,21 +4,20 @@ import { NextResponse } from "next/server";
4
4
  import { get_hazo_connect_instance } from "../hazo_connect_instance.server";
5
5
  import { createCrudService } from "hazo_connect/server";
6
6
  import { map_db_source_to_ui } from "../services/profile_picture_source_mapper";
7
+ import { get_cookie_name, get_cookie_options, BASE_COOKIE_NAMES } from "../cookies_config.server";
7
8
  // section: helpers
8
9
  /**
9
- * Clears authentication cookies from response
10
+ * Clears authentication cookies from response (with configurable prefix and domain)
10
11
  * @param response - NextResponse object to clear cookies from
11
12
  * @returns The response with cleared cookies
12
13
  */
13
14
  function clear_auth_cookies(response) {
14
- response.cookies.set("hazo_auth_user_email", "", {
15
- expires: new Date(0),
16
- path: "/",
17
- });
18
- response.cookies.set("hazo_auth_user_id", "", {
15
+ const clear_cookie_options = get_cookie_options({
19
16
  expires: new Date(0),
20
17
  path: "/",
21
18
  });
19
+ response.cookies.set(get_cookie_name(BASE_COOKIE_NAMES.USER_EMAIL), "", clear_cookie_options);
20
+ response.cookies.set(get_cookie_name(BASE_COOKIE_NAMES.USER_ID), "", clear_cookie_options);
22
21
  return response;
23
22
  }
24
23
  // section: functions
@@ -30,8 +29,8 @@ function clear_auth_cookies(response) {
30
29
  */
31
30
  export async function get_authenticated_user(request) {
32
31
  var _a, _b;
33
- const user_id = (_a = request.cookies.get("hazo_auth_user_id")) === null || _a === void 0 ? void 0 : _a.value;
34
- const user_email = (_b = request.cookies.get("hazo_auth_user_email")) === null || _b === void 0 ? void 0 : _b.value;
32
+ const user_id = (_a = request.cookies.get(get_cookie_name(BASE_COOKIE_NAMES.USER_ID))) === null || _a === void 0 ? void 0 : _a.value;
33
+ const user_email = (_b = request.cookies.get(get_cookie_name(BASE_COOKIE_NAMES.USER_EMAIL))) === null || _b === void 0 ? void 0 : _b.value;
35
34
  if (!user_id || !user_email) {
36
35
  return { authenticated: false };
37
36
  }
@@ -100,8 +99,8 @@ export async function require_auth(request) {
100
99
  */
101
100
  export async function get_authenticated_user_with_response(request) {
102
101
  var _a, _b;
103
- const user_id = (_a = request.cookies.get("hazo_auth_user_id")) === null || _a === void 0 ? void 0 : _a.value;
104
- const user_email = (_b = request.cookies.get("hazo_auth_user_email")) === null || _b === void 0 ? void 0 : _b.value;
102
+ const user_id = (_a = request.cookies.get(get_cookie_name(BASE_COOKIE_NAMES.USER_ID))) === null || _a === void 0 ? void 0 : _a.value;
103
+ const user_email = (_b = request.cookies.get(get_cookie_name(BASE_COOKIE_NAMES.USER_EMAIL))) === null || _b === void 0 ? void 0 : _b.value;
105
104
  if (!user_id || !user_email) {
106
105
  return { auth_result: { authenticated: false } };
107
106
  }
@@ -30,8 +30,9 @@ export declare function validate_dev_lock_cookie(request: NextRequest): Promise<
30
30
  */
31
31
  export declare function validate_dev_lock_password(password: string): boolean;
32
32
  /**
33
- * Gets the dev lock cookie name
33
+ * Gets the dev lock cookie name (with configurable prefix)
34
34
  * Exported for use in API routes when setting the cookie
35
+ * Uses HAZO_AUTH_COOKIE_PREFIX env var for configurable prefix
35
36
  * @returns Cookie name string
36
37
  */
37
38
  export declare function get_dev_lock_cookie_name(): string;
@@ -1 +1 @@
1
- {"version":3,"file":"dev_lock_validator.edge.d.ts","sourceRoot":"","sources":["../../../src/lib/auth/dev_lock_validator.edge.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAO/C,MAAM,MAAM,uBAAuB,GAAG;IACpC,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAmDF;;;;;;GAMG;AACH,wBAAsB,sBAAsB,CAC1C,QAAQ,EAAE,MAAM,EAChB,WAAW,GAAE,MAAU,GACtB,OAAO,CAAC,iBAAiB,CAAC,CAU5B;AAED;;;;;GAKG;AACH,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,uBAAuB,CAAC,CA8ClC;AAED;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAQpE;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,IAAI,MAAM,CAEjD"}
1
+ {"version":3,"file":"dev_lock_validator.edge.d.ts","sourceRoot":"","sources":["../../../src/lib/auth/dev_lock_validator.edge.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAO/C,MAAM,MAAM,uBAAuB,GAAG;IACpC,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAmDF;;;;;;GAMG;AACH,wBAAsB,sBAAsB,CAC1C,QAAQ,EAAE,MAAM,EAChB,WAAW,GAAE,MAAU,GACtB,OAAO,CAAC,iBAAiB,CAAC,CAU5B;AAED;;;;;GAKG;AACH,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,uBAAuB,CAAC,CA8ClC;AAED;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAQpE;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,IAAI,MAAM,CAEjD"}
@@ -1,5 +1,5 @@
1
+ import { get_cookie_name_edge, BASE_COOKIE_NAMES } from "../cookies_config.edge";
1
2
  // section: constants
2
- const COOKIE_NAME = "hazo_auth_dev_lock";
3
3
  const SEPARATOR = "|";
4
4
  // section: helpers
5
5
  /**
@@ -67,7 +67,7 @@ export async function validate_dev_lock_cookie(request) {
67
67
  // No password set - cannot validate
68
68
  return { valid: false };
69
69
  }
70
- const cookie = (_a = request.cookies.get(COOKIE_NAME)) === null || _a === void 0 ? void 0 : _a.value;
70
+ const cookie = (_a = request.cookies.get(get_cookie_name_edge(BASE_COOKIE_NAMES.DEV_LOCK))) === null || _a === void 0 ? void 0 : _a.value;
71
71
  if (!cookie) {
72
72
  return { valid: false };
73
73
  }
@@ -113,10 +113,11 @@ export function validate_dev_lock_password(password) {
113
113
  return constant_time_compare(password, expected);
114
114
  }
115
115
  /**
116
- * Gets the dev lock cookie name
116
+ * Gets the dev lock cookie name (with configurable prefix)
117
117
  * Exported for use in API routes when setting the cookie
118
+ * Uses HAZO_AUTH_COOKIE_PREFIX env var for configurable prefix
118
119
  * @returns Cookie name string
119
120
  */
120
121
  export function get_dev_lock_cookie_name() {
121
- return COOKIE_NAME;
122
+ return get_cookie_name_edge(BASE_COOKIE_NAMES.DEV_LOCK);
122
123
  }
@@ -1 +1 @@
1
- {"version":3,"file":"hazo_get_auth.server.d.ts","sourceRoot":"","sources":["../../../src/lib/auth/hazo_get_auth.server.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAK1C,OAAO,KAAK,EAAE,cAAc,EAAgB,eAAe,EAAmB,MAAM,cAAc,CAAC;AA2XnG;;;;;;;;;GASG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,WAAW,EACpB,OAAO,CAAC,EAAE,eAAe,GACxB,OAAO,CAAC,cAAc,CAAC,CAwOzB"}
1
+ {"version":3,"file":"hazo_get_auth.server.d.ts","sourceRoot":"","sources":["../../../src/lib/auth/hazo_get_auth.server.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAK1C,OAAO,KAAK,EAAE,cAAc,EAAgB,eAAe,EAAmB,MAAM,cAAc,CAAC;AA4XnG;;;;;;;;;GASG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,WAAW,EACpB,OAAO,CAAC,EAAE,eAAe,GACxB,OAAO,CAAC,cAAc,CAAC,CAwOzB"}
@@ -13,6 +13,7 @@ import { check_user_scope_access, get_user_scopes } from "../services/user_scope
13
13
  import { is_valid_scope_level } from "../services/scope_service";
14
14
  import { is_multi_tenancy_enabled, get_multi_tenancy_config } from "../multi_tenancy_config.server";
15
15
  import { get_org_cache } from "./org_cache";
16
+ import { get_cookie_name, BASE_COOKIE_NAMES } from "../cookies_config.server";
16
17
  // section: helpers
17
18
  /**
18
19
  * Parse JSON string to object, returning null on failure
@@ -310,12 +311,12 @@ export async function hazo_get_auth(request, options) {
310
311
  const config = get_auth_utility_config();
311
312
  const cache = get_auth_cache(config.cache_max_users, config.cache_ttl_minutes, config.cache_max_age_minutes);
312
313
  const rate_limiter = get_rate_limiter();
313
- // Fast path: Check for authentication cookies
314
+ // Fast path: Check for authentication cookies (with configurable prefix)
314
315
  // Priority: 1. JWT session token (new), 2. Simple cookies (backward compatibility)
315
316
  let user_id;
316
317
  let user_email;
317
318
  // Check for JWT session token first
318
- const session_token = (_a = request.cookies.get("hazo_auth_session")) === null || _a === void 0 ? void 0 : _a.value;
319
+ const session_token = (_a = request.cookies.get(get_cookie_name(BASE_COOKIE_NAMES.SESSION))) === null || _a === void 0 ? void 0 : _a.value;
319
320
  if (session_token) {
320
321
  try {
321
322
  const token_result = await validate_session_token(session_token);
@@ -337,8 +338,8 @@ export async function hazo_get_auth(request, options) {
337
338
  }
338
339
  // Fall back to simple cookies if JWT not present or invalid (backward compatibility)
339
340
  if (!user_id || !user_email) {
340
- user_id = (_b = request.cookies.get("hazo_auth_user_id")) === null || _b === void 0 ? void 0 : _b.value;
341
- user_email = (_c = request.cookies.get("hazo_auth_user_email")) === null || _c === void 0 ? void 0 : _c.value;
341
+ user_id = (_b = request.cookies.get(get_cookie_name(BASE_COOKIE_NAMES.USER_ID))) === null || _b === void 0 ? void 0 : _b.value;
342
+ user_email = (_c = request.cookies.get(get_cookie_name(BASE_COOKIE_NAMES.USER_EMAIL))) === null || _c === void 0 ? void 0 : _c.value;
342
343
  }
343
344
  if (!user_id || !user_email) {
344
345
  // Unauthenticated - check rate limit by IP
@@ -1 +1 @@
1
- {"version":3,"file":"server_auth.d.ts","sourceRoot":"","sources":["../../../src/lib/auth/server_auth.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,cAAc,GAAG;IAC3B,aAAa,EAAE,IAAI,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,OAAO,CAAC;IACxB,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,cAAc,CAAC,EAAE,QAAQ,GAAG,SAAS,GAAG,UAAU,GAAG,QAAQ,CAAC;CAC/D,CAAC;AAEF,MAAM,MAAM,gBAAgB,GACxB,cAAc,GACd;IAAE,aAAa,EAAE,KAAK,CAAA;CAAE,CAAC;AAG7B;;;;GAIG;AACH,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,gBAAgB,CAAC,CA+CtE;AAED;;;GAGG;AACH,wBAAsB,uBAAuB,IAAI,OAAO,CAAC,OAAO,CAAC,CAGhE"}
1
+ {"version":3,"file":"server_auth.d.ts","sourceRoot":"","sources":["../../../src/lib/auth/server_auth.ts"],"names":[],"mappings":"AASA,MAAM,MAAM,cAAc,GAAG;IAC3B,aAAa,EAAE,IAAI,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,OAAO,CAAC;IACxB,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,cAAc,CAAC,EAAE,QAAQ,GAAG,SAAS,GAAG,UAAU,GAAG,QAAQ,CAAC;CAC/D,CAAC;AAEF,MAAM,MAAM,gBAAgB,GACxB,cAAc,GACd;IAAE,aAAa,EAAE,KAAK,CAAA;CAAE,CAAC;AAG7B;;;;GAIG;AACH,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,gBAAgB,CAAC,CA+CtE;AAED;;;GAGG;AACH,wBAAsB,uBAAuB,IAAI,OAAO,CAAC,OAAO,CAAC,CAGhE"}
@@ -4,6 +4,7 @@ import { cookies } from "next/headers";
4
4
  import { get_hazo_connect_instance } from "../hazo_connect_instance.server";
5
5
  import { createCrudService } from "hazo_connect/server";
6
6
  import { map_db_source_to_ui } from "../services/profile_picture_source_mapper";
7
+ import { get_cookie_name, BASE_COOKIE_NAMES } from "../cookies_config.server";
7
8
  // section: functions
8
9
  /**
9
10
  * Gets authenticated user in server components/pages
@@ -13,8 +14,8 @@ import { map_db_source_to_ui } from "../services/profile_picture_source_mapper";
13
14
  export async function get_server_auth_user() {
14
15
  var _a, _b;
15
16
  const cookie_store = await cookies();
16
- const user_id = (_a = cookie_store.get("hazo_auth_user_id")) === null || _a === void 0 ? void 0 : _a.value;
17
- const user_email = (_b = cookie_store.get("hazo_auth_user_email")) === null || _b === void 0 ? void 0 : _b.value;
17
+ const user_id = (_a = cookie_store.get(get_cookie_name(BASE_COOKIE_NAMES.USER_ID))) === null || _a === void 0 ? void 0 : _a.value;
18
+ const user_email = (_b = cookie_store.get(get_cookie_name(BASE_COOKIE_NAMES.USER_EMAIL))) === null || _b === void 0 ? void 0 : _b.value;
18
19
  if (!user_id || !user_email) {
19
20
  return { authenticated: false };
20
21
  }
@@ -8,6 +8,7 @@ export type ValidateSessionCookieResult = {
8
8
  * Validates session cookie from NextRequest (Edge-compatible)
9
9
  * Extracts hazo_auth_session cookie and validates JWT signature and expiry
10
10
  * Works in Edge Runtime (Next.js proxy/middleware)
11
+ * Uses HAZO_AUTH_COOKIE_PREFIX env var for configurable cookie name
11
12
  * @param request - NextRequest object
12
13
  * @returns Validation result with user_id and email if valid
13
14
  */
@@ -1 +1 @@
1
- {"version":3,"file":"session_token_validator.edge.d.ts","sourceRoot":"","sources":["../../../src/lib/auth/session_token_validator.edge.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG/C,MAAM,MAAM,2BAA2B,GAAG;IACxC,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAsBF;;;;;;GAMG;AACH,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,2BAA2B,CAAC,CAwCtC"}
1
+ {"version":3,"file":"session_token_validator.edge.d.ts","sourceRoot":"","sources":["../../../src/lib/auth/session_token_validator.edge.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAI/C,MAAM,MAAM,2BAA2B,GAAG;IACxC,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAsBF;;;;;;;GAOG;AACH,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,2BAA2B,CAAC,CAwCtC"}
@@ -2,6 +2,7 @@
2
2
  // Uses jose library which works in Edge Runtime
3
3
  // section: imports
4
4
  import { jwtVerify } from "jose";
5
+ import { get_cookie_name_edge, BASE_COOKIE_NAMES } from "../cookies_config.edge";
5
6
  // section: helpers
6
7
  /**
7
8
  * Gets JWT secret from environment variables
@@ -23,14 +24,15 @@ function get_jwt_secret() {
23
24
  * Validates session cookie from NextRequest (Edge-compatible)
24
25
  * Extracts hazo_auth_session cookie and validates JWT signature and expiry
25
26
  * Works in Edge Runtime (Next.js proxy/middleware)
27
+ * Uses HAZO_AUTH_COOKIE_PREFIX env var for configurable cookie name
26
28
  * @param request - NextRequest object
27
29
  * @returns Validation result with user_id and email if valid
28
30
  */
29
31
  export async function validate_session_cookie(request) {
30
32
  var _a;
31
33
  try {
32
- // Extract session cookie
33
- const session_cookie = (_a = request.cookies.get("hazo_auth_session")) === null || _a === void 0 ? void 0 : _a.value;
34
+ // Extract session cookie (with configurable prefix from env var)
35
+ const session_cookie = (_a = request.cookies.get(get_cookie_name_edge(BASE_COOKIE_NAMES.SESSION))) === null || _a === void 0 ? void 0 : _a.value;
34
36
  if (!session_cookie) {
35
37
  return { valid: false };
36
38
  }
@@ -0,0 +1,33 @@
1
+ export declare const BASE_COOKIE_NAMES: {
2
+ readonly USER_ID: "hazo_auth_user_id";
3
+ readonly USER_EMAIL: "hazo_auth_user_email";
4
+ readonly SESSION: "hazo_auth_session";
5
+ readonly DEV_LOCK: "hazo_auth_dev_lock";
6
+ };
7
+ /**
8
+ * Gets the cookie prefix from environment variable
9
+ * For Edge runtime, use HAZO_AUTH_COOKIE_PREFIX env var
10
+ * @returns Cookie prefix string (empty string if not set)
11
+ */
12
+ export declare function get_cookie_prefix_edge(): string;
13
+ /**
14
+ * Gets the cookie domain from environment variable
15
+ * For Edge runtime, use HAZO_AUTH_COOKIE_DOMAIN env var
16
+ * @returns Cookie domain string (empty string if not set)
17
+ */
18
+ export declare function get_cookie_domain_edge(): string;
19
+ /**
20
+ * Gets the full cookie name with prefix applied (Edge-compatible)
21
+ * @param base_name - Base cookie name from BASE_COOKIE_NAMES
22
+ * @returns Full cookie name with prefix
23
+ */
24
+ export declare function get_cookie_name_edge(base_name: string): string;
25
+ /**
26
+ * Gets cookie options with domain if configured (Edge-compatible)
27
+ * @param options - Base cookie options
28
+ * @returns Cookie options with domain added if configured
29
+ */
30
+ export declare function get_cookie_options_edge<T extends Record<string, unknown>>(options: T): T & {
31
+ domain?: string;
32
+ };
33
+ //# sourceMappingURL=cookies_config.edge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cookies_config.edge.d.ts","sourceRoot":"","sources":["../../src/lib/cookies_config.edge.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,iBAAiB;;;;;CAKpB,CAAC;AAGX;;;;GAIG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,CAE/C;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,CAE/C;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAG9D;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC,GAAG,CAAC,GAAG;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAQ9G"}
@@ -0,0 +1,48 @@
1
+ // file_description: Edge-compatible cookie configuration helper
2
+ // Uses environment variables since Edge runtime can't read config files
3
+ // section: constants
4
+ // Base cookie names (without prefix)
5
+ export const BASE_COOKIE_NAMES = {
6
+ USER_ID: "hazo_auth_user_id",
7
+ USER_EMAIL: "hazo_auth_user_email",
8
+ SESSION: "hazo_auth_session",
9
+ DEV_LOCK: "hazo_auth_dev_lock",
10
+ };
11
+ // section: main_functions
12
+ /**
13
+ * Gets the cookie prefix from environment variable
14
+ * For Edge runtime, use HAZO_AUTH_COOKIE_PREFIX env var
15
+ * @returns Cookie prefix string (empty string if not set)
16
+ */
17
+ export function get_cookie_prefix_edge() {
18
+ return process.env.HAZO_AUTH_COOKIE_PREFIX || "";
19
+ }
20
+ /**
21
+ * Gets the cookie domain from environment variable
22
+ * For Edge runtime, use HAZO_AUTH_COOKIE_DOMAIN env var
23
+ * @returns Cookie domain string (empty string if not set)
24
+ */
25
+ export function get_cookie_domain_edge() {
26
+ return process.env.HAZO_AUTH_COOKIE_DOMAIN || "";
27
+ }
28
+ /**
29
+ * Gets the full cookie name with prefix applied (Edge-compatible)
30
+ * @param base_name - Base cookie name from BASE_COOKIE_NAMES
31
+ * @returns Full cookie name with prefix
32
+ */
33
+ export function get_cookie_name_edge(base_name) {
34
+ const prefix = get_cookie_prefix_edge();
35
+ return `${prefix}${base_name}`;
36
+ }
37
+ /**
38
+ * Gets cookie options with domain if configured (Edge-compatible)
39
+ * @param options - Base cookie options
40
+ * @returns Cookie options with domain added if configured
41
+ */
42
+ export function get_cookie_options_edge(options) {
43
+ const domain = get_cookie_domain_edge();
44
+ if (domain) {
45
+ return Object.assign(Object.assign({}, options), { domain });
46
+ }
47
+ return options;
48
+ }
@@ -0,0 +1,42 @@
1
+ export type CookiesConfig = {
2
+ /** Prefix for all hazo_auth cookies (e.g., "myapp_" results in "myapp_hazo_auth_session") */
3
+ cookie_prefix: string;
4
+ /** Optional domain for cookies (e.g., ".example.com" for cross-subdomain) */
5
+ cookie_domain: string;
6
+ };
7
+ export declare const BASE_COOKIE_NAMES: {
8
+ readonly USER_ID: "hazo_auth_user_id";
9
+ readonly USER_EMAIL: "hazo_auth_user_email";
10
+ readonly SESSION: "hazo_auth_session";
11
+ readonly DEV_LOCK: "hazo_auth_dev_lock";
12
+ };
13
+ /**
14
+ * Reads cookie configuration from hazo_auth_config.ini file
15
+ * Falls back to defaults if hazo_auth_config.ini is not found or section is missing
16
+ * @returns CookiesConfig object with all cookie settings
17
+ */
18
+ export declare function get_cookies_config(): CookiesConfig;
19
+ /**
20
+ * Gets the full cookie name with prefix applied
21
+ * @param base_name - Base cookie name from BASE_COOKIE_NAMES
22
+ * @returns Full cookie name with prefix
23
+ */
24
+ export declare function get_cookie_name(base_name: string): string;
25
+ /**
26
+ * Gets cookie options with domain if configured
27
+ * @param options - Base cookie options
28
+ * @returns Cookie options with domain added if configured
29
+ */
30
+ export declare function get_cookie_options<T extends Record<string, unknown>>(options: T): T & {
31
+ domain?: string;
32
+ };
33
+ /**
34
+ * Gets cached cookie configuration for performance-critical paths
35
+ * @returns CookiesConfig object
36
+ */
37
+ export declare function get_cached_cookies_config(): CookiesConfig;
38
+ /**
39
+ * Clears the cached config (useful for testing)
40
+ */
41
+ export declare function clear_cookies_config_cache(): void;
42
+ //# sourceMappingURL=cookies_config.server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cookies_config.server.d.ts","sourceRoot":"","sources":["../../src/lib/cookies_config.server.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,aAAa,GAAG;IAC1B,6FAA6F;IAC7F,aAAa,EAAE,MAAM,CAAC;IACtB,6EAA6E;IAC7E,aAAa,EAAE,MAAM,CAAC;CACvB,CAAC;AAYF,eAAO,MAAM,iBAAiB;;;;;CAKpB,CAAC;AAGX;;;;GAIG;AACH,wBAAgB,kBAAkB,IAAI,aAAa,CAWlD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAGzD;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC,GAAG,CAAC,GAAG;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAQzG;AAKD;;;GAGG;AACH,wBAAgB,yBAAyB,IAAI,aAAa,CAKzD;AAED;;GAEG;AACH,wBAAgB,0BAA0B,IAAI,IAAI,CAEjD"}
@@ -0,0 +1,71 @@
1
+ // file_description: server-only helper to read cookie configuration from hazo_auth_config.ini
2
+ import { read_config_section } from "./config/config_loader.server";
3
+ // section: defaults
4
+ const DEFAULT_CONFIG = {
5
+ cookie_prefix: "",
6
+ cookie_domain: "",
7
+ };
8
+ // section: constants
9
+ const SECTION_NAME = "hazo_auth__cookies";
10
+ // Base cookie names (without prefix)
11
+ export const BASE_COOKIE_NAMES = {
12
+ USER_ID: "hazo_auth_user_id",
13
+ USER_EMAIL: "hazo_auth_user_email",
14
+ SESSION: "hazo_auth_session",
15
+ DEV_LOCK: "hazo_auth_dev_lock",
16
+ };
17
+ // section: main_function
18
+ /**
19
+ * Reads cookie configuration from hazo_auth_config.ini file
20
+ * Falls back to defaults if hazo_auth_config.ini is not found or section is missing
21
+ * @returns CookiesConfig object with all cookie settings
22
+ */
23
+ export function get_cookies_config() {
24
+ const section = read_config_section(SECTION_NAME);
25
+ if (!section) {
26
+ return DEFAULT_CONFIG;
27
+ }
28
+ return {
29
+ cookie_prefix: section.cookie_prefix || DEFAULT_CONFIG.cookie_prefix,
30
+ cookie_domain: section.cookie_domain || DEFAULT_CONFIG.cookie_domain,
31
+ };
32
+ }
33
+ /**
34
+ * Gets the full cookie name with prefix applied
35
+ * @param base_name - Base cookie name from BASE_COOKIE_NAMES
36
+ * @returns Full cookie name with prefix
37
+ */
38
+ export function get_cookie_name(base_name) {
39
+ const config = get_cookies_config();
40
+ return `${config.cookie_prefix}${base_name}`;
41
+ }
42
+ /**
43
+ * Gets cookie options with domain if configured
44
+ * @param options - Base cookie options
45
+ * @returns Cookie options with domain added if configured
46
+ */
47
+ export function get_cookie_options(options) {
48
+ const config = get_cookies_config();
49
+ if (config.cookie_domain) {
50
+ return Object.assign(Object.assign({}, options), { domain: config.cookie_domain });
51
+ }
52
+ return options;
53
+ }
54
+ // Cached config for performance (module-level cache)
55
+ let cached_config = null;
56
+ /**
57
+ * Gets cached cookie configuration for performance-critical paths
58
+ * @returns CookiesConfig object
59
+ */
60
+ export function get_cached_cookies_config() {
61
+ if (!cached_config) {
62
+ cached_config = get_cookies_config();
63
+ }
64
+ return cached_config;
65
+ }
66
+ /**
67
+ * Clears the cached config (useful for testing)
68
+ */
69
+ export function clear_cookies_config_cache() {
70
+ cached_config = null;
71
+ }
@@ -3,6 +3,21 @@
3
3
  # Copy this file to your project root as hazo_auth_config.ini and customize the values
4
4
  # Commented values indicate defaults that are being used
5
5
 
6
+ [hazo_auth__cookies]
7
+ # Cookie configuration for hazo_auth
8
+ # Use these settings to avoid conflicts when running multiple apps with hazo_auth
9
+
10
+ # Cookie prefix (default: empty)
11
+ # Add a unique prefix for each app to avoid cookie conflicts
12
+ # Example: "myapp_" results in cookies named "myapp_hazo_auth_session", etc.
13
+ # IMPORTANT: For Edge runtime (middleware), also set HAZO_AUTH_COOKIE_PREFIX env var
14
+ # cookie_prefix =
15
+
16
+ # Cookie domain (default: empty, uses current domain)
17
+ # Set to share cookies across subdomains (e.g., ".example.com")
18
+ # IMPORTANT: For Edge runtime (middleware), also set HAZO_AUTH_COOKIE_DOMAIN env var
19
+ # cookie_domain =
20
+
6
21
  [hazo_connect]
7
22
  # Database type: sqlite, postgrest, supabase, or file
8
23
  type = sqlite
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hazo_auth",
3
- "version": "4.5.7",
3
+ "version": "4.6.0",
4
4
  "description": "Zero-config authentication UI components for Next.js with RBAC, OAuth, multi-tenancy, and hierarchical scopes",
5
5
  "keywords": [
6
6
  "authentication",