Skip to content

Commit 76a0e8e

Browse files
authored
Merge d956672 into ead5bf3
2 parents ead5bf3 + d956672 commit 76a0e8e

File tree

1 file changed

+81
-1
lines changed

1 file changed

+81
-1
lines changed

src/modules/auth.ts

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,79 @@ import {
77
ResetPasswordParams,
88
} from "./auth.types";
99

10+
const POPUP_AUTH_DOMAIN_REGEX =
11+
/^(preview-sandbox--|preview--|checkpoint--)[^.]+\./;
12+
13+
function isPopupAuthDomain(): boolean {
14+
if (typeof window === "undefined") return false;
15+
return POPUP_AUTH_DOMAIN_REGEX.test(window.location.hostname);
16+
}
17+
18+
/**
19+
* Opens a URL in a centered popup and waits for the backend to postMessage
20+
* the auth result back. On success, redirects the current window to
21+
* redirectUrl with the token params appended, preserving the same behaviour
22+
* as a normal full-page redirect flow.
23+
*
24+
* @param url - The login URL to open in the popup (should include popup_origin).
25+
* @param redirectUrl - Where to redirect after auth (the original fromUrl).
26+
* @param expectedOrigin - The origin we expect the postMessage to come from.
27+
*/
28+
function loginViaPopup(
29+
url: string,
30+
redirectUrl: string,
31+
expectedOrigin: string
32+
): void {
33+
const width = 500;
34+
const height = 600;
35+
const left = Math.round(window.screenX + (window.outerWidth - width) / 2);
36+
const top = Math.round(window.screenY + (window.outerHeight - height) / 2);
37+
38+
const popup = window.open(
39+
url,
40+
"base44_auth",
41+
`width=${width},height=${height},left=${left},top=${top},resizable=yes,scrollbars=yes`
42+
);
43+
44+
if (!popup) {
45+
return;
46+
}
47+
48+
const cleanup = () => {
49+
window.removeEventListener("message", onMessage);
50+
clearInterval(pollTimer);
51+
if (!popup.closed) popup.close();
52+
};
53+
54+
const onMessage = (event: MessageEvent) => {
55+
if (event.origin !== expectedOrigin) return;
56+
if (event.source !== popup) return;
57+
if (!event.data?.access_token) return;
58+
59+
cleanup();
60+
61+
// Append the token params to redirectUrl so the app processes them
62+
// exactly as it would from a normal OAuth callback redirect.
63+
const callbackUrl = new URL(redirectUrl);
64+
const { access_token, is_new_user } = event.data;
65+
66+
callbackUrl.searchParams.set("access_token", access_token);
67+
68+
if (is_new_user != null) {
69+
callbackUrl.searchParams.set("is_new_user", String(is_new_user));
70+
}
71+
72+
window.location.href = callbackUrl.toString();
73+
};
74+
75+
// Only used to detect the user closing the popup before auth completes
76+
const pollTimer = setInterval(() => {
77+
if (popup.closed) cleanup();
78+
}, 500);
79+
80+
window.addEventListener("message", onMessage);
81+
}
82+
1083
/**
1184
* Creates the auth module for the Base44 SDK.
1285
*
@@ -74,7 +147,14 @@ export function createAuthModule(
74147

75148
const loginUrl = `${options.appBaseUrl}/api${authPath}?${queryParams}`;
76149

77-
// Redirect to the provider login page
150+
// On preview/sandbox/checkpoint domains the app runs inside an iframe —
151+
// use a popup to avoid OAuth providers blocking iframe navigation.
152+
if (isPopupAuthDomain()) {
153+
const popupLoginUrl = `${loginUrl}&popup_origin=${encodeURIComponent(window.location.origin)}`;
154+
return loginViaPopup(popupLoginUrl, redirectUrl, window.location.origin);
155+
}
156+
157+
// Default: full-page redirect
78158
window.location.href = loginUrl;
79159
},
80160

0 commit comments

Comments
 (0)