Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 81 additions & 1 deletion src/modules/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,79 @@ import {
ResetPasswordParams,
} from "./auth.types";

const POPUP_AUTH_DOMAIN_REGEX =
/^(preview-sandbox--|preview--|checkpoint--)[^.]+\./;

function isPopupAuthDomain(): boolean {
if (typeof window === "undefined") return false;
return POPUP_AUTH_DOMAIN_REGEX.test(window.location.hostname);
}

/**
* Opens a URL in a centered popup and waits for the backend to postMessage
* the auth result back. On success, redirects the current window to
* redirectUrl with the token params appended, preserving the same behaviour
* as a normal full-page redirect flow.
*
* @param url - The login URL to open in the popup (should include popup_origin).
* @param redirectUrl - Where to redirect after auth (the original fromUrl).
* @param expectedOrigin - The origin we expect the postMessage to come from.
*/
function loginViaPopup(
url: string,
redirectUrl: string,
expectedOrigin: string
): void {
const width = 500;
const height = 600;
const left = Math.round(window.screenX + (window.outerWidth - width) / 2);
const top = Math.round(window.screenY + (window.outerHeight - height) / 2);

const popup = window.open(
url,
"base44_auth",
`width=${width},height=${height},left=${left},top=${top},resizable=yes,scrollbars=yes`
);

if (!popup) {
return;
}

const cleanup = () => {
window.removeEventListener("message", onMessage);
clearInterval(pollTimer);
if (!popup.closed) popup.close();
};

const onMessage = (event: MessageEvent) => {
if (event.origin !== expectedOrigin) return;
if (event.source !== popup) return;
if (!event.data?.access_token) return;

cleanup();

// Append the token params to redirectUrl so the app processes them
// exactly as it would from a normal OAuth callback redirect.
const callbackUrl = new URL(redirectUrl);
const { access_token, is_new_user } = event.data;

callbackUrl.searchParams.set("access_token", access_token);

if (is_new_user != null) {
callbackUrl.searchParams.set("is_new_user", String(is_new_user));
}

window.location.href = callbackUrl.toString();
};

// Only used to detect the user closing the popup before auth completes
const pollTimer = setInterval(() => {
if (popup.closed) cleanup();
}, 500);

window.addEventListener("message", onMessage);
}

/**
* Creates the auth module for the Base44 SDK.
*
Expand Down Expand Up @@ -74,7 +147,14 @@ export function createAuthModule(

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

// Redirect to the provider login page
// On preview/sandbox/checkpoint domains the app runs inside an iframe —
// use a popup to avoid OAuth providers blocking iframe navigation.
if (isPopupAuthDomain()) {
const popupLoginUrl = `${loginUrl}&popup_origin=${encodeURIComponent(window.location.origin)}`;
return loginViaPopup(popupLoginUrl, redirectUrl, window.location.origin);
}

// Default: full-page redirect
window.location.href = loginUrl;
},

Expand Down