@@ -3,11 +3,24 @@ package oauth
33import (
44 "context"
55 "fmt"
6+ "time"
67
78 "github.com/docker/mcp-gateway/pkg/desktop"
9+ pkgoauth "github.com/docker/mcp-gateway/pkg/oauth"
810)
911
1012func Authorize (ctx context.Context , app string , scopes string ) error {
13+ // Check if running in CE mode
14+ if pkgoauth .IsCEMode () {
15+ return authorizeCEMode (ctx , app , scopes )
16+ }
17+
18+ // Desktop mode - existing implementation
19+ return authorizeDesktopMode (ctx , app , scopes )
20+ }
21+
22+ // authorizeDesktopMode handles OAuth via Docker Desktop (existing behavior)
23+ func authorizeDesktopMode (ctx context.Context , app string , scopes string ) error {
1124 client := desktop .NewAuthClient ()
1225
1326 // Start OAuth flow - Docker Desktop handles DCR automatically if needed
@@ -24,3 +37,81 @@ func Authorize(ctx context.Context, app string, scopes string) error {
2437 fmt .Printf ("Opening your browser for authentication. If it doesn't open automatically, please visit: %s\n " , authResponse .BrowserURL )
2538 return nil
2639}
40+
41+ // authorizeCEMode handles OAuth in standalone CE mode
42+ func authorizeCEMode (ctx context.Context , serverName string , scopes string ) error {
43+ fmt .Printf ("Starting OAuth authorization for %s...\n " , serverName )
44+
45+ // Create OAuth manager with read-write credential helper
46+ credHelper := pkgoauth .NewReadWriteCredentialHelper ()
47+ manager := pkgoauth .NewManager (credHelper )
48+
49+ // Step 1: Ensure DCR client is registered
50+ fmt .Printf ("Checking DCR registration...\n " )
51+ if err := manager .EnsureDCRClient (ctx , serverName , scopes ); err != nil {
52+ return fmt .Errorf ("DCR registration failed: %w" , err )
53+ }
54+
55+ // Step 2: Create callback server
56+ callbackServer , err := pkgoauth .NewCallbackServer ()
57+ if err != nil {
58+ return fmt .Errorf ("failed to create callback server: %w" , err )
59+ }
60+
61+ // Start callback server in background
62+ go func () {
63+ if err := callbackServer .Start (); err != nil {
64+ fmt .Printf ("Callback server error: %v\n " , err )
65+ }
66+ }()
67+ defer func () {
68+ shutdownCtx , cancel := context .WithTimeout (context .Background (), 5 * time .Second )
69+ defer cancel ()
70+ if err := callbackServer .Shutdown (shutdownCtx ); err != nil {
71+ fmt .Printf ("Warning: failed to shutdown callback server: %v\n " , err )
72+ }
73+ }()
74+
75+ // Step 3: Build authorization URL with callback URL in state
76+ fmt .Printf ("Generating authorization URL...\n " )
77+
78+ scopesList := []string {}
79+ if scopes != "" {
80+ scopesList = []string {scopes }
81+ }
82+
83+ // Pass callback URL - will be embedded in state for mcp-oauth proxy routing
84+ callbackURL := callbackServer .URL ()
85+ authURL , baseState , _ , err := manager .BuildAuthorizationURL (ctx , serverName , scopesList , callbackURL )
86+ if err != nil {
87+ return fmt .Errorf ("failed to generate authorization URL: %w" , err )
88+ }
89+
90+ // Store base state for later validation
91+ _ = baseState // We'll validate using the state from callback
92+
93+ // Step 4: Display authorization URL
94+ fmt .Printf ("Please visit this URL to authorize:\n \n %s\n \n " , authURL )
95+
96+ // Step 5: Wait for callback
97+ fmt .Printf ("Waiting for authorization callback on http://localhost:%d/callback...\n " , callbackServer .Port ())
98+
99+ timeoutCtx , cancel := context .WithTimeout (ctx , 5 * time .Minute )
100+ defer cancel ()
101+
102+ code , callbackState , err := callbackServer .Wait (timeoutCtx )
103+ if err != nil {
104+ return fmt .Errorf ("failed to receive callback: %w" , err )
105+ }
106+
107+ // Step 6: Exchange code for token
108+ fmt .Printf ("Exchanging authorization code for access token...\n " )
109+ if err := manager .ExchangeCode (ctx , code , callbackState ); err != nil {
110+ return fmt .Errorf ("token exchange failed: %w" , err )
111+ }
112+
113+ fmt .Printf ("Authorization successful! Token stored securely.\n " )
114+ fmt .Printf ("You can now use: docker mcp server start %s\n " , serverName )
115+
116+ return nil
117+ }
0 commit comments