Skip to content

Commit 5242d43

Browse files
authored
feat: add API_SERVER_URL for separate server-side and browser API URLs (#14)
1 parent 5369fc9 commit 5242d43

3 files changed

Lines changed: 24 additions & 11 deletions

File tree

.env.example

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,14 @@
55
SESSION_SECRET=
66

77
# ── Optional ─────────────────────────────────────────────────
8-
# Base URL of the LibreChat API server. Defaults to http://localhost:3080
8+
# Browser-facing URL of the LibreChat API server (used for OAuth redirects).
9+
# Defaults to http://localhost:3080
910
# VITE_API_BASE_URL=http://localhost:3080
1011

12+
# Server-side URL for LibreChat API calls. Falls back to VITE_API_BASE_URL.
13+
# Useful when the server reaches LibreChat on a different URL than the browser.
14+
# API_SERVER_URL=http://localhost:3080
15+
1116
# Force SSO-only login (hides the email/password form)
1217
# ADMIN_SSO_ONLY=false
1318

src/server/auth.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { createServerFn } from '@tanstack/react-start';
77
import { getRequestHeader } from '@tanstack/react-start/server';
88
import type * as t from '@/types';
99
import { useAppSession, SESSION_CONFIG } from './session';
10-
import { getApiBaseUrl } from './utils/api';
10+
import { getApiBaseUrl, getServerApiUrl } from './utils/api';
1111

1212
/** Extract a named cookie value from `set-cookie` response headers. */
1313
function extractCookieValue(response: Response, name: string): string | undefined {
@@ -29,7 +29,7 @@ export const adminLoginFn = createServerFn({ method: 'POST' })
2929
)
3030
.handler(async ({ data }) => {
3131
try {
32-
const response = await fetch(`${getApiBaseUrl()}/api/admin/login/local`, {
32+
const response = await fetch(`${getServerApiUrl()}/api/admin/login/local`, {
3333
method: 'POST',
3434
headers: { 'Content-Type': 'application/json' },
3535
body: JSON.stringify(data),
@@ -93,7 +93,7 @@ export const adminVerify2FAFn = createServerFn({ method: 'POST' })
9393
)
9494
.handler(async ({ data }) => {
9595
try {
96-
const response = await fetch(`${getApiBaseUrl()}/api/auth/2fa/verify-temp`, {
96+
const response = await fetch(`${getServerApiUrl()}/api/auth/2fa/verify-temp`, {
9797
method: 'POST',
9898
headers: { 'Content-Type': 'application/json' },
9999
body: JSON.stringify({ tempToken: data.tempToken, token: data.totpCode }),
@@ -170,7 +170,7 @@ async function refreshAdminToken(
170170
cookieParts.push('token_provider=openid');
171171
}
172172

173-
const response = await fetch(`${getApiBaseUrl()}/api/auth/refresh`, {
173+
const response = await fetch(`${getServerApiUrl()}/api/auth/refresh`, {
174174
method: 'POST',
175175
headers: { Cookie: cookieParts.join('; ') },
176176
});
@@ -216,7 +216,7 @@ export const verifyAdminTokenFn = createServerFn({ method: 'GET' }).handler(asyn
216216

217217
if (needsRevalidation) {
218218
try {
219-
const response = await fetch(`${getApiBaseUrl()}/api/admin/verify`, {
219+
const response = await fetch(`${getServerApiUrl()}/api/admin/verify`, {
220220
headers: { Authorization: `Bearer ${token}` },
221221
});
222222

@@ -236,7 +236,7 @@ export const verifyAdminTokenFn = createServerFn({ method: 'GET' }).handler(asyn
236236
lastActivity: now,
237237
};
238238
try {
239-
const reVerify = await fetch(`${getApiBaseUrl()}/api/admin/verify`, {
239+
const reVerify = await fetch(`${getServerApiUrl()}/api/admin/verify`, {
240240
headers: { Authorization: `Bearer ${refreshed.token}` },
241241
});
242242
if (reVerify.ok) {
@@ -305,7 +305,7 @@ export const adminLogoutFn = createServerFn({ method: 'POST' }).handler(async ()
305305

306306
if (token) {
307307
try {
308-
await fetch(`${getApiBaseUrl()}/api/auth/logout`, {
308+
await fetch(`${getServerApiUrl()}/api/auth/logout`, {
309309
method: 'POST',
310310
headers: { Authorization: `Bearer ${token}` },
311311
});
@@ -340,7 +340,7 @@ export const openIdCheckOptions = queryOptions({
340340

341341
export const checkOpenIdFn = createServerFn({ method: 'GET' }).handler(async () => {
342342
try {
343-
const response = await fetch(`${getApiBaseUrl()}/api/admin/oauth/openid/check`);
343+
const response = await fetch(`${getServerApiUrl()}/api/admin/oauth/openid/check`);
344344
if (!response.ok) return { available: false, ssoOnly: false };
345345
const ssoOnly = process.env.ADMIN_SSO_ONLY === 'true';
346346
return { available: true, ssoOnly };
@@ -389,7 +389,7 @@ export const oauthExchangeFn = createServerFn({ method: 'POST' })
389389
const session = await useAppSession();
390390
const { codeVerifier } = session.data;
391391

392-
const response = await fetch(`${getApiBaseUrl()}/api/admin/oauth/exchange`, {
392+
const response = await fetch(`${getServerApiUrl()}/api/admin/oauth/exchange`, {
393393
method: 'POST',
394394
headers,
395395
body: JSON.stringify({ code: data.code, code_verifier: codeVerifier }),

src/server/utils/api.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,14 @@ export function getApiBaseUrl(): string {
1010
return 'http://localhost:3080';
1111
}
1212

13+
/** Server-to-server API URL. Falls back to getApiBaseUrl() if API_SERVER_URL is not set. */
14+
export function getServerApiUrl(): string {
15+
if (typeof process !== 'undefined' && process.env?.API_SERVER_URL) {
16+
return process.env.API_SERVER_URL;
17+
}
18+
return getApiBaseUrl();
19+
}
20+
1321
/**
1422
* Make an authenticated request to the LibreChat API.
1523
* Reads the JWT token from the admin session and sets the Authorization header.
@@ -23,7 +31,7 @@ export async function apiFetch(path: string, init?: RequestInit): Promise<Respon
2331
throw new Error('No admin session token available');
2432
}
2533

26-
const url = `${getApiBaseUrl()}${path}`;
34+
const url = `${getServerApiUrl()}${path}`;
2735
return fetch(url, {
2836
...init,
2937
headers: {

0 commit comments

Comments
 (0)