hazo_auth 5.1.33 → 5.1.35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -3
- package/cli-src/lib/register_config.server.ts +24 -0
- package/cli-src/lib/utils/proxy_request.ts +81 -0
- package/dist/components/layouts/register/index.d.ts +13 -1
- package/dist/components/layouts/register/index.d.ts.map +1 -1
- package/dist/components/layouts/register/index.js +28 -2
- package/dist/components/ui/button.d.ts +1 -1
- package/dist/lib/register_config.server.d.ts +7 -0
- package/dist/lib/register_config.server.d.ts.map +1 -1
- package/dist/lib/register_config.server.js +11 -0
- package/dist/lib/utils/proxy_request.d.ts +20 -0
- package/dist/lib/utils/proxy_request.d.ts.map +1 -0
- package/dist/lib/utils/proxy_request.js +74 -0
- package/dist/server/routes/nextauth.d.ts.map +1 -1
- package/dist/server/routes/nextauth.js +89 -43
- package/dist/server/routes/oauth_google_callback.d.ts +1 -1
- package/dist/server/routes/oauth_google_callback.d.ts.map +1 -1
- package/dist/server/routes/oauth_google_callback.js +19 -8
- package/dist/server_pages/register.d.ts.map +1 -1
- package/dist/server_pages/register.js +6 -1
- package/dist/server_pages/register_client_wrapper.d.ts +5 -2
- package/dist/server_pages/register_client_wrapper.d.ts.map +1 -1
- package/dist/server_pages/register_client_wrapper.js +2 -2
- package/package.json +2 -2
- package/dist/lib/index.d.ts +0 -32
- package/dist/lib/index.d.ts.map +0 -1
- package/dist/lib/index.js +0 -37
package/README.md
CHANGED
|
@@ -251,7 +251,7 @@ export default function Page() {
|
|
|
251
251
|
| Page | Import | Description |
|
|
252
252
|
|------|--------|-------------|
|
|
253
253
|
| **LoginPage** | `hazo_auth/pages/login` | Login form with forgot password link |
|
|
254
|
-
| **RegisterPage** | `hazo_auth/pages/register` | Registration with password validation |
|
|
254
|
+
| **RegisterPage** | `hazo_auth/pages/register` | Registration with password validation and OAuth support |
|
|
255
255
|
| **ForgotPasswordPage** | `hazo_auth/pages/forgot_password` | Request password reset email |
|
|
256
256
|
| **ResetPasswordPage** | `hazo_auth/pages/reset_password` | Set new password with token |
|
|
257
257
|
| **VerifyEmailPage** | `hazo_auth/pages/verify_email` | Email verification handler |
|
|
@@ -926,7 +926,7 @@ hazo_auth supports Google Sign-In via NextAuth.js v4, allowing users to authenti
|
|
|
926
926
|
|
|
927
927
|
- **Dual authentication**: Users can have BOTH Google OAuth and email/password login
|
|
928
928
|
- **Auto-linking**: Automatically links Google login to existing unverified email/password accounts
|
|
929
|
-
- **Graceful degradation**: Login
|
|
929
|
+
- **Graceful degradation**: Login and register pages adapt based on enabled authentication methods
|
|
930
930
|
- **Set password feature**: Google-only users can add a password later via My Settings
|
|
931
931
|
- **Profile data**: Full name and profile picture automatically populated from Google
|
|
932
932
|
|
|
@@ -1018,6 +1018,7 @@ auto_link_unverified_accounts = true
|
|
|
1018
1018
|
|
|
1019
1019
|
# Customize button text (optional)
|
|
1020
1020
|
google_button_text = Continue with Google
|
|
1021
|
+
google_button_text_register = Sign up with Google
|
|
1021
1022
|
oauth_divider_text = or
|
|
1022
1023
|
|
|
1023
1024
|
# Post-Login Redirect Configuration (v5.1.16+)
|
|
@@ -1266,7 +1267,7 @@ export default async function LoginPage() {
|
|
|
1266
1267
|
|
|
1267
1268
|
**Available Layout Components:**
|
|
1268
1269
|
- `LoginLayout` - Login form with email/password
|
|
1269
|
-
- `RegisterLayout` - Registration form with password requirements
|
|
1270
|
+
- `RegisterLayout` - Registration form with password requirements and OAuth (Google Sign-In)
|
|
1270
1271
|
- `ForgotPasswordLayout` - Request password reset
|
|
1271
1272
|
- `ResetPasswordLayout` - Set new password with token
|
|
1272
1273
|
- `EmailVerificationLayout` - Verify email address
|
|
@@ -7,6 +7,7 @@ import { get_config_boolean, get_config_value, read_config_section } from "./con
|
|
|
7
7
|
import { get_password_requirements_config } from "./password_requirements_config.server.js";
|
|
8
8
|
import { get_already_logged_in_config } from "./already_logged_in_config.server.js";
|
|
9
9
|
import { get_user_fields_config } from "./user_fields_config.server.js";
|
|
10
|
+
import { get_oauth_config } from "./oauth_config.server.js";
|
|
10
11
|
|
|
11
12
|
// Default image path - consuming apps should either:
|
|
12
13
|
// 1. Configure their own image_src in hazo_auth_config.ini
|
|
@@ -33,6 +34,13 @@ export type RegisterConfig = {
|
|
|
33
34
|
imageSrc: string;
|
|
34
35
|
imageAlt: string;
|
|
35
36
|
imageBackgroundColor: string;
|
|
37
|
+
/** OAuth configuration */
|
|
38
|
+
oauth: {
|
|
39
|
+
enable_google: boolean;
|
|
40
|
+
enable_email_password: boolean;
|
|
41
|
+
google_button_text: string;
|
|
42
|
+
oauth_divider_text: string;
|
|
43
|
+
};
|
|
36
44
|
};
|
|
37
45
|
|
|
38
46
|
// section: helpers
|
|
@@ -89,6 +97,16 @@ export function get_register_config(): RegisterConfig {
|
|
|
89
97
|
"#e2e8f0"
|
|
90
98
|
);
|
|
91
99
|
|
|
100
|
+
// Get OAuth configuration (shared with login)
|
|
101
|
+
const oauthConfig = get_oauth_config();
|
|
102
|
+
|
|
103
|
+
// For the register page, default button text to "Sign up with Google" unless overridden
|
|
104
|
+
const registerGoogleButtonText = get_config_value(
|
|
105
|
+
"hazo_auth__oauth",
|
|
106
|
+
"google_button_text_register",
|
|
107
|
+
"Sign up with Google"
|
|
108
|
+
);
|
|
109
|
+
|
|
92
110
|
return {
|
|
93
111
|
showNameField,
|
|
94
112
|
passwordRequirements,
|
|
@@ -102,6 +120,12 @@ export function get_register_config(): RegisterConfig {
|
|
|
102
120
|
imageSrc,
|
|
103
121
|
imageAlt,
|
|
104
122
|
imageBackgroundColor,
|
|
123
|
+
oauth: {
|
|
124
|
+
enable_google: oauthConfig.enable_google,
|
|
125
|
+
enable_email_password: oauthConfig.enable_email_password,
|
|
126
|
+
google_button_text: registerGoogleButtonText,
|
|
127
|
+
oauth_divider_text: oauthConfig.oauth_divider_text,
|
|
128
|
+
},
|
|
105
129
|
};
|
|
106
130
|
}
|
|
107
131
|
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// file_description: Shared utility for rewriting request.url behind reverse proxies (Cloudflare Tunnel, nginx, AWS ALB)
|
|
2
|
+
import { NextRequest } from "next/server";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Detects the public-facing origin from proxy headers.
|
|
6
|
+
* Returns null if not behind a proxy (origins match).
|
|
7
|
+
*/
|
|
8
|
+
function detect_public_origin(request_url: URL, headers: Headers): string | null {
|
|
9
|
+
// Priority 1: NEXTAUTH_URL env var (explicitly configured)
|
|
10
|
+
const nextauth_url = process.env.NEXTAUTH_URL;
|
|
11
|
+
if (nextauth_url) {
|
|
12
|
+
try {
|
|
13
|
+
const public_origin = new URL(nextauth_url).origin;
|
|
14
|
+
if (public_origin !== request_url.origin) {
|
|
15
|
+
return public_origin;
|
|
16
|
+
}
|
|
17
|
+
} catch {
|
|
18
|
+
// Invalid NEXTAUTH_URL, fall through
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Priority 2: x-forwarded-host header (set by Cloudflare Tunnel, nginx, etc.)
|
|
23
|
+
const forwarded_host = headers.get("x-forwarded-host");
|
|
24
|
+
if (forwarded_host && forwarded_host !== request_url.hostname) {
|
|
25
|
+
const proto = headers.get("x-forwarded-proto") || "https";
|
|
26
|
+
return `${proto}://${forwarded_host}`;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Priority 3: host header (Cloudflare Tunnel also sets this)
|
|
30
|
+
const host_header = headers.get("host");
|
|
31
|
+
if (host_header && host_header !== request_url.host) {
|
|
32
|
+
const proto = headers.get("x-forwarded-proto") || "https";
|
|
33
|
+
return `${proto}://${host_header}`;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Rewrites request.url to use the public-facing origin when behind a reverse proxy.
|
|
41
|
+
*
|
|
42
|
+
* Behind proxies like Cloudflare Tunnel, Next.js sets request.url to the internal
|
|
43
|
+
* address (e.g., https://localhost:3000). This causes NextResponse.redirect() to
|
|
44
|
+
* resolve Location headers against the internal origin instead of the public domain.
|
|
45
|
+
*
|
|
46
|
+
* Apply this at the TOP of any route handler that uses NextResponse.redirect().
|
|
47
|
+
*
|
|
48
|
+
* @param request - The incoming NextRequest
|
|
49
|
+
* @returns A new NextRequest with corrected URL, or the original if no proxy detected
|
|
50
|
+
*/
|
|
51
|
+
export function rewrite_request_for_proxy(request: NextRequest): NextRequest {
|
|
52
|
+
try {
|
|
53
|
+
const request_url = new URL(request.url);
|
|
54
|
+
const public_origin = detect_public_origin(request_url, request.headers);
|
|
55
|
+
|
|
56
|
+
if (!public_origin) {
|
|
57
|
+
return request; // Not behind a proxy, no rewriting needed
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Construct corrected URL: public origin + original path + query
|
|
61
|
+
const corrected_url = `${public_origin}${request_url.pathname}${request_url.search}`;
|
|
62
|
+
|
|
63
|
+
// Create new NextRequest with corrected URL, preserving everything else
|
|
64
|
+
return new NextRequest(corrected_url, {
|
|
65
|
+
method: request.method,
|
|
66
|
+
headers: request.headers,
|
|
67
|
+
body: request.body,
|
|
68
|
+
});
|
|
69
|
+
} catch {
|
|
70
|
+
return request;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Gets the public-facing origin for constructing redirect URLs.
|
|
76
|
+
* Use this when you need the origin string but don't need to rewrite the request.
|
|
77
|
+
*/
|
|
78
|
+
export function get_public_origin(request: NextRequest): string {
|
|
79
|
+
const request_url = new URL(request.url);
|
|
80
|
+
return detect_public_origin(request_url, request.headers) || request_url.origin;
|
|
81
|
+
}
|
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
import { type ButtonPaletteOverrides, type LayoutFieldMapOverrides, type LayoutLabelOverrides, type PasswordRequirementOverrides } from "../shared/config/layout_customization.js";
|
|
2
2
|
import { type LayoutDataClient } from "../shared/data/layout_data_client.js";
|
|
3
3
|
import type { StaticImageData } from "next/image";
|
|
4
|
+
export type OAuthLayoutConfig = {
|
|
5
|
+
/** Enable Google OAuth login */
|
|
6
|
+
enable_google: boolean;
|
|
7
|
+
/** Enable traditional email/password login */
|
|
8
|
+
enable_email_password: boolean;
|
|
9
|
+
/** Text displayed on the Google sign-in button */
|
|
10
|
+
google_button_text: string;
|
|
11
|
+
/** Text displayed on the divider between OAuth and email/password form */
|
|
12
|
+
oauth_divider_text: string;
|
|
13
|
+
};
|
|
4
14
|
export type RegisterLayoutProps<TClient = unknown> = {
|
|
5
15
|
image_src: string | StaticImageData;
|
|
6
16
|
image_alt: string;
|
|
@@ -19,6 +29,8 @@ export type RegisterLayoutProps<TClient = unknown> = {
|
|
|
19
29
|
signInPath?: string;
|
|
20
30
|
signInLabel?: string;
|
|
21
31
|
urlOnLogon?: string;
|
|
32
|
+
/** OAuth configuration */
|
|
33
|
+
oauth?: OAuthLayoutConfig;
|
|
22
34
|
};
|
|
23
|
-
export default function register_layout<TClient>({ image_src, image_alt, image_background_color, field_overrides, labels, button_colors, password_requirements, show_name_field, data_client, alreadyLoggedInMessage, showLogoutButton, showReturnHomeButton, returnHomeButtonLabel, returnHomePath, signInPath, signInLabel, urlOnLogon, }: RegisterLayoutProps<TClient>): import("react/jsx-runtime").JSX.Element;
|
|
35
|
+
export default function register_layout<TClient>({ image_src, image_alt, image_background_color, field_overrides, labels, button_colors, password_requirements, show_name_field, data_client, alreadyLoggedInMessage, showLogoutButton, showReturnHomeButton, returnHomeButtonLabel, returnHomePath, signInPath, signInLabel, urlOnLogon, oauth, }: RegisterLayoutProps<TClient>): import("react/jsx-runtime").JSX.Element;
|
|
24
36
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/layouts/register/index.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/layouts/register/index.tsx"],"names":[],"mappings":"AAiBA,OAAO,EACL,KAAK,sBAAsB,EAC3B,KAAK,uBAAuB,EAC5B,KAAK,oBAAoB,EACzB,KAAK,4BAA4B,EAClC,MAAM,uCAAuC,CAAC;AAY/C,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAC1E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAGlD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,gCAAgC;IAChC,aAAa,EAAE,OAAO,CAAC;IACvB,8CAA8C;IAC9C,qBAAqB,EAAE,OAAO,CAAC;IAC/B,kDAAkD;IAClD,kBAAkB,EAAE,MAAM,CAAC;IAC3B,0EAA0E;IAC1E,kBAAkB,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,mBAAmB,CAAC,OAAO,GAAG,OAAO,IAAI;IACnD,SAAS,EAAE,MAAM,GAAG,eAAe,CAAC;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,eAAe,CAAC,EAAE,uBAAuB,CAAC;IAC1C,MAAM,CAAC,EAAE,oBAAoB,CAAC;IAC9B,aAAa,CAAC,EAAE,sBAAsB,CAAC;IACvC,qBAAqB,CAAC,EAAE,4BAA4B,CAAC;IACrD,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,WAAW,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAC;IACvC,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,0BAA0B;IAC1B,KAAK,CAAC,EAAE,iBAAiB,CAAC;CAC3B,CAAC;AAYF,MAAM,CAAC,OAAO,UAAU,eAAe,CAAC,OAAO,EAAE,EAC/C,SAAS,EACT,SAAS,EACT,sBAAkC,EAClC,eAAe,EACf,MAAM,EACN,aAAa,EACb,qBAAqB,EACrB,eAAsB,EACtB,WAAW,EACX,sBAAoD,EACpD,gBAAuB,EACvB,oBAA4B,EAC5B,qBAAqC,EACrC,cAAoB,EACpB,UAA+B,EAC/B,WAAuB,EACvB,UAAU,EACV,KAAK,GACN,EAAE,mBAAmB,CAAC,OAAO,CAAC,2CAgN9B"}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
5
5
|
// section: imports
|
|
6
6
|
import Link from "next/link";
|
|
7
|
+
import { useSearchParams } from "next/navigation";
|
|
7
8
|
import { Input } from "../../ui/input.js";
|
|
8
9
|
import { PasswordField } from "../shared/components/password_field.js";
|
|
9
10
|
import { FormFieldWrapper } from "../shared/components/form_field_wrapper.js";
|
|
@@ -11,6 +12,9 @@ import { FormHeader } from "../shared/components/form_header.js";
|
|
|
11
12
|
import { FormActionButtons } from "../shared/components/form_action_buttons.js";
|
|
12
13
|
import { TwoColumnAuthLayout } from "../shared/components/two_column_auth_layout.js";
|
|
13
14
|
import { AlreadyLoggedInGuard } from "../shared/components/already_logged_in_guard.js";
|
|
15
|
+
import { GoogleSignInButton } from "../shared/components/google_sign_in_button.js";
|
|
16
|
+
import { OAuthDivider } from "../shared/components/oauth_divider.js";
|
|
17
|
+
import { AlertCircle } from "lucide-react";
|
|
14
18
|
import { REGISTER_FIELD_IDS, createRegisterFieldDefinitions, resolveRegisterButtonPalette, resolveRegisterLabels, resolveRegisterPasswordRequirements, } from "./config/register_field_config.js";
|
|
15
19
|
import { use_register_form, } from "./hooks/use_register_form.js";
|
|
16
20
|
const ORDERED_FIELDS = [
|
|
@@ -20,7 +24,29 @@ const ORDERED_FIELDS = [
|
|
|
20
24
|
REGISTER_FIELD_IDS.CONFIRM_PASSWORD,
|
|
21
25
|
];
|
|
22
26
|
// section: component
|
|
23
|
-
export default function register_layout({ image_src, image_alt, image_background_color = "#f1f5f9", field_overrides, labels, button_colors, password_requirements, show_name_field = true, data_client, alreadyLoggedInMessage = "You are already logged in", showLogoutButton = true, showReturnHomeButton = false, returnHomeButtonLabel = "Return home", returnHomePath = "/", signInPath = "/hazo_auth/login", signInLabel = "Sign in", urlOnLogon, }) {
|
|
27
|
+
export default function register_layout({ image_src, image_alt, image_background_color = "#f1f5f9", field_overrides, labels, button_colors, password_requirements, show_name_field = true, data_client, alreadyLoggedInMessage = "You are already logged in", showLogoutButton = true, showReturnHomeButton = false, returnHomeButtonLabel = "Return home", returnHomePath = "/", signInPath = "/hazo_auth/login", signInLabel = "Sign in", urlOnLogon, oauth, }) {
|
|
28
|
+
// Default OAuth config: both enabled
|
|
29
|
+
const oauthConfig = oauth || {
|
|
30
|
+
enable_google: true,
|
|
31
|
+
enable_email_password: true,
|
|
32
|
+
google_button_text: "Sign up with Google",
|
|
33
|
+
oauth_divider_text: "or continue with email",
|
|
34
|
+
};
|
|
35
|
+
// Read OAuth error from URL query params (e.g., ?error=AccessDenied)
|
|
36
|
+
const searchParams = useSearchParams();
|
|
37
|
+
const oauthError = searchParams.get("error");
|
|
38
|
+
const getOAuthErrorMessage = (error) => {
|
|
39
|
+
switch (error) {
|
|
40
|
+
case "AccessDenied":
|
|
41
|
+
return "Access was denied. You may have cancelled the sign-in or your account is not authorized.";
|
|
42
|
+
case "OAuthSignin":
|
|
43
|
+
case "OAuthCallback":
|
|
44
|
+
case "OAuthCreateAccount":
|
|
45
|
+
return "Something went wrong with Google sign-in. Please try again.";
|
|
46
|
+
default:
|
|
47
|
+
return "An error occurred during sign-in. Please try again.";
|
|
48
|
+
}
|
|
49
|
+
};
|
|
24
50
|
const fieldDefinitions = createRegisterFieldDefinitions(field_overrides);
|
|
25
51
|
const resolvedLabels = resolveRegisterLabels(labels);
|
|
26
52
|
const resolvedButtonPalette = resolveRegisterButtonPalette(button_colors);
|
|
@@ -54,5 +80,5 @@ export default function register_layout({ image_src, image_alt, image_background
|
|
|
54
80
|
return (_jsx(FormFieldWrapper, { fieldId: fieldDefinition.id, label: fieldDefinition.label, input: inputElement, errorMessage: shouldShowError }, fieldId));
|
|
55
81
|
});
|
|
56
82
|
};
|
|
57
|
-
return (_jsx(AlreadyLoggedInGuard, { image_src: image_src, image_alt: image_alt, image_background_color: image_background_color, message: alreadyLoggedInMessage, showLogoutButton: showLogoutButton, showReturnHomeButton: showReturnHomeButton, returnHomeButtonLabel: returnHomeButtonLabel, returnHomePath: returnHomePath, children: _jsx(TwoColumnAuthLayout, { imageSrc: image_src, imageAlt: image_alt, imageBackgroundColor: image_background_color, formContent: _jsxs(_Fragment, { children: [_jsx(FormHeader, { heading: resolvedLabels.heading, subHeading: resolvedLabels.subHeading }), _jsxs("form", { className: "cls_register_layout_form_fields flex flex-col gap-5", onSubmit: form.handleSubmit, "aria-label": "Registration form", children: [renderFields(form), _jsx(FormActionButtons, { submitLabel: resolvedLabels.submitButton, cancelLabel: resolvedLabels.cancelButton, buttonPalette: resolvedButtonPalette, isSubmitDisabled: form.isSubmitDisabled, onCancel: form.handleCancel, submitAriaLabel: "Submit registration form", cancelAriaLabel: "Cancel registration form" }), _jsxs("div", { className: "cls_register_layout_sign_in_link flex items-center justify-center gap-1 text-sm text-muted-foreground", children: [_jsx("span", { children: "Already have an account?" }), _jsx(Link, { href: signInPath, className: "cls_register_layout_sign_in_link_text text-primary underline-offset-4 hover:underline", "aria-label": "Go to sign in page", children: signInLabel })] }), form.isSubmitting && (_jsx("div", { className: "cls_register_submitting_indicator text-sm text-slate-600 text-center", children: "Registering..." }))] })] }) }) }));
|
|
83
|
+
return (_jsx(AlreadyLoggedInGuard, { image_src: image_src, image_alt: image_alt, image_background_color: image_background_color, message: alreadyLoggedInMessage, showLogoutButton: showLogoutButton, showReturnHomeButton: showReturnHomeButton, returnHomeButtonLabel: returnHomeButtonLabel, returnHomePath: returnHomePath, children: _jsx(TwoColumnAuthLayout, { imageSrc: image_src, imageAlt: image_alt, imageBackgroundColor: image_background_color, formContent: _jsxs(_Fragment, { children: [_jsx(FormHeader, { heading: resolvedLabels.heading, subHeading: resolvedLabels.subHeading }), oauthError && (_jsxs("div", { className: "cls_register_layout_oauth_error flex items-center gap-2 rounded-md border border-red-200 bg-red-50 p-3 text-sm text-red-700", children: [_jsx(AlertCircle, { className: "h-4 w-4 shrink-0", "aria-hidden": "true" }), _jsx("span", { children: getOAuthErrorMessage(oauthError) })] })), oauthConfig.enable_google && (_jsx("div", { className: "cls_register_layout_oauth_section", children: _jsx(GoogleSignInButton, { label: oauthConfig.google_button_text }) })), oauthConfig.enable_google && oauthConfig.enable_email_password && (_jsx(OAuthDivider, { text: oauthConfig.oauth_divider_text })), oauthConfig.enable_email_password && (_jsxs("form", { className: "cls_register_layout_form_fields flex flex-col gap-5", onSubmit: form.handleSubmit, "aria-label": "Registration form", children: [renderFields(form), _jsx(FormActionButtons, { submitLabel: resolvedLabels.submitButton, cancelLabel: resolvedLabels.cancelButton, buttonPalette: resolvedButtonPalette, isSubmitDisabled: form.isSubmitDisabled, onCancel: form.handleCancel, submitAriaLabel: "Submit registration form", cancelAriaLabel: "Cancel registration form" }), _jsxs("div", { className: "cls_register_layout_sign_in_link flex items-center justify-center gap-1 text-sm text-muted-foreground", children: [_jsx("span", { children: "Already have an account?" }), _jsx(Link, { href: signInPath, className: "cls_register_layout_sign_in_link_text text-primary underline-offset-4 hover:underline", "aria-label": "Go to sign in page", children: signInLabel })] }), form.isSubmitting && (_jsx("div", { className: "cls_register_submitting_indicator text-sm text-slate-600 text-center", children: "Registering..." }))] })), !oauthConfig.enable_email_password && oauthConfig.enable_google && (_jsxs("div", { className: "cls_register_layout_sign_in_link mt-4 flex items-center justify-center gap-1 text-sm text-muted-foreground", children: [_jsx("span", { children: "Already have an account?" }), _jsx(Link, { href: signInPath, className: "cls_register_layout_sign_in_link_text text-primary underline-offset-4 hover:underline", "aria-label": "Go to sign in page", children: signInLabel })] }))] }) }) }));
|
|
58
84
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { type VariantProps } from "class-variance-authority";
|
|
3
3
|
declare const buttonVariants: (props?: ({
|
|
4
|
-
variant?: "
|
|
4
|
+
variant?: "default" | "destructive" | "outline" | "secondary" | "ghost" | "link" | null | undefined;
|
|
5
5
|
size?: "default" | "sm" | "lg" | "icon" | null | undefined;
|
|
6
6
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
7
7
|
export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
|
|
@@ -18,6 +18,13 @@ export type RegisterConfig = {
|
|
|
18
18
|
imageSrc: string;
|
|
19
19
|
imageAlt: string;
|
|
20
20
|
imageBackgroundColor: string;
|
|
21
|
+
/** OAuth configuration */
|
|
22
|
+
oauth: {
|
|
23
|
+
enable_google: boolean;
|
|
24
|
+
enable_email_password: boolean;
|
|
25
|
+
google_button_text: string;
|
|
26
|
+
oauth_divider_text: string;
|
|
27
|
+
};
|
|
21
28
|
};
|
|
22
29
|
/**
|
|
23
30
|
* Reads register layout configuration from hazo_auth_config.ini file
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"register_config.server.d.ts","sourceRoot":"","sources":["../../src/lib/register_config.server.ts"],"names":[],"mappings":"AAEA,OAAO,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"register_config.server.d.ts","sourceRoot":"","sources":["../../src/lib/register_config.server.ts"],"names":[],"mappings":"AAEA,OAAO,aAAa,CAAC;AAerB,MAAM,MAAM,cAAc,GAAG;IAC3B,aAAa,EAAE,OAAO,CAAC;IACvB,oBAAoB,EAAE;QACpB,cAAc,EAAE,MAAM,CAAC;QACvB,iBAAiB,EAAE,OAAO,CAAC;QAC3B,iBAAiB,EAAE,OAAO,CAAC;QAC3B,cAAc,EAAE,OAAO,CAAC;QACxB,eAAe,EAAE,OAAO,CAAC;KAC1B,CAAC;IACF,sBAAsB,EAAE,MAAM,CAAC;IAC/B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,oBAAoB,EAAE,OAAO,CAAC;IAC9B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,0BAA0B;IAC1B,KAAK,EAAE;QACL,aAAa,EAAE,OAAO,CAAC;QACvB,qBAAqB,EAAE,OAAO,CAAC;QAC/B,kBAAkB,EAAE,MAAM,CAAC;QAC3B,kBAAkB,EAAE,MAAM,CAAC;KAC5B,CAAC;CACH,CAAC;AAGF;;;;GAIG;AACH,wBAAgB,mBAAmB,IAAI,cAAc,CA8EpD"}
|
|
@@ -6,6 +6,7 @@ import { get_config_boolean, get_config_value, read_config_section } from "./con
|
|
|
6
6
|
import { get_password_requirements_config } from "./password_requirements_config.server.js";
|
|
7
7
|
import { get_already_logged_in_config } from "./already_logged_in_config.server.js";
|
|
8
8
|
import { get_user_fields_config } from "./user_fields_config.server.js";
|
|
9
|
+
import { get_oauth_config } from "./oauth_config.server.js";
|
|
9
10
|
// Default image path - consuming apps should either:
|
|
10
11
|
// 1. Configure their own image_src in hazo_auth_config.ini
|
|
11
12
|
// 2. Copy the default images from node_modules/hazo_auth/public/hazo_auth/images/ to their public folder
|
|
@@ -37,6 +38,10 @@ export function get_register_config() {
|
|
|
37
38
|
const imageSrc = get_config_value("hazo_auth__register_layout", "image_src", DEFAULT_REGISTER_IMAGE_PATH);
|
|
38
39
|
const imageAlt = get_config_value("hazo_auth__register_layout", "image_alt", "Modern building representing user registration");
|
|
39
40
|
const imageBackgroundColor = get_config_value("hazo_auth__register_layout", "image_background_color", "#e2e8f0");
|
|
41
|
+
// Get OAuth configuration (shared with login)
|
|
42
|
+
const oauthConfig = get_oauth_config();
|
|
43
|
+
// For the register page, default button text to "Sign up with Google" unless overridden
|
|
44
|
+
const registerGoogleButtonText = get_config_value("hazo_auth__oauth", "google_button_text_register", "Sign up with Google");
|
|
40
45
|
return {
|
|
41
46
|
showNameField,
|
|
42
47
|
passwordRequirements,
|
|
@@ -50,5 +55,11 @@ export function get_register_config() {
|
|
|
50
55
|
imageSrc,
|
|
51
56
|
imageAlt,
|
|
52
57
|
imageBackgroundColor,
|
|
58
|
+
oauth: {
|
|
59
|
+
enable_google: oauthConfig.enable_google,
|
|
60
|
+
enable_email_password: oauthConfig.enable_email_password,
|
|
61
|
+
google_button_text: registerGoogleButtonText,
|
|
62
|
+
oauth_divider_text: oauthConfig.oauth_divider_text,
|
|
63
|
+
},
|
|
53
64
|
};
|
|
54
65
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { NextRequest } from "next/server";
|
|
2
|
+
/**
|
|
3
|
+
* Rewrites request.url to use the public-facing origin when behind a reverse proxy.
|
|
4
|
+
*
|
|
5
|
+
* Behind proxies like Cloudflare Tunnel, Next.js sets request.url to the internal
|
|
6
|
+
* address (e.g., https://localhost:3000). This causes NextResponse.redirect() to
|
|
7
|
+
* resolve Location headers against the internal origin instead of the public domain.
|
|
8
|
+
*
|
|
9
|
+
* Apply this at the TOP of any route handler that uses NextResponse.redirect().
|
|
10
|
+
*
|
|
11
|
+
* @param request - The incoming NextRequest
|
|
12
|
+
* @returns A new NextRequest with corrected URL, or the original if no proxy detected
|
|
13
|
+
*/
|
|
14
|
+
export declare function rewrite_request_for_proxy(request: NextRequest): NextRequest;
|
|
15
|
+
/**
|
|
16
|
+
* Gets the public-facing origin for constructing redirect URLs.
|
|
17
|
+
* Use this when you need the origin string but don't need to rewrite the request.
|
|
18
|
+
*/
|
|
19
|
+
export declare function get_public_origin(request: NextRequest): string;
|
|
20
|
+
//# sourceMappingURL=proxy_request.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy_request.d.ts","sourceRoot":"","sources":["../../../src/lib/utils/proxy_request.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAqC1C;;;;;;;;;;;GAWG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,WAAW,GAAG,WAAW,CAqB3E;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CAG9D"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// file_description: Shared utility for rewriting request.url behind reverse proxies (Cloudflare Tunnel, nginx, AWS ALB)
|
|
2
|
+
import { NextRequest } from "next/server";
|
|
3
|
+
/**
|
|
4
|
+
* Detects the public-facing origin from proxy headers.
|
|
5
|
+
* Returns null if not behind a proxy (origins match).
|
|
6
|
+
*/
|
|
7
|
+
function detect_public_origin(request_url, headers) {
|
|
8
|
+
// Priority 1: NEXTAUTH_URL env var (explicitly configured)
|
|
9
|
+
const nextauth_url = process.env.NEXTAUTH_URL;
|
|
10
|
+
if (nextauth_url) {
|
|
11
|
+
try {
|
|
12
|
+
const public_origin = new URL(nextauth_url).origin;
|
|
13
|
+
if (public_origin !== request_url.origin) {
|
|
14
|
+
return public_origin;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
catch (_a) {
|
|
18
|
+
// Invalid NEXTAUTH_URL, fall through
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
// Priority 2: x-forwarded-host header (set by Cloudflare Tunnel, nginx, etc.)
|
|
22
|
+
const forwarded_host = headers.get("x-forwarded-host");
|
|
23
|
+
if (forwarded_host && forwarded_host !== request_url.hostname) {
|
|
24
|
+
const proto = headers.get("x-forwarded-proto") || "https";
|
|
25
|
+
return `${proto}://${forwarded_host}`;
|
|
26
|
+
}
|
|
27
|
+
// Priority 3: host header (Cloudflare Tunnel also sets this)
|
|
28
|
+
const host_header = headers.get("host");
|
|
29
|
+
if (host_header && host_header !== request_url.host) {
|
|
30
|
+
const proto = headers.get("x-forwarded-proto") || "https";
|
|
31
|
+
return `${proto}://${host_header}`;
|
|
32
|
+
}
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Rewrites request.url to use the public-facing origin when behind a reverse proxy.
|
|
37
|
+
*
|
|
38
|
+
* Behind proxies like Cloudflare Tunnel, Next.js sets request.url to the internal
|
|
39
|
+
* address (e.g., https://localhost:3000). This causes NextResponse.redirect() to
|
|
40
|
+
* resolve Location headers against the internal origin instead of the public domain.
|
|
41
|
+
*
|
|
42
|
+
* Apply this at the TOP of any route handler that uses NextResponse.redirect().
|
|
43
|
+
*
|
|
44
|
+
* @param request - The incoming NextRequest
|
|
45
|
+
* @returns A new NextRequest with corrected URL, or the original if no proxy detected
|
|
46
|
+
*/
|
|
47
|
+
export function rewrite_request_for_proxy(request) {
|
|
48
|
+
try {
|
|
49
|
+
const request_url = new URL(request.url);
|
|
50
|
+
const public_origin = detect_public_origin(request_url, request.headers);
|
|
51
|
+
if (!public_origin) {
|
|
52
|
+
return request; // Not behind a proxy, no rewriting needed
|
|
53
|
+
}
|
|
54
|
+
// Construct corrected URL: public origin + original path + query
|
|
55
|
+
const corrected_url = `${public_origin}${request_url.pathname}${request_url.search}`;
|
|
56
|
+
// Create new NextRequest with corrected URL, preserving everything else
|
|
57
|
+
return new NextRequest(corrected_url, {
|
|
58
|
+
method: request.method,
|
|
59
|
+
headers: request.headers,
|
|
60
|
+
body: request.body,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
catch (_a) {
|
|
64
|
+
return request;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Gets the public-facing origin for constructing redirect URLs.
|
|
69
|
+
* Use this when you need the origin string but don't need to rewrite the request.
|
|
70
|
+
*/
|
|
71
|
+
export function get_public_origin(request) {
|
|
72
|
+
const request_url = new URL(request.url);
|
|
73
|
+
return detect_public_origin(request_url, request.headers) || request_url.origin;
|
|
74
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nextauth.d.ts","sourceRoot":"","sources":["../../../src/server/routes/nextauth.ts"],"names":[],"mappings":"AAQA,KAAK,eAAe,GAAG;IACrB,MAAM,EAAE,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;CACzC,CAAC;
|
|
1
|
+
{"version":3,"file":"nextauth.d.ts","sourceRoot":"","sources":["../../../src/server/routes/nextauth.ts"],"names":[],"mappings":"AAQA,KAAK,eAAe,GAAG;IACrB,MAAM,EAAE,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;CACzC,CAAC;AAyGF,wBAAsB,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,eAAe,gBAEnE;AAED,wBAAsB,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,eAAe,gBAEpE"}
|
|
@@ -4,60 +4,106 @@
|
|
|
4
4
|
import NextAuthImport from "next-auth";
|
|
5
5
|
const NextAuth = NextAuthImport.default || NextAuthImport;
|
|
6
6
|
import { get_nextauth_config } from "../../lib/auth/nextauth_config.js";
|
|
7
|
-
// section:
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
7
|
+
// section: proxy_detection
|
|
8
|
+
/**
|
|
9
|
+
* Detects the public-facing origin from request headers.
|
|
10
|
+
* Cloudflare tunnel sends: x-forwarded-host, x-forwarded-proto, cf-visitor, host
|
|
11
|
+
*/
|
|
12
|
+
function detect_proxy_origin(request) {
|
|
13
|
+
try {
|
|
14
|
+
const request_url = new URL(request.url);
|
|
15
|
+
const forwarded_host = request.headers.get("x-forwarded-host");
|
|
16
|
+
const host_header = request.headers.get("host");
|
|
17
|
+
const forwarded_proto = request.headers.get("x-forwarded-proto") || "https";
|
|
18
|
+
// Debug logging in development
|
|
19
|
+
if (process.env.NODE_ENV === "development") {
|
|
20
|
+
console.log("[NextAuth Proxy] request.url:", request.url);
|
|
21
|
+
console.log("[NextAuth Proxy] request_url.hostname:", request_url.hostname, "request_url.host:", request_url.host);
|
|
22
|
+
console.log("[NextAuth Proxy] x-forwarded-host:", forwarded_host);
|
|
23
|
+
console.log("[NextAuth Proxy] host header:", host_header);
|
|
24
|
+
console.log("[NextAuth Proxy] x-forwarded-proto:", forwarded_proto);
|
|
25
|
+
}
|
|
26
|
+
// Check x-forwarded-host first (set by Cloudflare tunnel, nginx, etc.)
|
|
27
|
+
if (forwarded_host && forwarded_host !== request_url.hostname) {
|
|
28
|
+
const origin = `${forwarded_proto}://${forwarded_host}`;
|
|
29
|
+
if (process.env.NODE_ENV === "development") {
|
|
30
|
+
console.log("[NextAuth Proxy] Detected proxy via x-forwarded-host:", origin);
|
|
31
|
+
}
|
|
32
|
+
return origin;
|
|
33
|
+
}
|
|
34
|
+
// Check host header (Cloudflare tunnel also sets this to the tunnel domain)
|
|
35
|
+
if (host_header && host_header !== request_url.host) {
|
|
36
|
+
const origin = `${forwarded_proto}://${host_header}`;
|
|
37
|
+
if (process.env.NODE_ENV === "development") {
|
|
38
|
+
console.log("[NextAuth Proxy] Detected proxy via host header:", origin);
|
|
39
|
+
}
|
|
40
|
+
return origin;
|
|
41
|
+
}
|
|
42
|
+
if (process.env.NODE_ENV === "development") {
|
|
43
|
+
console.log("[NextAuth Proxy] No proxy detected");
|
|
44
|
+
}
|
|
18
45
|
}
|
|
19
|
-
|
|
46
|
+
catch (e) {
|
|
47
|
+
console.error("[NextAuth Proxy] Error:", e);
|
|
48
|
+
}
|
|
49
|
+
return null;
|
|
20
50
|
}
|
|
21
|
-
// section:
|
|
51
|
+
// section: handler
|
|
22
52
|
/**
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
53
|
+
* Handles NextAuth requests with proxy/tunnel support.
|
|
54
|
+
*
|
|
55
|
+
* When behind a proxy (Cloudflare tunnel, nginx, etc.), temporarily sets
|
|
56
|
+
* NEXTAUTH_URL to the proxy origin so next-auth uses the correct baseUrl
|
|
57
|
+
* for cookies, CSRF, and OAuth callback URLs.
|
|
58
|
+
*
|
|
59
|
+
* IMPORTANT: NEXTAUTH_URL must remain overridden for the entire duration of
|
|
60
|
+
* the handler execution, because next-auth reads it lazily during request
|
|
61
|
+
* processing (not just at handler creation time). We restore it after the
|
|
62
|
+
* handler completes.
|
|
27
63
|
*/
|
|
28
|
-
function
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
64
|
+
async function handle_request(request, context) {
|
|
65
|
+
const proxy_origin = detect_proxy_origin(request);
|
|
66
|
+
const original_nextauth_url = process.env.NEXTAUTH_URL;
|
|
67
|
+
// If behind a proxy, override NEXTAUTH_URL for the entire request lifecycle
|
|
68
|
+
if (proxy_origin) {
|
|
69
|
+
let auth_path = "/api/auth";
|
|
70
|
+
if (original_nextauth_url) {
|
|
71
|
+
try {
|
|
72
|
+
const parsed = new URL(original_nextauth_url);
|
|
73
|
+
auth_path = parsed.pathname;
|
|
74
|
+
}
|
|
75
|
+
catch (_a) {
|
|
76
|
+
// ignore
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
process.env.NEXTAUTH_URL = `${proxy_origin}${auth_path}`;
|
|
32
80
|
}
|
|
33
81
|
try {
|
|
34
|
-
const
|
|
35
|
-
const
|
|
36
|
-
//
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
// Create a new Request with the corrected URL, preserving everything else
|
|
43
|
-
return new Request(corrected_url, {
|
|
44
|
-
method: request.method,
|
|
45
|
-
headers: request.headers,
|
|
46
|
-
body: request.body,
|
|
47
|
-
// @ts-expect-error - duplex is required for streaming bodies in Node.js
|
|
48
|
-
duplex: "half",
|
|
49
|
-
});
|
|
82
|
+
const config = get_nextauth_config();
|
|
83
|
+
const handler = NextAuth(config);
|
|
84
|
+
// Next.js 16 passes params as a Promise, but next-auth v4 expects it resolved
|
|
85
|
+
const resolved_params = await context.params;
|
|
86
|
+
const resolved_context = { params: resolved_params };
|
|
87
|
+
// Await the handler response before restoring NEXTAUTH_URL
|
|
88
|
+
const response = await handler(request, resolved_context);
|
|
89
|
+
return response;
|
|
50
90
|
}
|
|
51
|
-
|
|
52
|
-
|
|
91
|
+
finally {
|
|
92
|
+
// Restore original NEXTAUTH_URL after handler completes
|
|
93
|
+
if (proxy_origin) {
|
|
94
|
+
if (original_nextauth_url) {
|
|
95
|
+
process.env.NEXTAUTH_URL = original_nextauth_url;
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
delete process.env.NEXTAUTH_URL;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
53
101
|
}
|
|
54
102
|
}
|
|
55
103
|
// section: exports
|
|
56
104
|
export async function GET(request, context) {
|
|
57
|
-
|
|
58
|
-
return handler(rewrite_request_for_proxy(request), context);
|
|
105
|
+
return handle_request(request, context);
|
|
59
106
|
}
|
|
60
107
|
export async function POST(request, context) {
|
|
61
|
-
|
|
62
|
-
return handler(rewrite_request_for_proxy(request), context);
|
|
108
|
+
return handle_request(request, context);
|
|
63
109
|
}
|
|
@@ -4,5 +4,5 @@ import { NextRequest, NextResponse } from "next/server";
|
|
|
4
4
|
* The user creation/linking is done in NextAuth signIn callback
|
|
5
5
|
* This route just sets the hazo_auth session cookies
|
|
6
6
|
*/
|
|
7
|
-
export declare function GET(
|
|
7
|
+
export declare function GET(original_request: NextRequest): Promise<NextResponse<unknown>>;
|
|
8
8
|
//# sourceMappingURL=oauth_google_callback.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oauth_google_callback.d.ts","sourceRoot":"","sources":["../../../src/server/routes/oauth_google_callback.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAwBxD;;;;GAIG;AACH,wBAAsB,GAAG,CAAC,
|
|
1
|
+
{"version":3,"file":"oauth_google_callback.d.ts","sourceRoot":"","sources":["../../../src/server/routes/oauth_google_callback.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAwBxD;;;;GAIG;AACH,wBAAsB,GAAG,CAAC,gBAAgB,EAAE,WAAW,kCA6JtD"}
|
|
@@ -10,18 +10,28 @@ import { get_cookie_name, get_cookie_options, BASE_COOKIE_NAMES } from "../../li
|
|
|
10
10
|
import { get_hazo_connect_instance } from "../../lib/hazo_connect_instance.server.js";
|
|
11
11
|
import { get_post_login_redirect } from "../../lib/services/post_verification_service.js";
|
|
12
12
|
import { get_oauth_config } from "../../lib/oauth_config.server.js";
|
|
13
|
-
import {
|
|
13
|
+
import { rewrite_request_for_proxy } from "../../lib/utils/proxy_request.js";
|
|
14
14
|
// section: api_handler
|
|
15
15
|
/**
|
|
16
16
|
* Handles the OAuth callback after Google sign-in
|
|
17
17
|
* The user creation/linking is done in NextAuth signIn callback
|
|
18
18
|
* This route just sets the hazo_auth session cookies
|
|
19
19
|
*/
|
|
20
|
-
export async function GET(
|
|
20
|
+
export async function GET(original_request) {
|
|
21
|
+
// Rewrite request.url to public origin when behind a reverse proxy.
|
|
22
|
+
// This ensures all NextResponse.redirect() calls produce correct Location headers.
|
|
23
|
+
const request = rewrite_request_for_proxy(original_request);
|
|
21
24
|
const logger = create_app_logger();
|
|
25
|
+
// Detect if request came through HTTPS proxy (Cloudflare tunnel, etc.)
|
|
26
|
+
const is_secure = original_request.headers.get("x-forwarded-proto") === "https" ||
|
|
27
|
+
request.url.startsWith("https://");
|
|
22
28
|
try {
|
|
23
29
|
// Get the NextAuth token from the session
|
|
24
|
-
|
|
30
|
+
// When behind HTTPS proxy, next-auth uses __Secure- cookie prefix
|
|
31
|
+
const token = (await getToken({
|
|
32
|
+
req: request,
|
|
33
|
+
secureCookie: is_secure,
|
|
34
|
+
}));
|
|
25
35
|
logger.debug("google_callback_token_received", {
|
|
26
36
|
filename: get_filename(),
|
|
27
37
|
line_number: get_line_number(),
|
|
@@ -37,7 +47,7 @@ export async function GET(request) {
|
|
|
37
47
|
note: "No NextAuth token found - user may not have completed Google sign-in",
|
|
38
48
|
});
|
|
39
49
|
// Redirect to login with error — use .toString() to ensure absolute URL
|
|
40
|
-
const login_url =
|
|
50
|
+
const login_url = new URL("/hazo_auth/login", request.url);
|
|
41
51
|
login_url.searchParams.set("error", "oauth_failed");
|
|
42
52
|
return NextResponse.redirect(login_url.toString());
|
|
43
53
|
}
|
|
@@ -50,7 +60,7 @@ export async function GET(request) {
|
|
|
50
60
|
has_hazo_user_id: !!token.hazo_user_id,
|
|
51
61
|
has_google_id: !!token.google_id,
|
|
52
62
|
});
|
|
53
|
-
const login_url =
|
|
63
|
+
const login_url = new URL("/hazo_auth/login", request.url);
|
|
54
64
|
login_url.searchParams.set("error", "oauth_incomplete");
|
|
55
65
|
return NextResponse.redirect(login_url.toString());
|
|
56
66
|
}
|
|
@@ -94,12 +104,13 @@ export async function GET(request) {
|
|
|
94
104
|
invitation_table_error,
|
|
95
105
|
});
|
|
96
106
|
// Create redirect response — use .toString() to ensure absolute public-facing URL
|
|
97
|
-
const redirect_url =
|
|
107
|
+
const redirect_url = new URL(determined_redirect, request.url);
|
|
98
108
|
const response = NextResponse.redirect(redirect_url.toString());
|
|
99
109
|
// Set authentication cookies (same as login route, with configurable prefix and domain)
|
|
110
|
+
// secure=true when in production OR when accessed via HTTPS proxy (Cloudflare tunnel, etc.)
|
|
100
111
|
const base_cookie_options = {
|
|
101
112
|
httpOnly: true,
|
|
102
|
-
secure: process.env.NODE_ENV === "production",
|
|
113
|
+
secure: process.env.NODE_ENV === "production" || is_secure,
|
|
103
114
|
sameSite: "lax",
|
|
104
115
|
path: "/",
|
|
105
116
|
maxAge: 60 * 60 * 24 * 30, // 30 days
|
|
@@ -134,7 +145,7 @@ export async function GET(request) {
|
|
|
134
145
|
error_message,
|
|
135
146
|
error_stack,
|
|
136
147
|
});
|
|
137
|
-
const login_url =
|
|
148
|
+
const login_url = new URL("/hazo_auth/login", request.url);
|
|
138
149
|
login_url.searchParams.set("error", "oauth_error");
|
|
139
150
|
return NextResponse.redirect(login_url.toString());
|
|
140
151
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../src/server_pages/register.tsx"],"names":[],"mappings":"AAEA,OAAO,aAAa,CAAC;AAOrB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,MAAM,MAAM,iBAAiB,GAAG;IAC9B;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,eAAe,CAAC;IAErC;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,sBAAsB,CAAC,EAAE,MAAM,CAAC;CACjC,CAAC;AAIF;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,CAAC,OAAO,UAAU,YAAY,CAAC,EACnC,SAAS,EACT,SAAS,EACT,sBAAsB,GACvB,GAAE,iBAAsB,
|
|
1
|
+
{"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../src/server_pages/register.tsx"],"names":[],"mappings":"AAEA,OAAO,aAAa,CAAC;AAOrB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,MAAM,MAAM,iBAAiB,GAAG;IAC9B;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,eAAe,CAAC;IAErC;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,sBAAsB,CAAC,EAAE,MAAM,CAAC;CACjC,CAAC;AAIF;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,CAAC,OAAO,UAAU,YAAY,CAAC,EACnC,SAAS,EACT,SAAS,EACT,sBAAsB,GACvB,GAAE,iBAAsB,2CAkCxB;AAGD,OAAO,EAAE,YAAY,EAAE,CAAC"}
|
|
@@ -40,7 +40,12 @@ export default function RegisterPage({ image_src, image_alt, image_background_co
|
|
|
40
40
|
const finalImageAlt = image_alt || config.imageAlt;
|
|
41
41
|
const finalImageBackgroundColor = image_background_color || config.imageBackgroundColor;
|
|
42
42
|
// Pass serializable config to client wrapper, wrapped in AuthPageShell for navbar support
|
|
43
|
-
return (_jsx(AuthPageShell, { children: _jsx(RegisterClientWrapper, { image_src: finalImageSrc, image_alt: finalImageAlt, image_background_color: finalImageBackgroundColor, showNameField: config.showNameField, passwordRequirements: config.passwordRequirements, alreadyLoggedInMessage: config.alreadyLoggedInMessage, showLogoutButton: config.showLogoutButton, showReturnHomeButton: config.showReturnHomeButton, returnHomeButtonLabel: config.returnHomeButtonLabel, returnHomePath: config.returnHomePath, signInPath: config.signInPath, signInLabel: config.signInLabel
|
|
43
|
+
return (_jsx(AuthPageShell, { children: _jsx(RegisterClientWrapper, { image_src: finalImageSrc, image_alt: finalImageAlt, image_background_color: finalImageBackgroundColor, showNameField: config.showNameField, passwordRequirements: config.passwordRequirements, alreadyLoggedInMessage: config.alreadyLoggedInMessage, showLogoutButton: config.showLogoutButton, showReturnHomeButton: config.showReturnHomeButton, returnHomeButtonLabel: config.returnHomeButtonLabel, returnHomePath: config.returnHomePath, signInPath: config.signInPath, signInLabel: config.signInLabel, oauth: {
|
|
44
|
+
enable_google: config.oauth.enable_google,
|
|
45
|
+
enable_email_password: config.oauth.enable_email_password,
|
|
46
|
+
google_button_text: config.oauth.google_button_text,
|
|
47
|
+
oauth_divider_text: config.oauth.oauth_divider_text,
|
|
48
|
+
} }) }));
|
|
44
49
|
}
|
|
45
50
|
// Named export for direct imports
|
|
46
51
|
export { RegisterPage };
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import type { RegisterConfig } from "../lib/register_config.server";
|
|
2
|
+
import type { OAuthLayoutConfig } from "../components/layouts/register/index";
|
|
2
3
|
import type { StaticImageData } from "next/image";
|
|
3
|
-
export type RegisterClientWrapperProps = Omit<RegisterConfig, 'imageSrc' | 'imageAlt' | 'imageBackgroundColor'> & {
|
|
4
|
+
export type RegisterClientWrapperProps = Omit<RegisterConfig, 'imageSrc' | 'imageAlt' | 'imageBackgroundColor' | 'oauth'> & {
|
|
4
5
|
image_src: string | StaticImageData;
|
|
5
6
|
image_alt: string;
|
|
6
7
|
image_background_color: string;
|
|
8
|
+
/** OAuth configuration */
|
|
9
|
+
oauth?: OAuthLayoutConfig;
|
|
7
10
|
};
|
|
8
11
|
/**
|
|
9
12
|
* Client wrapper for RegisterLayout
|
|
10
13
|
* Initializes hazo_connect data client on client side and passes config from server
|
|
11
14
|
*/
|
|
12
|
-
export declare function RegisterClientWrapper({ image_src, image_alt, image_background_color, showNameField, passwordRequirements, alreadyLoggedInMessage, showLogoutButton, showReturnHomeButton, returnHomeButtonLabel, returnHomePath, signInPath, signInLabel, }: RegisterClientWrapperProps): import("react/jsx-runtime").JSX.Element;
|
|
15
|
+
export declare function RegisterClientWrapper({ image_src, image_alt, image_background_color, showNameField, passwordRequirements, alreadyLoggedInMessage, showLogoutButton, showReturnHomeButton, returnHomeButtonLabel, returnHomePath, signInPath, signInLabel, oauth, }: RegisterClientWrapperProps): import("react/jsx-runtime").JSX.Element;
|
|
13
16
|
//# sourceMappingURL=register_client_wrapper.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"register_client_wrapper.d.ts","sourceRoot":"","sources":["../../src/server_pages/register_client_wrapper.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"register_client_wrapper.d.ts","sourceRoot":"","sources":["../../src/server_pages/register_client_wrapper.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AACpE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sCAAsC,CAAC;AAG9E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,MAAM,MAAM,0BAA0B,GAAG,IAAI,CAAC,cAAc,EAAE,UAAU,GAAG,UAAU,GAAG,sBAAsB,GAAG,OAAO,CAAC,GAAG;IAC1H,SAAS,EAAE,MAAM,GAAG,eAAe,CAAC;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,sBAAsB,EAAE,MAAM,CAAC;IAC/B,0BAA0B;IAC1B,KAAK,CAAC,EAAE,iBAAiB,CAAC;CAC3B,CAAC;AAGF;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,EACpC,SAAS,EACT,SAAS,EACT,sBAAsB,EACtB,aAAa,EACb,oBAAoB,EACpB,sBAAsB,EACtB,gBAAgB,EAChB,oBAAoB,EACpB,qBAAqB,EACrB,cAAc,EACd,UAAU,EACV,WAAW,EACX,KAAK,GACN,EAAE,0BAA0B,2CAsC5B"}
|
|
@@ -11,7 +11,7 @@ import { create_sqlite_hazo_connect } from "../lib/hazo_connect_setup.js";
|
|
|
11
11
|
* Client wrapper for RegisterLayout
|
|
12
12
|
* Initializes hazo_connect data client on client side and passes config from server
|
|
13
13
|
*/
|
|
14
|
-
export function RegisterClientWrapper({ image_src, image_alt, image_background_color, showNameField, passwordRequirements, alreadyLoggedInMessage, showLogoutButton, showReturnHomeButton, returnHomeButtonLabel, returnHomePath, signInPath, signInLabel, }) {
|
|
14
|
+
export function RegisterClientWrapper({ image_src, image_alt, image_background_color, showNameField, passwordRequirements, alreadyLoggedInMessage, showLogoutButton, showReturnHomeButton, returnHomeButtonLabel, returnHomePath, signInPath, signInLabel, oauth, }) {
|
|
15
15
|
const [dataClient, setDataClient] = useState(null);
|
|
16
16
|
useEffect(() => {
|
|
17
17
|
// Initialize hazo_connect on client side
|
|
@@ -23,5 +23,5 @@ export function RegisterClientWrapper({ image_src, image_alt, image_background_c
|
|
|
23
23
|
if (!dataClient) {
|
|
24
24
|
return (_jsx("div", { className: "cls_register_page_loading flex items-center justify-center min-h-screen", children: _jsx("div", { className: "text-slate-600 animate-pulse", children: "Loading..." }) }));
|
|
25
25
|
}
|
|
26
|
-
return (_jsx(RegisterLayout, { image_src: image_src, image_alt: image_alt, image_background_color: image_background_color, data_client: dataClient, show_name_field: showNameField, password_requirements: passwordRequirements, alreadyLoggedInMessage: alreadyLoggedInMessage, showLogoutButton: showLogoutButton, showReturnHomeButton: showReturnHomeButton, returnHomeButtonLabel: returnHomeButtonLabel, returnHomePath: returnHomePath, signInPath: signInPath, signInLabel: signInLabel }));
|
|
26
|
+
return (_jsx(RegisterLayout, { image_src: image_src, image_alt: image_alt, image_background_color: image_background_color, data_client: dataClient, show_name_field: showNameField, password_requirements: passwordRequirements, alreadyLoggedInMessage: alreadyLoggedInMessage, showLogoutButton: showLogoutButton, showReturnHomeButton: showReturnHomeButton, returnHomeButtonLabel: returnHomeButtonLabel, returnHomePath: returnHomePath, signInPath: signInPath, signInLabel: signInLabel, oauth: oauth }));
|
|
27
27
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hazo_auth",
|
|
3
|
-
"version": "5.1.
|
|
3
|
+
"version": "5.1.35",
|
|
4
4
|
"description": "Zero-config authentication UI components for Next.js with RBAC, OAuth, scope-based multi-tenancy, and invitations",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"authentication",
|
|
@@ -188,7 +188,7 @@
|
|
|
188
188
|
"scripts": {
|
|
189
189
|
"dev": "next dev",
|
|
190
190
|
"build": "next build",
|
|
191
|
-
"build:pkg": "tsc -p tsconfig.build.json && tsx scripts/copy_assets.ts",
|
|
191
|
+
"build:pkg": "tsc --jsx react-jsx --skipLibCheck -p tsconfig.build.json && tsx scripts/copy_assets.ts",
|
|
192
192
|
"prepublishOnly": "npm run build:pkg",
|
|
193
193
|
"validate": "tsx scripts/validate_setup.ts",
|
|
194
194
|
"generate-routes": "tsx scripts/generate_routes.ts",
|
package/dist/lib/index.d.ts
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
export * from "./auth/index.js";
|
|
2
|
-
export * from "./services/index.js";
|
|
3
|
-
export { cn, merge_class_names } from "./utils.js";
|
|
4
|
-
export { get_config_value, get_config_number, get_config_boolean, get_config_array, read_config_section } from "./config/config_loader.server.js";
|
|
5
|
-
export { create_sqlite_hazo_connect } from "./hazo_connect_setup.js";
|
|
6
|
-
export { get_hazo_connect_instance } from "./hazo_connect_instance.server.js";
|
|
7
|
-
export { create_app_logger } from "./app_logger.js";
|
|
8
|
-
export { get_login_config } from "./login_config.server.js";
|
|
9
|
-
export { get_register_config } from "./register_config.server.js";
|
|
10
|
-
export { get_forgot_password_config } from "./forgot_password_config.server.js";
|
|
11
|
-
export { get_reset_password_config } from "./reset_password_config.server.js";
|
|
12
|
-
export { get_email_verification_config } from "./email_verification_config.server.js";
|
|
13
|
-
export { get_my_settings_config } from "./my_settings_config.server.js";
|
|
14
|
-
export { get_user_management_config } from "./user_management_config.server.js";
|
|
15
|
-
export { get_profile_picture_config } from "./profile_picture_config.server.js";
|
|
16
|
-
export { get_profile_pic_menu_config } from "./profile_pic_menu_config.server.js";
|
|
17
|
-
export { get_already_logged_in_config } from "./already_logged_in_config.server.js";
|
|
18
|
-
export { get_ui_shell_config } from "./ui_shell_config.server.js";
|
|
19
|
-
export { get_ui_sizes_config } from "./ui_sizes_config.server.js";
|
|
20
|
-
export { get_auth_utility_config } from "./auth_utility_config.server.js";
|
|
21
|
-
export { get_password_requirements_config } from "./password_requirements_config.server.js";
|
|
22
|
-
export { get_messages_config } from "./messages_config.server.js";
|
|
23
|
-
export { get_user_fields_config } from "./user_fields_config.server.js";
|
|
24
|
-
export { get_file_types_config } from "./file_types_config.server.js";
|
|
25
|
-
export { get_oauth_config, is_google_oauth_enabled, is_email_password_enabled } from "./oauth_config.server.js";
|
|
26
|
-
export type { OAuthConfig } from "./oauth_config.server";
|
|
27
|
-
export { get_branding_config, is_branding_enabled, is_allowed_logo_format, get_max_logo_size_bytes } from "./branding_config.server.js";
|
|
28
|
-
export type { FirmBrandingConfig } from "./branding_config.server";
|
|
29
|
-
export { sanitize_error_for_user } from "./utils/error_sanitizer.js";
|
|
30
|
-
export type { ErrorSanitizationOptions } from "./utils/error_sanitizer";
|
|
31
|
-
export * from "./utils/api_route_helpers.js";
|
|
32
|
-
//# sourceMappingURL=index.d.ts.map
|
package/dist/lib/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lib/index.ts"],"names":[],"mappings":"AAEA,cAAc,cAAc,CAAC;AAG7B,cAAc,kBAAkB,CAAC;AAGjC,OAAO,EAAE,EAAE,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAGhD,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AAG/I,OAAO,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,EAAE,yBAAyB,EAAE,MAAM,gCAAgC,CAAC;AAG3E,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAGjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAC7E,OAAO,EAAE,yBAAyB,EAAE,MAAM,gCAAgC,CAAC;AAC3E,OAAO,EAAE,6BAA6B,EAAE,MAAM,oCAAoC,CAAC;AACnF,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAC7E,OAAO,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAC7E,OAAO,EAAE,2BAA2B,EAAE,MAAM,kCAAkC,CAAC;AAC/E,OAAO,EAAE,4BAA4B,EAAE,MAAM,mCAAmC,CAAC;AACjF,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AACvE,OAAO,EAAE,gCAAgC,EAAE,MAAM,uCAAuC,CAAC;AACzF,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AAC7G,YAAY,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AACrI,YAAY,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAGnE,OAAO,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAClE,YAAY,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AACxE,cAAc,2BAA2B,CAAC"}
|
package/dist/lib/index.js
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
// file_description: barrel export for lib utilities
|
|
2
|
-
// section: auth_exports
|
|
3
|
-
export * from "./auth/index.js";
|
|
4
|
-
// section: service_exports
|
|
5
|
-
export * from "./services/index.js";
|
|
6
|
-
// section: utility_exports
|
|
7
|
-
export { cn, merge_class_names } from "./utils.js";
|
|
8
|
-
// section: config_exports
|
|
9
|
-
export { get_config_value, get_config_number, get_config_boolean, get_config_array, read_config_section } from "./config/config_loader.server.js";
|
|
10
|
-
// section: hazo_connect_exports
|
|
11
|
-
export { create_sqlite_hazo_connect } from "./hazo_connect_setup.js";
|
|
12
|
-
export { get_hazo_connect_instance } from "./hazo_connect_instance.server.js";
|
|
13
|
-
// section: logger_exports
|
|
14
|
-
export { create_app_logger } from "./app_logger.js";
|
|
15
|
-
// section: config_server_exports
|
|
16
|
-
export { get_login_config } from "./login_config.server.js";
|
|
17
|
-
export { get_register_config } from "./register_config.server.js";
|
|
18
|
-
export { get_forgot_password_config } from "./forgot_password_config.server.js";
|
|
19
|
-
export { get_reset_password_config } from "./reset_password_config.server.js";
|
|
20
|
-
export { get_email_verification_config } from "./email_verification_config.server.js";
|
|
21
|
-
export { get_my_settings_config } from "./my_settings_config.server.js";
|
|
22
|
-
export { get_user_management_config } from "./user_management_config.server.js";
|
|
23
|
-
export { get_profile_picture_config } from "./profile_picture_config.server.js";
|
|
24
|
-
export { get_profile_pic_menu_config } from "./profile_pic_menu_config.server.js";
|
|
25
|
-
export { get_already_logged_in_config } from "./already_logged_in_config.server.js";
|
|
26
|
-
export { get_ui_shell_config } from "./ui_shell_config.server.js";
|
|
27
|
-
export { get_ui_sizes_config } from "./ui_sizes_config.server.js";
|
|
28
|
-
export { get_auth_utility_config } from "./auth_utility_config.server.js";
|
|
29
|
-
export { get_password_requirements_config } from "./password_requirements_config.server.js";
|
|
30
|
-
export { get_messages_config } from "./messages_config.server.js";
|
|
31
|
-
export { get_user_fields_config } from "./user_fields_config.server.js";
|
|
32
|
-
export { get_file_types_config } from "./file_types_config.server.js";
|
|
33
|
-
export { get_oauth_config, is_google_oauth_enabled, is_email_password_enabled } from "./oauth_config.server.js";
|
|
34
|
-
export { get_branding_config, is_branding_enabled, is_allowed_logo_format, get_max_logo_size_bytes } from "./branding_config.server.js";
|
|
35
|
-
// section: util_exports
|
|
36
|
-
export { sanitize_error_for_user } from "./utils/error_sanitizer.js";
|
|
37
|
-
export * from "./utils/api_route_helpers.js";
|