@@ -45,8 +45,11 @@ export interface OAuthCallbacks {
4545}
4646
4747const CALLBACK_PORT = 8914 ;
48- const CALLBACK_PATH = '/oauth/callback' ;
48+ const CALLBACK_PATH = '/callback' ;
49+ // Client names for OAuth registration
50+ // Some MCP servers (like Figma) have an allowlist - try '1code' first, fall back to 'Codex'
4951const CLIENT_NAME = '1code' ;
52+ const FALLBACK_CLIENT_NAME = 'Codex' ;
5053
5154/**
5255 * Generate a styled OAuth callback page with terminal emulator aesthetic
@@ -537,7 +540,7 @@ export class CraftOAuth {
537540 }
538541
539542 // Register OAuth client dynamically
540- private async registerClient ( registrationEndpoint : string ) : Promise < {
543+ private async registerClient ( registrationEndpoint : string , clientName : string ) : Promise < {
541544 client_id : string ;
542545 client_secret ?: string ;
543546 } > {
@@ -547,7 +550,7 @@ export class CraftOAuth {
547550 method : 'POST' ,
548551 headers : { 'Content-Type' : 'application/json' } ,
549552 body : JSON . stringify ( {
550- client_name : CLIENT_NAME ,
553+ client_name : clientName ,
551554 redirect_uris : [ redirectUri ] ,
552555 grant_types : [ 'authorization_code' , 'refresh_token' ] ,
553556 response_types : [ 'code' ] ,
@@ -572,7 +575,8 @@ export class CraftOAuth {
572575 code : string ,
573576 codeVerifier : string ,
574577 clientId : string ,
575- redirectUri ?: string
578+ redirectUri ?: string ,
579+ clientSecret ?: string
576580 ) : Promise < OAuthTokens > {
577581 const uri = redirectUri || this . config . redirectUri || `http://localhost:${ CALLBACK_PORT } ${ CALLBACK_PATH } ` ;
578582
@@ -584,6 +588,11 @@ export class CraftOAuth {
584588 code_verifier : codeVerifier ,
585589 } ) ;
586590
591+ // Add client_secret if provided (some servers require it)
592+ if ( clientSecret ) {
593+ params . set ( 'client_secret' , clientSecret ) ;
594+ }
595+
587596 const response = await fetch ( tokenEndpoint , {
588597 method : 'POST' ,
589598 headers : { 'Content-Type' : 'application/x-www-form-urlencoded' } ,
@@ -686,15 +695,24 @@ export class CraftOAuth {
686695 // Register client if endpoint available
687696 let clientId : string ;
688697 if ( metadata . registration_endpoint ) {
689- this . callbacks . onStatus ( `Registering client at ${ metadata . registration_endpoint } ...` ) ;
698+ // Try primary client name first, fall back to alternative if rejected
699+ this . callbacks . onStatus ( `Registering client as '${ CLIENT_NAME } '...` ) ;
690700 try {
691- const client = await this . registerClient ( metadata . registration_endpoint ) ;
701+ const client = await this . registerClient ( metadata . registration_endpoint , CLIENT_NAME ) ;
692702 clientId = client . client_id ;
693703 this . callbacks . onStatus ( `Registered as client: ${ clientId } ` ) ;
694704 } catch ( error ) {
695- const msg = error instanceof Error ? error . message : 'Unknown error' ;
696- this . callbacks . onStatus ( `Client registration failed: ${ msg } ` ) ;
697- throw error ;
705+ // Try fallback client name (some servers have allowlists)
706+ this . callbacks . onStatus ( `Registration as '${ CLIENT_NAME } ' failed, trying '${ FALLBACK_CLIENT_NAME } '...` ) ;
707+ try {
708+ const client = await this . registerClient ( metadata . registration_endpoint , FALLBACK_CLIENT_NAME ) ;
709+ clientId = client . client_id ;
710+ this . callbacks . onStatus ( `Registered as client: ${ clientId } ` ) ;
711+ } catch ( fallbackError ) {
712+ const msg = fallbackError instanceof Error ? fallbackError . message : 'Unknown error' ;
713+ this . callbacks . onStatus ( `Client registration failed: ${ msg } ` ) ;
714+ throw fallbackError ;
715+ }
698716 }
699717 } else {
700718 // Use a default client ID for public clients
@@ -754,16 +772,32 @@ export class CraftOAuth {
754772 codeVerifier : string ;
755773 tokenEndpoint : string ;
756774 clientId : string ;
775+ clientSecret ?: string ;
757776 } > {
758777 this . callbacks . onStatus ( 'Fetching OAuth server configuration...' ) ;
759778 const metadata = preloadedMetadata || await this . getServerMetadata ( ) ;
760779
761780 // Register client if endpoint available
762781 let clientId : string ;
782+ let clientSecret : string | undefined ;
763783 if ( metadata . registration_endpoint ) {
764- const client = await this . registerClient ( metadata . registration_endpoint ) ;
765- clientId = client . client_id ;
784+ // Try primary client name first, fall back to alternative if rejected
785+ this . callbacks . onStatus ( `Registering client as '${ CLIENT_NAME } '...` ) ;
786+ try {
787+ const client = await this . registerClient ( metadata . registration_endpoint , CLIENT_NAME ) ;
788+ clientId = client . client_id ;
789+ clientSecret = client . client_secret ;
790+ this . callbacks . onStatus ( `Registered as client: ${ clientId } ` ) ;
791+ } catch ( error ) {
792+ // Try fallback client name (some servers have allowlists)
793+ this . callbacks . onStatus ( `Registration as '${ CLIENT_NAME } ' failed, trying '${ FALLBACK_CLIENT_NAME } '...` ) ;
794+ const client = await this . registerClient ( metadata . registration_endpoint , FALLBACK_CLIENT_NAME ) ;
795+ clientId = client . client_id ;
796+ clientSecret = client . client_secret ;
797+ this . callbacks . onStatus ( `Registered as client: ${ clientId } ` ) ;
798+ }
766799 } else {
800+ // No registration endpoint - use default client ID
767801 clientId = '1code' ;
768802 }
769803
@@ -785,6 +819,7 @@ export class CraftOAuth {
785819 codeVerifier : pkce . verifier ,
786820 tokenEndpoint : metadata . token_endpoint ,
787821 clientId,
822+ clientSecret,
788823 } ;
789824 }
790825
@@ -795,10 +830,11 @@ export class CraftOAuth {
795830 code : string ,
796831 codeVerifier : string ,
797832 tokenEndpoint : string ,
798- clientId : string
833+ clientId : string ,
834+ clientSecret ?: string
799835 ) : Promise < OAuthTokens > {
800836 const redirectUri = this . config . redirectUri || `http://localhost:${ CALLBACK_PORT } ${ CALLBACK_PATH } ` ;
801- return this . exchangeCodeForTokens ( tokenEndpoint , code , codeVerifier , clientId , redirectUri ) ;
837+ return this . exchangeCodeForTokens ( tokenEndpoint , code , codeVerifier , clientId , redirectUri , clientSecret ) ;
802838 }
803839
804840 // Start local HTTP server to receive OAuth callback
0 commit comments