File size: 3,634 Bytes
c211e0e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import { useEffect, useState } from "react";
import { exchangeCodeForToken } from "../services/oauth";
import { secureStorage } from "../utils/storage";
import type { MCPServerConfig } from "../types/mcp";
import { STORAGE_KEYS, DEFAULTS } from "../config/constants";

interface OAuthTokens {
  access_token: string;
  refresh_token?: string;
  expires_in?: number;
  token_type?: string;
  [key: string]: string | number | undefined;
}

interface OAuthCallbackProps {
  serverUrl: string;
  onSuccess?: (tokens: OAuthTokens) => void;
  onError?: (error: Error) => void;
}

const OAuthCallback: React.FC<OAuthCallbackProps> = ({
  serverUrl,
  onSuccess,
  onError,
}) => {
  const [status, setStatus] = useState<string>("Authorizing...");

  useEffect(() => {
    const params = new URLSearchParams(window.location.search);
    const code = params.get("code");
    // Always persist MCP server URL for robustness
    localStorage.setItem(STORAGE_KEYS.OAUTH_MCP_SERVER_URL, serverUrl);
    if (code) {
      exchangeCodeForToken({
        serverUrl,
        code,
        redirectUri: window.location.origin + DEFAULTS.OAUTH_REDIRECT_PATH,
      })
        .then(async (tokens) => {
          await secureStorage.setItem(STORAGE_KEYS.OAUTH_ACCESS_TOKEN, tokens.access_token);
          // Add MCP server to MCPClientService for UI
          const mcpServerUrl = localStorage.getItem(STORAGE_KEYS.OAUTH_MCP_SERVER_URL);
          if (mcpServerUrl) {
            // Use persisted name and transport from initial add
            const serverName =
              localStorage.getItem(STORAGE_KEYS.MCP_SERVER_NAME) || mcpServerUrl;
            const serverTransport = 
              (localStorage.getItem(STORAGE_KEYS.MCP_SERVER_TRANSPORT) as MCPServerConfig['transport']) || DEFAULTS.MCP_TRANSPORT;
            // Build config and add to mcp-servers
            const serverConfig = {
              id: `server_${Date.now()}`,
              name: serverName,
              url: mcpServerUrl,
              enabled: true,
              transport: serverTransport,
              auth: {
                type: "bearer" as const,
                token: tokens.access_token,
              },
            };
            // Load existing servers
            let servers: MCPServerConfig[] = [];
            try {
              const stored = localStorage.getItem(STORAGE_KEYS.MCP_SERVERS);
              if (stored) servers = JSON.parse(stored);
            } catch {}
            // Add or update
            const exists = servers.some((s: MCPServerConfig) => s.url === mcpServerUrl);
            if (!exists) {
              servers.push(serverConfig);
              localStorage.setItem(STORAGE_KEYS.MCP_SERVERS, JSON.stringify(servers));
            }
            // Clear temp values from localStorage for clean slate
            localStorage.removeItem(STORAGE_KEYS.MCP_SERVER_NAME);
            localStorage.removeItem(STORAGE_KEYS.MCP_SERVER_TRANSPORT);
            localStorage.removeItem(STORAGE_KEYS.OAUTH_MCP_SERVER_URL);
          }
          setStatus("Authorization successful! Redirecting...");
          if (onSuccess) onSuccess(tokens);
          // Redirect to main app page after short delay
          setTimeout(() => {
            window.location.replace("/");
          }, 1000);
        })
        .catch((err) => {
          setStatus("OAuth token exchange failed: " + err.message);
          if (onError) onError(err);
        });
    } else {
      setStatus("Missing authorization code in callback URL.");
    }
  }, [serverUrl, onSuccess, onError]);

  return <div>{status}</div>;
};

export default OAuthCallback;