Skip to content

Commit 1beb8e4

Browse files
authored
redirect to login on app base url (#39)
1 parent dfd6141 commit 1beb8e4

4 files changed

Lines changed: 60 additions & 73 deletions

File tree

src/client.ts

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export type Base44Client = ReturnType<typeof createClient>;
1818
* Create a Base44 client instance
1919
* @param {Object} config - Client configuration
2020
* @param {string} [config.serverUrl='https://base44.app'] - API server URL
21+
* @param {string} [config.appBaseUrl] - Application base URL
2122
* @param {string|number} config.appId - Application ID
2223
* @param {string} [config.token] - Authentication token
2324
* @param {string} [config.serviceToken] - Service role authentication token
@@ -26,24 +27,24 @@ export type Base44Client = ReturnType<typeof createClient>;
2627
*/
2728
export function createClient(config: {
2829
serverUrl?: string;
30+
appBaseUrl?: string;
2931
appId: string;
3032
token?: string;
3133
serviceToken?: string;
3234
requiresAuth?: boolean;
3335
functionsVersion?: string;
3436
headers?: Record<string, string>;
3537
options?: CreateClientOptions;
36-
onRedirectToLogin?: () => void;
3738
}) {
3839
const {
3940
serverUrl = "https://base44.app",
4041
appId,
4142
token,
4243
serviceToken,
4344
requiresAuth = false,
45+
appBaseUrl,
4446
options,
4547
functionsVersion,
46-
onRedirectToLogin,
4748
headers: optionalHeaders,
4849
} = config;
4950

@@ -75,50 +76,36 @@ export function createClient(config: {
7576
baseURL: `${serverUrl}/api`,
7677
headers,
7778
token,
78-
requiresAuth,
79-
appId,
80-
serverUrl,
8179
onError: options?.onError,
82-
onRedirectToLogin,
8380
});
8481

8582
const functionsAxiosClient = createAxiosClient({
8683
baseURL: `${serverUrl}/api`,
8784
headers: functionHeaders,
8885
token,
89-
requiresAuth,
90-
appId,
91-
serverUrl,
9286
interceptResponses: false,
9387
onError: options?.onError,
94-
onRedirectToLogin,
9588
});
9689

9790
const serviceRoleAxiosClient = createAxiosClient({
9891
baseURL: `${serverUrl}/api`,
9992
headers,
10093
token: serviceToken,
101-
serverUrl,
102-
appId,
10394
onError: options?.onError,
104-
onRedirectToLogin,
10595
});
10696

10797
const serviceRoleFunctionsAxiosClient = createAxiosClient({
10898
baseURL: `${serverUrl}/api`,
10999
headers: functionHeaders,
110100
token: serviceToken,
111-
serverUrl,
112-
appId,
113101
interceptResponses: false,
114-
onRedirectToLogin,
115102
});
116103

117104
const userModules = {
118105
entities: createEntitiesModule(axiosClient, appId),
119106
integrations: createIntegrationsModule(axiosClient, appId),
120107
auth: createAuthModule(axiosClient, functionsAxiosClient, appId, {
121-
onRedirectToLogin,
108+
appBaseUrl,
122109
serverUrl,
123110
}),
124111
functions: createFunctionsModule(functionsAxiosClient, appId),
@@ -144,7 +131,7 @@ export function createClient(config: {
144131
socket,
145132
appId,
146133
serverUrl,
147-
token
134+
token,
148135
}),
149136
cleanup: () => {
150137
socket.disconnect();

src/modules/auth.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export function createAuthModule(
1313
appId: string,
1414
options: {
1515
serverUrl: string;
16-
onRedirectToLogin?: () => void;
16+
appBaseUrl?: string;
1717
}
1818
) {
1919
return {
@@ -46,19 +46,15 @@ export function createAuthModule(
4646
);
4747
}
4848

49-
if (options.onRedirectToLogin) {
50-
options.onRedirectToLogin();
51-
return;
52-
}
5349
// If nextUrl is not provided, use the current URL
5450
const redirectUrl = nextUrl
5551
? new URL(nextUrl, window.location.origin).toString()
5652
: window.location.href;
5753

5854
// Build the login URL
5955
const loginUrl = `${
60-
options.serverUrl
61-
}/login?from_url=${encodeURIComponent(redirectUrl)}&app_id=${appId}`;
56+
options.appBaseUrl ?? ""
57+
}/login?from_url=${encodeURIComponent(redirectUrl)}`;
6258

6359
// Redirect to the login page
6460
window.location.href = loginUrl;

src/utils/axios-client.ts

Lines changed: 0 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -57,21 +57,6 @@ function safeErrorLog(prefix: string, error: unknown) {
5757
}
5858
}
5959

60-
/**
61-
* Redirects to the login page with the current URL as return destination
62-
* @param {string} serverUrl - Base server URL
63-
* @param {string|number} appId - Application ID
64-
*/
65-
function redirectToLogin(serverUrl: string, appId: string) {
66-
if (typeof window === "undefined") {
67-
return; // Can't redirect in non-browser environment
68-
}
69-
70-
const currentUrl = encodeURIComponent(window.location.href);
71-
const loginUrl = `${serverUrl}/login?from_url=${currentUrl}&app_id=${appId}`;
72-
window.location.href = loginUrl;
73-
}
74-
7560
/**
7661
* Creates an axios client with default configuration and interceptors
7762
* @param {Object} options - Client configuration options
@@ -87,22 +72,14 @@ export function createAxiosClient({
8772
baseURL,
8873
headers = {},
8974
token,
90-
requiresAuth = false,
91-
appId,
92-
serverUrl,
9375
interceptResponses = true,
9476
onError,
95-
onRedirectToLogin,
9677
}: {
9778
baseURL: string;
9879
headers?: Record<string, string>;
9980
token?: string;
100-
requiresAuth?: boolean;
101-
appId: string;
102-
serverUrl: string;
10381
interceptResponses?: boolean;
10482
onError?: (error: Error) => void;
105-
onRedirectToLogin?: () => void;
10683
}) {
10784
const client = axios.create({
10885
baseURL,
@@ -193,26 +170,6 @@ export function createAxiosClient({
193170
safeErrorLog("[Base44 SDK Error]", base44Error);
194171
}
195172

196-
// Check for 403 Forbidden (authentication required) and redirect to login if requiresAuth is true
197-
console.log(
198-
requiresAuth,
199-
error.response?.status,
200-
typeof window !== "undefined"
201-
);
202-
if (
203-
requiresAuth &&
204-
error.response?.status === 403 &&
205-
typeof window !== "undefined"
206-
) {
207-
console.log("Authentication required. Redirecting to login...");
208-
// Use a slight delay to allow the error to propagate first
209-
setTimeout(() => {
210-
onRedirectToLogin
211-
? onRedirectToLogin()
212-
: redirectToLogin(serverUrl, appId);
213-
}, 100);
214-
}
215-
216173
onError?.(base44Error);
217174

218175
return Promise.reject(base44Error);

tests/unit/auth.test.js

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ describe('Auth Module', () => {
149149

150150
// Verify the redirect URL was set correctly
151151
expect(mockLocation.href).toBe(
152-
`${serverUrl}/login?from_url=${encodeURIComponent(nextUrl)}&app_id=${appId}`
152+
`/login?from_url=${encodeURIComponent(nextUrl)}`
153153
);
154154

155155
// Restore window
@@ -164,14 +164,61 @@ describe('Auth Module', () => {
164164
global.window = {
165165
location: mockLocation
166166
};
167-
167+
168168
base44.auth.redirectToLogin();
169-
169+
170170
// Verify the redirect URL uses current URL
171171
expect(mockLocation.href).toBe(
172-
`${serverUrl}/login?from_url=${encodeURIComponent(currentUrl)}&app_id=${appId}`
172+
`/login?from_url=${encodeURIComponent(currentUrl)}`
173173
);
174-
174+
175+
// Restore window
176+
global.window = originalWindow;
177+
});
178+
179+
test('should use appBaseUrl for login redirect when provided', () => {
180+
const customAppBaseUrl = 'https://custom-app.example.com';
181+
const clientWithCustomUrl = createClient({
182+
serverUrl,
183+
appId,
184+
appBaseUrl: customAppBaseUrl,
185+
});
186+
187+
// Mock window.location
188+
const originalWindow = global.window;
189+
const mockLocation = { href: '' };
190+
global.window = {
191+
location: mockLocation
192+
};
193+
194+
const nextUrl = 'https://example.com/dashboard';
195+
clientWithCustomUrl.auth.redirectToLogin(nextUrl);
196+
197+
// Verify the redirect URL uses the custom appBaseUrl
198+
expect(mockLocation.href).toBe(
199+
`${customAppBaseUrl}/login?from_url=${encodeURIComponent(nextUrl)}`
200+
);
201+
202+
// Restore window
203+
global.window = originalWindow;
204+
});
205+
206+
test('should use relative URL for login redirect when appBaseUrl is not provided', () => {
207+
// Mock window.location
208+
const originalWindow = global.window;
209+
const mockLocation = { href: '', origin: 'https://current-app.com' };
210+
global.window = {
211+
location: mockLocation
212+
};
213+
214+
const nextUrl = 'https://example.com/dashboard';
215+
base44.auth.redirectToLogin(nextUrl);
216+
217+
// Verify the redirect URL uses a relative path (no appBaseUrl prefix)
218+
expect(mockLocation.href).toBe(
219+
`/login?from_url=${encodeURIComponent(nextUrl)}`
220+
);
221+
175222
// Restore window
176223
global.window = originalWindow;
177224
});

0 commit comments

Comments
 (0)