diff --git a/src/modules/auth.ts b/src/modules/auth.ts index 13c35d7..afdb8d9 100644 --- a/src/modules/auth.ts +++ b/src/modules/auth.ts @@ -6,6 +6,7 @@ import { ChangePasswordParams, ResetPasswordParams, } from "./auth.types"; +import { getLoginUrl } from "../utils/auth-utils.js"; function isInsideIframe(): boolean { if (typeof window === "undefined") return false; @@ -116,8 +117,11 @@ export function createAuthModule( ? new URL(nextUrl, window.location.origin).toString() : window.location.href; - // Build the login URL - const loginUrl = `${options.appBaseUrl}/login?from_url=${encodeURIComponent(redirectUrl)}`; + // A foreign origin (e.g. local dev) can't resolve the app by Host, so + // the login URL must carry the app id; same-origin keeps the bare path. + const loginUrl = options.appBaseUrl + ? getLoginUrl(redirectUrl, { serverUrl: options.appBaseUrl, appId }) + : `/login?from_url=${encodeURIComponent(redirectUrl)}`; // Redirect to the login page window.location.href = loginUrl; diff --git a/tests/unit/auth.test.js b/tests/unit/auth.test.js index c31f7a1..26f1a87 100644 --- a/tests/unit/auth.test.js +++ b/tests/unit/auth.test.js @@ -165,7 +165,7 @@ describe('Auth Module', () => { // Verify the redirect URL was set correctly expect(mockLocation.href).toBe( - `${appBaseUrl}/login?from_url=${encodeURIComponent(nextUrl)}` + `${appBaseUrl}/login?from_url=${encodeURIComponent(nextUrl)}&app_id=${appId}` ); // Restore window @@ -185,7 +185,7 @@ describe('Auth Module', () => { // Verify the redirect URL uses current URL expect(mockLocation.href).toBe( - `${appBaseUrl}/login?from_url=${encodeURIComponent(currentUrl)}` + `${appBaseUrl}/login?from_url=${encodeURIComponent(currentUrl)}&app_id=${appId}` ); // Restore window @@ -212,13 +212,30 @@ describe('Auth Module', () => { // Verify the redirect URL uses the custom appBaseUrl expect(mockLocation.href).toBe( - `${customAppBaseUrl}/login?from_url=${encodeURIComponent(nextUrl)}` + `${customAppBaseUrl}/login?from_url=${encodeURIComponent(nextUrl)}&app_id=${appId}` ); // Restore window global.window = originalWindow; }); + test('should preserve a query string in nextUrl through from_url encoding', () => { + const originalWindow = global.window; + const mockLocation = { href: '' }; + global.window = { + location: mockLocation + }; + + const nextUrl = 'https://example.com/dashboard?tab=x&page=2'; + base44.auth.redirectToLogin(nextUrl); + + expect(mockLocation.href).toBe( + `${appBaseUrl}/login?from_url=${encodeURIComponent(nextUrl)}&app_id=${appId}` + ); + + global.window = originalWindow; + }); + test('should use relative URL for login redirect when appBaseUrl is not provided', () => { // Create a client without appBaseUrl const clientWithoutAppBaseUrl = createClient({ diff --git a/tests/unit/client.test.js b/tests/unit/client.test.js index 5ba2eba..4fdd5ec 100644 --- a/tests/unit/client.test.js +++ b/tests/unit/client.test.js @@ -98,7 +98,7 @@ describe('appBaseUrl Normalization', () => { // Verify the redirect URL uses the custom appBaseUrl expect(mockLocation.href).toBe( - `${customAppBaseUrl}/login?from_url=${encodeURIComponent(nextUrl)}` + `${customAppBaseUrl}/login?from_url=${encodeURIComponent(nextUrl)}&app_id=test-app-id` ); // Restore window