11/**
22 * OAuth helper for browser-based MCP authentication
3- *
3+ *
44 * This helper provides OAuth 2.0 authorization code flow support for MCP servers
55 * that require authentication, such as Linear's MCP server.
66 */
@@ -107,12 +107,13 @@ export class OAuthHelper {
107107 // Any other response (200, 404, 500, etc.) means no auth required
108108 console . log ( '✅ [OAuthHelper] No authentication required for:' , serverUrl )
109109 return false
110- } catch ( error : any ) {
110+ }
111+ catch ( error : any ) {
111112 console . warn ( '⚠️ [OAuthHelper] Could not check auth requirement for:' , serverUrl , error )
112113
113114 // Handle specific error types
114- if ( error . name === 'TypeError' &&
115- ( error . message ?. includes ( 'CORS' ) || error . message ?. includes ( 'Failed to fetch' ) ) ) {
115+ if ( error . name === 'TypeError'
116+ && ( error . message ?. includes ( 'CORS' ) || error . message ?. includes ( 'Failed to fetch' ) ) ) {
116117 console . log ( '🔍 [OAuthHelper] CORS blocked direct check, using heuristics for:' , serverUrl )
117118 return this . checkAuthByHeuristics ( serverUrl )
118119 }
@@ -149,7 +150,7 @@ export class OAuthHelper {
149150 // Known patterns that typically don't require auth (public MCP servers)
150151 const noAuthPatterns = [
151152 / l o c a l h o s t / i, // Local development
152- / 1 2 7 \. 0 \. 0 \. 1 / i , // Local development
153+ / 1 2 7 \. 0 \. 0 \. 1 / , // Local development
153154 / \. l o c a l / i, // Local development
154155 / m c p \. .* \. c o m / i, // Generic MCP server pattern (often public)
155156 ]
@@ -182,22 +183,23 @@ export class OAuthHelper {
182183 try {
183184 const discoveryUrl = `${ serverUrl } /.well-known/oauth-authorization-server`
184185 const response = await fetch ( discoveryUrl )
185-
186+
186187 if ( ! response . ok ) {
187188 throw new Error ( `OAuth discovery failed: ${ response . status } ${ response . statusText } ` )
188189 }
189-
190+
190191 this . discovery = await response . json ( )
191192 return this . discovery
192- } catch ( error ) {
193+ }
194+ catch ( error ) {
193195 throw new Error ( `Failed to discover OAuth configuration: ${ error } ` )
194196 }
195197 }
196198
197199 /**
198200 * Register a new OAuth client dynamically
199201 */
200- async registerClient ( serverUrl : string ) : Promise < ClientRegistration > {
202+ async registerClient ( _serverUrl : string ) : Promise < ClientRegistration > {
201203 if ( ! this . discovery ) {
202204 throw new Error ( 'OAuth discovery not performed. Call discoverOAuthConfig first.' )
203205 }
@@ -227,7 +229,7 @@ export class OAuthHelper {
227229 headers : {
228230 'Content-Type' : 'application/json' ,
229231 } ,
230- body : JSON . stringify ( registrationData )
232+ body : JSON . stringify ( registrationData ) ,
231233 } )
232234
233235 if ( ! response . ok ) {
@@ -242,7 +244,8 @@ export class OAuthHelper {
242244 } )
243245
244246 return this . clientRegistration
245- } catch ( error ) {
247+ }
248+ catch ( error ) {
246249 console . error ( '❌ [OAuthHelper] Client registration failed:' , error )
247250 throw new Error ( `Failed to register OAuth client: ${ error } ` )
248251 }
@@ -262,7 +265,7 @@ export class OAuthHelper {
262265 response_type : 'code' ,
263266 scope : this . config . scope || 'read' ,
264267 state : this . config . state || this . generateState ( ) ,
265- ...additionalParams
268+ ...additionalParams ,
266269 } )
267270
268271 return `${ this . discovery . authorization_endpoint } ?${ params . toString ( ) } `
@@ -272,9 +275,9 @@ export class OAuthHelper {
272275 * Exchange authorization code for access token
273276 */
274277 async exchangeCodeForToken (
275- serverUrl : string ,
276- code : string ,
277- codeVerifier ?: string
278+ serverUrl : string ,
279+ code : string ,
280+ codeVerifier ?: string ,
278281 ) : Promise < OAuthResult > {
279282 if ( ! this . discovery ) {
280283 throw new Error ( 'OAuth discovery not performed. Call discoverOAuthConfig first.' )
@@ -296,7 +299,7 @@ export class OAuthHelper {
296299 headers : {
297300 'Content-Type' : 'application/x-www-form-urlencoded' ,
298301 } ,
299- body : body . toString ( )
302+ body : body . toString ( ) ,
300303 } )
301304
302305 if ( ! response . ok ) {
@@ -310,7 +313,7 @@ export class OAuthHelper {
310313 /**
311314 * Handle OAuth callback and extract authorization code
312315 */
313- handleCallback ( ) : { code : string ; state : string } | null {
316+ handleCallback ( ) : { code : string , state : string } | null {
314317 const urlParams = new URLSearchParams ( window . location . search )
315318 const code = urlParams . get ( 'code' )
316319 const state = urlParams . get ( 'state' )
@@ -340,20 +343,21 @@ export class OAuthHelper {
340343 try {
341344 await this . discoverOAuthConfig ( serverUrl )
342345 const authUrl = this . generateAuthUrl ( serverUrl )
343-
346+
344347 // Open popup window for authentication (similar to your implementation)
345348 const authWindow = window . open (
346349 authUrl ,
347350 'mcp-oauth' ,
348- 'width=500,height=600,scrollbars=yes,resizable=yes,status=yes,location=yes'
351+ 'width=500,height=600,scrollbars=yes,resizable=yes,status=yes,location=yes' ,
349352 )
350353
351354 if ( ! authWindow ) {
352355 throw new Error ( 'Failed to open authentication window. Please allow popups for this site and try again.' )
353356 }
354357
355358 console . log ( '✅ [OAuthHelper] OAuth popup opened successfully' )
356- } catch ( error ) {
359+ }
360+ catch ( error ) {
357361 console . error ( '❌ [OAuthHelper] Failed to start OAuth flow:' , error )
358362 this . setState ( {
359363 isAuthenticating : false ,
@@ -374,7 +378,7 @@ export class OAuthHelper {
374378
375379 try {
376380 const tokenResponse = await this . exchangeCodeForToken ( serverUrl , code )
377-
381+
378382 this . setState ( {
379383 isAuthenticating : false ,
380384 isAuthenticated : true ,
@@ -385,7 +389,8 @@ export class OAuthHelper {
385389
386390 console . log ( '✅ [OAuthHelper] OAuth flow completed successfully' )
387391 return tokenResponse
388- } catch ( error ) {
392+ }
393+ catch ( error ) {
389394 console . error ( '❌ [OAuthHelper] Failed to complete OAuth flow:' , error )
390395 this . setState ( {
391396 isAuthenticating : false ,
@@ -421,8 +426,8 @@ export class OAuthHelper {
421426 * Generate a random state parameter for CSRF protection
422427 */
423428 private generateState ( ) : string {
424- return Math . random ( ) . toString ( 36 ) . substring ( 2 , 15 ) +
425- Math . random ( ) . toString ( 36 ) . substring ( 2 , 15 )
429+ return Math . random ( ) . toString ( 36 ) . substring ( 2 , 15 )
430+ + Math . random ( ) . toString ( 36 ) . substring ( 2 , 15 )
426431 }
427432}
428433
@@ -444,8 +449,8 @@ export function createOAuthMCPConfig(serverUrl: string, accessToken: string) {
444449 linear : {
445450 url : serverUrl ,
446451 authToken : accessToken ,
447- transport : 'sse'
448- }
449- }
452+ transport : 'sse' ,
453+ } ,
454+ } ,
450455 }
451456}
0 commit comments