Skip to content

Commit 002d838

Browse files
authored
🪵 refactor: Improve OpenID redirect origin handling and startup logs (#50)
* refactor: Improve request origin handling and restore metrics warning - Added a new function to extract the request origin from headers, enhancing cross-origin request handling. - Updated OpenID check and login functions to utilize the new origin extraction logic. - Restored the warning for unset ADMIN_PANEL_METRICS_SECRET, ensuring visibility for metrics endpoint access issues. - Refactored server initialization to log the correct port number. * refactor: request origin extraction for improved security - Introduced a new function to reliably extract the request origin from headers, improving handling of cross-origin requests. - Updated OpenID login and OAuth exchange functions to utilize the new origin extraction logic, ensuring correct redirect URIs. - Removed redundant origin handling code, streamlining the request processing flow.
1 parent 2928b61 commit 002d838

2 files changed

Lines changed: 38 additions & 19 deletions

File tree

‎server.ts‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,6 @@ type Handler = { default: { fetch: (req: Request) => Promise<Response> } };
3636

3737
const { default: handler } = (await import(SERVER_ENTRY.href)) as Handler;
3838

39-
if (!process.env.ADMIN_PANEL_METRICS_SECRET) {
40-
console.warn('[metrics] ADMIN_PANEL_METRICS_SECRET is not set — /metrics will return 401 for all requests');
41-
}
42-
4339
async function buildStaticRoutes(): Promise<Record<string, () => Response>> {
4440
const routes: Record<string, () => Response> = {};
4541
for await (const path of new Glob('**/*').scan(CLIENT_DIR)) {
@@ -51,7 +47,7 @@ async function buildStaticRoutes(): Promise<Record<string, () => Response>> {
5147
return routes;
5248
}
5349

54-
Bun.serve({
50+
const server = Bun.serve({
5551
port: Number(process.env.PORT ?? 3000),
5652
routes: {
5753
...(await buildStaticRoutes()),
@@ -72,4 +68,8 @@ Bun.serve({
7268
},
7369
});
7470

75-
console.log(`Admin panel listening on http://localhost:${process.env.PORT ?? 3000}`);
71+
console.log(`Admin panel listening on http://localhost:${server.port}`);
72+
73+
if (!process.env.ADMIN_PANEL_METRICS_SECRET) {
74+
console.warn('[metrics] ADMIN_PANEL_METRICS_SECRET is not set — /metrics will return 401 for all requests');
75+
}

‎src/server/auth.ts‎

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,26 @@ function extractCookieValue(response: Response, name: string): string | undefine
2121
return undefined;
2222
}
2323

24+
function getRequestOrigin(): string | undefined {
25+
const origin = getRequestHeader('origin');
26+
if (origin) return origin;
27+
28+
const referer = getRequestHeader('referer');
29+
if (referer) {
30+
try {
31+
return new URL(referer).origin;
32+
} catch {
33+
return undefined;
34+
}
35+
}
36+
37+
const host = getRequestHeader('host');
38+
if (!host) return undefined;
39+
40+
const proto = getRequestHeader('x-forwarded-proto') ?? 'http';
41+
return `${proto}://${host}`;
42+
}
43+
2444
export const adminLoginFn = createServerFn({ method: 'POST' })
2545
.inputValidator(
2646
z.object({
@@ -303,12 +323,17 @@ export const openIdCheckOptions = queryOptions({
303323
});
304324

305325
export const checkOpenIdFn = createServerFn({ method: 'GET' }).handler(async () => {
326+
const checkUrl = `${getServerApiUrl()}/api/admin/oauth/openid/check`;
306327
try {
307-
const response = await fetch(`${getServerApiUrl()}/api/admin/oauth/openid/check`);
308-
if (!response.ok) return { available: false, ssoOnly: false };
328+
const response = await fetch(checkUrl);
329+
if (!response.ok) {
330+
console.warn('[checkOpenIdFn] OpenID check failed:', response.status, checkUrl);
331+
return { available: false, ssoOnly: false };
332+
}
309333
const ssoOnly = process.env.ADMIN_SSO_ONLY === 'true';
310334
return { available: true, ssoOnly };
311-
} catch {
335+
} catch (error) {
336+
console.warn('[checkOpenIdFn] OpenID check request failed:', checkUrl, error);
312337
return { available: false, ssoOnly: false };
313338
}
314339
});
@@ -317,11 +342,12 @@ export const openidLoginFn = createServerFn({ method: 'GET' }).handler(async ()
317342
try {
318343
const baseUrl = getApiBaseUrl();
319344
const authUrl = new URL(`${baseUrl}/api/admin/oauth/openid`);
345+
const requestOrigin = getRequestOrigin();
320346

321-
/** Generate PKCE code_verifier and store in session */
322347
const codeVerifier = crypto.randomBytes(32).toString('hex');
323348
const codeChallenge = crypto.createHash('sha256').update(codeVerifier).digest('hex');
324349
authUrl.searchParams.set('code_challenge', codeChallenge);
350+
if (requestOrigin) authUrl.searchParams.set('redirect_uri', `${requestOrigin}/auth/openid/callback`);
325351

326352
const session = await useAppSession();
327353
await session.update({ codeVerifier });
@@ -340,16 +366,9 @@ export const oauthExchangeFn = createServerFn({ method: 'POST' })
340366
.handler(async ({ data }) => {
341367
try {
342368
const headers: Record<string, string> = { 'Content-Type': 'application/json' };
343-
const rawOrigin = getRequestHeader('origin') || getRequestHeader('referer');
344-
if (rawOrigin) {
345-
try {
346-
headers['Origin'] = new URL(rawOrigin).origin;
347-
} catch {
348-
// malformed URL – skip forwarding
349-
}
350-
}
369+
const requestOrigin = getRequestOrigin();
370+
if (requestOrigin) headers['Origin'] = requestOrigin;
351371

352-
/** Read PKCE code_verifier from session (stored during openidLoginFn) */
353372
const session = await useAppSession();
354373
const { codeVerifier } = session.data;
355374

0 commit comments

Comments
 (0)