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.
- package/README.md +16 -0
- package/SETUP_CHECKLIST.md +16 -0
- package/cli-src/lib/auth/auth_utils.server.ts +9 -10
- package/cli-src/lib/auth/dev_lock_validator.edge.ts +5 -4
- package/cli-src/lib/auth/hazo_get_auth.server.ts +6 -5
- package/cli-src/lib/auth/server_auth.ts +3 -2
- package/cli-src/lib/auth/session_token_validator.edge.ts +4 -2
- package/cli-src/lib/cookies_config.edge.ts +55 -0
- package/cli-src/lib/cookies_config.server.ts +93 -0
- package/dist/app/api/hazo_auth/login/route.d.ts.map +1 -1
- package/dist/app/api/hazo_auth/login/route.js +8 -17
- package/dist/app/api/hazo_auth/logout/route.d.ts.map +1 -1
- package/dist/app/api/hazo_auth/logout/route.js +9 -13
- package/dist/app/api/hazo_auth/update_user/route.d.ts.map +1 -1
- package/dist/app/api/hazo_auth/update_user/route.js +6 -3
- package/dist/components/layouts/shared/components/profile_pic_menu.d.ts.map +1 -1
- package/dist/components/layouts/shared/components/profile_pic_menu.js +49 -43
- package/dist/lib/auth/auth_utils.server.d.ts.map +1 -1
- package/dist/lib/auth/auth_utils.server.js +9 -10
- package/dist/lib/auth/dev_lock_validator.edge.d.ts +2 -1
- package/dist/lib/auth/dev_lock_validator.edge.d.ts.map +1 -1
- package/dist/lib/auth/dev_lock_validator.edge.js +5 -4
- package/dist/lib/auth/hazo_get_auth.server.d.ts.map +1 -1
- package/dist/lib/auth/hazo_get_auth.server.js +5 -4
- package/dist/lib/auth/server_auth.d.ts.map +1 -1
- package/dist/lib/auth/server_auth.js +3 -2
- package/dist/lib/auth/session_token_validator.edge.d.ts +1 -0
- package/dist/lib/auth/session_token_validator.edge.d.ts.map +1 -1
- package/dist/lib/auth/session_token_validator.edge.js +4 -2
- package/dist/lib/cookies_config.edge.d.ts +33 -0
- package/dist/lib/cookies_config.edge.d.ts.map +1 -0
- package/dist/lib/cookies_config.edge.js +48 -0
- package/dist/lib/cookies_config.server.d.ts +42 -0
- package/dist/lib/cookies_config.server.d.ts.map +1 -0
- package/dist/lib/cookies_config.server.js +71 -0
- package/hazo_auth_config.example.ini +15 -0
- 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
|
---
|
package/SETUP_CHECKLIST.md
CHANGED
|
@@ -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
|
-
|
|
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(
|
|
52
|
-
const user_email = request.cookies.get(
|
|
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(
|
|
136
|
-
const user_email = request.cookies.get(
|
|
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(
|
|
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
|
|
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(
|
|
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(
|
|
439
|
-
user_email = request.cookies.get(
|
|
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(
|
|
34
|
-
const user_email = cookie_store.get(
|
|
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(
|
|
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;
|
|
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
|
-
|
|
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
|
-
|
|
122
|
-
|
|
123
|
-
|
|
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(
|
|
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;
|
|
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(
|
|
15
|
-
const user_id = (_b = request.cookies.get(
|
|
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
|
-
|
|
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(
|
|
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;
|
|
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
|
-
|
|
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":"
|
|
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:
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
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 (
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
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;
|
|
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
|
-
|
|
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(
|
|
34
|
-
const user_email = (_b = request.cookies.get(
|
|
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(
|
|
104
|
-
const user_email = (_b = request.cookies.get(
|
|
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
|
|
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(
|
|
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
|
|
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;
|
|
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(
|
|
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(
|
|
341
|
-
user_email = (_c = request.cookies.get(
|
|
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":"
|
|
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(
|
|
17
|
-
const user_email = (_b = cookie_store.get(
|
|
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;
|
|
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(
|
|
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
|