mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2026-08-24 07:12:18 +10:00
fix(auth): use loopback URL for MCP OAuth JWKS verification (#3297)
* fix(auth): use loopback URL for MCP OAuth JWKS verification Fetch the JWKS endpoint over the internal loopback address instead of the public APP_URL, so token verification works under Docker port-mapping, reverse proxies, and other deployments where the public URL does not loop back to the Node process. Also log the specific MCP OAuth verification error instead of swallowing it with a bare catch. Fixes #3077 * fix(auth): normalize internal JWKS URL and throttle MCP OAuth warnings - Problem: default loopback JWKS URL used PORT in dev where the server listens on SERVER_PORT (3001), and trailing-slash overrides produced //api/auth/jwks; unthrottled warn logs could flood on bad bearer tokens. - Fix: resolveInternalBaseUrl trims/normalizes BETTER_AUTH_INTERNAL_URL, mirrors apps/server listen-port selection, and MCP OAuth warnings are throttled to once per minute. - Verification: pnpm exec biome check on changed files; pnpm typecheck. * fix(auth): declare BETTER_AUTH_INTERNAL_URL in turbo globalEnv - Problem: Turborepo strict env mode strips undeclared BETTER_AUTH_INTERNAL_URL under pnpm dev, so the JWKS override silently falls back to loopback. - Fix: add BETTER_AUTH_INTERNAL_URL to turbo.json globalEnv (required for any new env var per CLAUDE.md). - Verification: python3 JSON parse of turbo.json; confirmed var was absent from globalEnv before this change. --------- Co-authored-by: Amruth Pillai <im.amruth@gmail.com>
This commit is contained in:
co-authored by
Amruth Pillai
parent
5fc9c3ee04
commit
7eb6d3bdbf
@@ -28,6 +28,23 @@ import { getTrustedOrigins } from "./trusted-origins";
|
||||
const authBaseUrl = env.APP_URL;
|
||||
const isRateLimitEnabled = process.env.NODE_ENV === "production" && !env.FLAG_DISABLE_API_RATE_LIMIT;
|
||||
|
||||
// JWKS must be reachable from inside the Node runtime. `authBaseUrl` is the
|
||||
// publicly-visible URL — under Docker port-mapping or behind a reverse proxy
|
||||
// it does not loop back to the app process. Override with `BETTER_AUTH_INTERNAL_URL`
|
||||
// for split deployments or custom servers that bind to a port not exposed via `PORT`.
|
||||
function resolveInternalBaseUrl(): string {
|
||||
const configured = process.env.BETTER_AUTH_INTERNAL_URL?.trim();
|
||||
if (configured) {
|
||||
return configured.replace(/\/+$/, "");
|
||||
}
|
||||
|
||||
const port = process.env.NODE_ENV === "production" ? (process.env.PORT ?? "3000") : String(env.SERVER_PORT);
|
||||
|
||||
return `http://127.0.0.1:${port}`;
|
||||
}
|
||||
|
||||
const internalBaseUrl = resolveInternalBaseUrl();
|
||||
|
||||
const oauthAudienceBase = authBaseUrl.replace(/\/$/, "");
|
||||
const OAUTH_AUDIENCES = [
|
||||
oauthAudienceBase,
|
||||
@@ -38,7 +55,7 @@ const OAUTH_AUDIENCES = [
|
||||
|
||||
export function verifyOAuthToken(token: string): Promise<JWTPayload> {
|
||||
return verifyAccessToken(token, {
|
||||
jwksUrl: `${authBaseUrl}/api/auth/jwks`,
|
||||
jwksUrl: `${internalBaseUrl}/api/auth/jwks`,
|
||||
verifyOptions: {
|
||||
issuer: `${authBaseUrl}/api/auth`,
|
||||
audience: OAUTH_AUDIENCES,
|
||||
|
||||
Reference in New Issue
Block a user