hazo_auth 5.1.33 → 5.1.34
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/cli-src/lib/utils/proxy_request.ts +81 -0
- package/dist/components/ui/button.d.ts +1 -1
- 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/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
|
@@ -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,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> {
|
|
@@ -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
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hazo_auth",
|
|
3
|
-
"version": "5.1.
|
|
3
|
+
"version": "5.1.34",
|
|
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";
|