@@ -10,9 +10,20 @@ import {
1010import { ErrorCode , WebRouteError , mapRuntimeError } from "./errors.js" ;
1111import { bearerAuthMiddleware } from "../../middleware/bearer-auth.js" ;
1212import { guestRateLimitMiddleware } from "../../middleware/guest-rate-limit.js" ;
13+ import { getRequestLogger } from "../../utils/request-logger.js" ;
14+ import { classifyError } from "../../utils/error-classify.js" ;
1315
1416const oauthWeb = new Hono ( ) ;
1517
18+ function safeHostname ( url : string | undefined ) : string {
19+ if ( ! url ) return "unknown" ;
20+ try {
21+ return new URL ( url ) . hostname || url ;
22+ } catch {
23+ return url ;
24+ }
25+ }
26+
1627// Require some form of bearer token (guest or WorkOS) on all OAuth proxy routes
1728oauthWeb . use ( "*" , bearerAuthMiddleware ) ;
1829
@@ -79,8 +90,10 @@ function getConvexHttpUrl(): string {
7990 * Body: { url: string, method?: string, body?: object, headers?: object }
8091 */
8192oauthWeb . post ( "/proxy" , async ( c ) => {
93+ let proxyUrl : string | undefined ;
8294 try {
8395 const { url, method, body, headers } = await c . req . json ( ) ;
96+ proxyUrl = url ;
8497 const result = await executeOAuthProxy ( {
8598 url,
8699 method,
@@ -90,6 +103,12 @@ oauthWeb.post("/proxy", async (c) => {
90103 } ) ;
91104 return c . json ( result ) ;
92105 } catch ( error ) {
106+ getRequestLogger ( c , "routes.web.oauth" ) . event ( "mcp.oauth.proxy.failed" , {
107+ targetUrlHost : safeHostname ( proxyUrl ) ,
108+ oauthPhase : "proxy" ,
109+ errorCode : classifyError ( error ) ,
110+ ...( error instanceof OAuthProxyError ? { statusCode : error . status } : { } ) ,
111+ } ) ;
93112 return webErrorCompat ( c , toRouteError ( error ) ) ;
94113 }
95114} ) ;
@@ -101,17 +120,17 @@ oauthWeb.post("/proxy", async (c) => {
101120 * Mirrors /api/mcp/oauth/metadata with HTTPS-only + private IP blocking.
102121 */
103122oauthWeb . get ( "/metadata" , async ( c ) => {
123+ const metadataUrl = c . req . query ( "url" ) ;
104124 try {
105- const url = c . req . query ( "url" ) ;
106- if ( ! url ) {
125+ if ( ! metadataUrl ) {
107126 throw new WebRouteError (
108127 400 ,
109128 ErrorCode . VALIDATION_ERROR ,
110129 "Missing url parameter" ,
111130 ) ;
112131 }
113132
114- const result = await fetchOAuthMetadata ( url , true ) ;
133+ const result = await fetchOAuthMetadata ( metadataUrl , true ) ;
115134 if ( "status" in result && result . status !== undefined ) {
116135 throw new WebRouteError (
117136 result . status ,
@@ -122,6 +141,12 @@ oauthWeb.get("/metadata", async (c) => {
122141
123142 return c . json ( result . metadata ) ;
124143 } catch ( error ) {
144+ getRequestLogger ( c , "routes.web.oauth" ) . event ( "mcp.oauth.proxy.failed" , {
145+ targetUrlHost : safeHostname ( metadataUrl ) ,
146+ oauthPhase : "metadata" ,
147+ errorCode : classifyError ( error ) ,
148+ ...( error instanceof OAuthProxyError ? { statusCode : error . status } : { } ) ,
149+ } ) ;
125150 return webErrorCompat ( c , toRouteError ( error ) ) ;
126151 }
127152} ) ;
@@ -161,8 +186,10 @@ oauthWeb.post("/session", async (c) => {
161186 * Body: { url: string, method?: string, body?: object, headers?: object }
162187 */
163188oauthWeb . post ( "/debug/proxy" , async ( c ) => {
189+ let proxyUrl : string | undefined ;
164190 try {
165191 const { url, method, body, headers } = await c . req . json ( ) ;
192+ proxyUrl = url ;
166193 const result = await executeDebugOAuthProxy ( {
167194 url,
168195 method,
@@ -172,6 +199,12 @@ oauthWeb.post("/debug/proxy", async (c) => {
172199 } ) ;
173200 return c . json ( result ) ;
174201 } catch ( error ) {
202+ getRequestLogger ( c , "routes.web.oauth" ) . event ( "mcp.oauth.proxy.failed" , {
203+ targetUrlHost : safeHostname ( proxyUrl ) ,
204+ oauthPhase : "proxy" ,
205+ errorCode : classifyError ( error ) ,
206+ ...( error instanceof OAuthProxyError ? { statusCode : error . status } : { } ) ,
207+ } ) ;
175208 return webErrorCompat ( c , toRouteError ( error ) ) ;
176209 }
177210} ) ;
0 commit comments