@civic/auth-mcp
Version:
Civic Auth integration for MCP servers
1 lines • 25.6 kB
Source Map (JSON)
{"version":3,"sources":["../../src/client/index.ts","../../src/constants.ts","../../src/client/CLIClient.ts","../../src/client/providers/persistence/InMemoryTokenPersistence.ts","../../src/client/providers/CivicAuthProvider.ts","../../src/client/providers/CLIAuthProvider.ts","../../src/client/providers/TokenAuthProvider.ts","../../src/client/transport/RestartableStreamableHTTPClientTransport.ts"],"sourcesContent":["// Re-export from providers\n\n// Re-export constants\nexport * from \"../constants.js\";\n// Re-export CLIClient\nexport { CLIClient } from \"./CLIClient.js\";\nexport * from \"./providers/index.js\";\n// Re-export from transport\nexport * from \"./transport/index.js\";\n","export const DEFAULT_WELLKNOWN_URL = \"https://auth.civic.com/oauth/.well-known/openid-configuration\";\n\n/**\n * Default scope for OAuth authentication\n */\nexport const DEFAULT_SCOPES = [\"openid\", \"profile\", \"email\", \"offline_access\"];\n\n/**\n * Default callback port for CLI authentication flow\n */\nexport const DEFAULT_CALLBACK_PORT = 8080;\n\n// Default mcpRoute to '/mcp' if not specified\nexport const DEFAULT_MCP_ROUTE = \"/mcp\";\n\n// This client ID is used when a client is not provided.\n// It is registered on Civic Auth as a rate-limited public \"sandbox\" account.\n// Note, this option is used only if the auth server is Civic\nexport const PUBLIC_CIVIC_CLIENT_ID = \"12220cf4-1a9a-4964-8eb7-7c6d7d049f34\";\n","import { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport type { RestartableStreamableHTTPClientTransport } from \"./transport/index.js\";\n\n/**\n * MCP Client with built-in CLI authentication support\n * Handles the OAuth flow automatically and retries connection after auth\n */\nexport class CLIClient extends Client {\n /**\n * Connect to MCP server with automatic authentication handling\n * If the first connection fails due to auth, it will wait for the OAuth flow\n * to complete and then retry the connection\n */\n async connect(transport: RestartableStreamableHTTPClientTransport): Promise<void> {\n try {\n await super.connect(transport);\n } catch (error: unknown) {\n // Check if this is an authorization error\n if (error instanceof Error) {\n // This error.message is ONLY returned if auth() in @modelcontextprotocol/sdk/client/auth.js\n // returns \"REDIRECT\", therefore we waitForAuthorizationCode() and connect again.\n if (error.message === \"Unauthorized\") {\n console.log(\"Authorization required, waiting for user to complete OAuth flow...\");\n const authProvider = transport.authProvider;\n\n // Wait for the OAuth flow to complete\n await authProvider.waitForAuthorizationCode();\n console.log(\"Authorization completed.\");\n\n // Retry the connection - the auth provider now has tokens\n return await super.connect(transport);\n }\n }\n\n // Re-throw any other errors\n throw error;\n }\n }\n}\n","import type { OAuthTokens } from \"@modelcontextprotocol/sdk/shared/auth.js\";\nimport type { TokenPersistence } from \"./TokenPersistence.js\";\n\n/**\n * In-memory token persistence strategy\n * Tokens are stored in memory and lost when the process exits\n */\nexport class InMemoryTokenPersistence implements TokenPersistence {\n private tokens: OAuthTokens | undefined;\n\n saveTokens(tokens: OAuthTokens): void {\n this.tokens = tokens;\n }\n\n loadTokens(): OAuthTokens | undefined {\n return this.tokens;\n }\n\n clearTokens(): void {\n this.tokens = undefined;\n }\n}\n","import type { OAuthClientProvider } from \"@modelcontextprotocol/sdk/client/auth.js\";\nimport type {\n OAuthClientInformation,\n OAuthClientMetadata,\n OAuthTokens,\n} from \"@modelcontextprotocol/sdk/shared/auth.js\";\nimport { InMemoryTokenPersistence, type TokenPersistence } from \"./persistence/index.js\";\n\nexport interface CivicAuthProviderOptions {\n /**\n * Client secret for OAuth flows that don't support PKCE.\n * Optional - only needed for auth servers that require client authentication.\n */\n clientSecret?: string;\n\n /**\n * Token persistence strategy to use for storing/retrieving tokens.\n * Defaults to in-memory persistence if not provided.\n */\n tokenPersistence?: TokenPersistence;\n}\n\n/**\n * Abstract base class for Civic auth providers\n */\nexport abstract class CivicAuthProvider implements OAuthClientProvider {\n protected clientSecret?: string;\n protected tokenPersistence: TokenPersistence;\n\n constructor(options: CivicAuthProviderOptions) {\n this.clientSecret = options.clientSecret;\n this.tokenPersistence = options.tokenPersistence ?? new InMemoryTokenPersistence();\n }\n\n abstract clientInformation(): OAuthClientInformation | Promise<OAuthClientInformation | undefined> | undefined;\n\n abstract get clientMetadata(): OAuthClientMetadata;\n\n abstract codeVerifier(): string | Promise<string>;\n\n abstract get redirectUrl(): string | URL;\n\n abstract saveCodeVerifier(codeVerifier: string): void;\n\n saveTokens(tokens: OAuthTokens): void | Promise<void> {\n return this.tokenPersistence.saveTokens(tokens);\n }\n\n /**\n * Returns the stored tokens\n */\n tokens(): OAuthTokens | undefined | Promise<OAuthTokens | undefined> {\n return this.tokenPersistence.loadTokens();\n }\n\n /**\n * Clears the stored tokens\n */\n clearTokens(): void | Promise<void> {\n return this.tokenPersistence.clearTokens();\n }\n\n abstract redirectToAuthorization(authorizationUrl: URL): void | Promise<void>;\n}\n","import { execFile } from \"node:child_process\";\nimport crypto from \"node:crypto\";\nimport http from \"node:http\";\nimport type { AddressInfo } from \"node:net\";\nimport url from \"node:url\";\nimport { promisify } from \"node:util\";\nimport type { SSEClientTransport } from \"@modelcontextprotocol/sdk/client/sse.js\";\nimport type { StreamableHTTPClientTransport } from \"@modelcontextprotocol/sdk/client/streamableHttp.js\";\nimport type { OAuthClientInformation, OAuthClientMetadata } from \"@modelcontextprotocol/sdk/shared/auth.js\";\nimport escapeHtml from \"escape-html\";\nimport { DEFAULT_CALLBACK_PORT, DEFAULT_SCOPES } from \"../../constants.js\";\nimport { CivicAuthProvider, type CivicAuthProviderOptions } from \"./CivicAuthProvider.js\";\n\nexport interface CLIAuthProviderOptions extends CivicAuthProviderOptions {\n clientId: string;\n scope?: string;\n callbackPort?: number;\n enablePortFallback?: boolean;\n successHtml?: string;\n errorHtml?: string;\n authTimeoutMs?: number;\n}\n\n/**\n * CLI Auth Provider for MCP\n * Opens authorization URL in default browser and stores tokens in memory\n */\nexport class CLIAuthProvider extends CivicAuthProvider {\n private storedCodeVerifier: string | undefined;\n private clientId: string;\n private scope: string;\n private callbackPort: number;\n private enablePortFallback: boolean;\n private authTimeoutMs: number;\n private successHtml: string;\n private errorHtml: string;\n private callbackServer: http.Server | undefined;\n private authorizationCodePromise: Promise<string> | undefined;\n private authorizationCodeResolve: ((code: string) => void) | undefined;\n private authorizationCodeReject: ((error: Error) => void) | undefined;\n private transport: SSEClientTransport | StreamableHTTPClientTransport | undefined;\n private serverTimeout: NodeJS.Timeout | undefined;\n\n constructor(options: CLIAuthProviderOptions) {\n super(options);\n this.clientId = options.clientId;\n this.scope = options.scope ?? DEFAULT_SCOPES.join(\" \");\n this.callbackPort = options.callbackPort ?? DEFAULT_CALLBACK_PORT;\n this.enablePortFallback = options.enablePortFallback ?? true;\n this.authTimeoutMs = options.authTimeoutMs ?? 5 * 60 * 1000; // 5 minutes default\n this.successHtml =\n options.successHtml ??\n '<html lang=\"en\"><body><h1>Authorization Successful</h1><p>You can now close this window.</p></body></html>';\n this.errorHtml =\n options.errorHtml ?? '<html lang=\"en\"><body><h1>Authorization Failed</h1><p>{{error}}</p></body></html>';\n }\n\n clientInformation(): OAuthClientInformation | Promise<OAuthClientInformation | undefined> | undefined {\n const info: OAuthClientInformation = {\n client_id: this.clientId,\n };\n\n // Include client_secret if provided (for non-PKCE auth servers)\n if (this.clientSecret) {\n info.client_secret = this.clientSecret;\n }\n\n return info;\n }\n\n get clientMetadata(): OAuthClientMetadata {\n return {\n redirect_uris: [this.getCallbackUrl(this.callbackPort)],\n client_name: this.clientId,\n scope: this.scope,\n };\n }\n\n codeVerifier(): string | Promise<string> {\n // Generate and return the stored code verifier\n if (!this.storedCodeVerifier) {\n this.storedCodeVerifier = crypto.randomBytes(32).toString(\"base64url\");\n }\n return this.storedCodeVerifier;\n }\n\n async redirectToAuthorization(authorizationUrl: URL): Promise<void> {\n // Check if authorization flow is already in progress\n if (this.callbackServer) {\n throw new Error(\"Authorization flow already in progress. Please wait for it to complete.\");\n }\n\n console.log(`Opening authorization URL in browser: ${authorizationUrl.href}`);\n\n // Start the callback server before opening the browser\n const actualPort = await this.startCallbackServer();\n\n // Modify the auth URL to use updated redirect URI if port changed\n let urlToOpen = authorizationUrl.href;\n if (actualPort) {\n // update the callback URL\n this.callbackPort = actualPort;\n const authUrlObj = new URL(authorizationUrl);\n authUrlObj.searchParams.set(\"redirect_uri\", this.getCallbackUrl(actualPort));\n urlToOpen = authUrlObj.href;\n }\n\n // Open URL in default browser\n await this.openInBrowser(urlToOpen);\n\n console.log(\"Please complete the authorization in your browser.\");\n }\n\n /**\n * Registers the transport with the auth provider so that we can call finishAuth when the code is received.\n * @param transport\n */\n registerTransport(transport: SSEClientTransport | StreamableHTTPClientTransport): void {\n this.transport = transport;\n }\n\n get redirectUrl(): string | URL {\n // Return the redirect URL for the OAuth flow\n return new URL(this.getCallbackUrl(this.callbackPort));\n }\n\n saveCodeVerifier(codeVerifier: string): void {\n this.storedCodeVerifier = codeVerifier;\n }\n\n private getCallbackUrl(port: number): string {\n return `http://localhost:${port}/callback`;\n }\n\n /**\n * Listen on Port Promise\n * @param server\n * @param port\n * @private port that is being listened on.\n */\n private listenOnPort(server: http.Server, port: number): Promise<number> {\n return new Promise((resolve, reject) => {\n const onError = (err: NodeJS.ErrnoException) => {\n server.off(\"listening\", onListening);\n reject(err);\n };\n\n const onListening = () => {\n server.off(\"error\", onError);\n const address = server.address() as AddressInfo;\n resolve(address.port);\n };\n\n server.once(\"error\", onError);\n server.once(\"listening\", onListening);\n server.listen(port, \"localhost\");\n });\n }\n\n /**\n * Starts a local HTTP server to handle the OAuth callback with port fallback support\n * @returns The actual port number if different from the configured port, undefined otherwise\n */\n private async startCallbackServer(): Promise<number | undefined> {\n // Create a promise for the authorization code\n this.authorizationCodePromise = new Promise((resolveCode, rejectCode) => {\n this.authorizationCodeResolve = resolveCode;\n this.authorizationCodeReject = rejectCode;\n });\n\n // Create the callback server\n this.callbackServer = http.createServer((req, res) => {\n try {\n if (!req.url) {\n res.writeHead(400);\n res.end(\"Bad Request\");\n return;\n }\n\n const parsedUrl = url.parse(req.url, true);\n\n if (parsedUrl.pathname === \"/callback\") {\n const code = parsedUrl.query.code as string;\n const error = parsedUrl.query.error as string;\n\n if (error) {\n res.writeHead(200, { \"Content-Type\": \"text/html\" });\n res.end(this.errorHtml.replace(\"{{error}}\", escapeHtml(error)));\n this.authorizationCodeReject?.(new Error(`OAuth error: ${error}`));\n } else if (code) {\n res.writeHead(200, { \"Content-Type\": \"text/html\" });\n res.end(this.successHtml);\n\n // Call finishAuth on the transport if set. This triggers the token exchange\n if (this.transport) {\n this.transport\n .finishAuth(code)\n .then(() => this.authorizationCodeResolve?.(code))\n .catch((error) => {\n console.error(\"Error in finishAuth:\", error);\n this.authorizationCodeReject?.(error);\n });\n } else {\n this.authorizationCodeReject?.(new Error(\"No transport registered\"));\n }\n } else {\n res.writeHead(400);\n res.end(\"Missing authorization code\");\n }\n } else {\n res.writeHead(404);\n res.end(\"Not Found\");\n }\n } finally {\n // Always stop the server after ANY request\n this.cleanup();\n }\n });\n\n let actualPort: number;\n try {\n actualPort = await this.listenOnPort(this.callbackServer, this.callbackPort);\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code === \"EADDRINUSE\" && this.enablePortFallback) {\n console.warn(`Port ${this.callbackPort} in use. Trying a random port...`);\n actualPort = await this.listenOnPort(this.callbackServer, 0); // 0 = random available port\n } else {\n throw err;\n }\n }\n\n // Set up timeout to automatically close server\n this.serverTimeout = setTimeout(() => {\n console.warn(`OAuth callback server timeout reached after ${this.authTimeoutMs / 1000}s. Closing server.`);\n this.cleanup();\n }, this.authTimeoutMs);\n\n return actualPort !== this.callbackPort ? actualPort : undefined;\n }\n\n /**\n * Resets the instance to its post-initialization state\n * Stops any active server, clears timeouts\n */\n private cleanup(): void {\n // Close the callback server\n if (this.callbackServer) {\n this.callbackServer.close();\n this.callbackServer = undefined;\n }\n\n // Clear the timeout\n if (this.serverTimeout) {\n clearTimeout(this.serverTimeout);\n this.serverTimeout = undefined;\n }\n }\n\n /**\n * Waits for the authorization code from the callback\n */\n async waitForAuthorizationCode(): Promise<string> {\n if (!this.authorizationCodePromise) {\n throw new Error(\"Authorization flow not started\");\n }\n return this.authorizationCodePromise;\n }\n\n private async openInBrowser(url: string): Promise<void> {\n const execFileAsync = promisify(execFile);\n\n try {\n switch (process.platform) {\n case \"darwin\":\n await execFileAsync(\"open\", [url]);\n break;\n case \"win32\":\n await execFileAsync(\"cmd\", [\"/c\", \"start\", url]);\n break;\n default:\n // Linux/Unix\n await execFileAsync(\"xdg-open\", [url]);\n }\n } catch (error) {\n console.error(\"Failed to open browser:\", error);\n console.log(\"Please open this URL manually:\", url);\n }\n }\n}\n","import type {\n OAuthClientInformation,\n OAuthClientMetadata,\n OAuthTokens,\n} from \"@modelcontextprotocol/sdk/shared/auth.js\";\nimport { CivicAuthProvider, type CivicAuthProviderOptions } from \"./CivicAuthProvider.js\";\n\n/**\n * Configuration options for TokenAuthProvider\n */\nexport interface TokenAuthProviderOptions extends CivicAuthProviderOptions {\n /**\n * OAuth tokens to use for authentication\n */\n tokens: OAuthTokens;\n}\n\n/**\n * Authentication provider for pre-obtained tokens.\n * Use this when you already have access tokens from an external OAuth flow\n * and want to use them directly with the MCP client.\n */\nexport class TokenAuthProvider extends CivicAuthProvider {\n /**\n * Create a new TokenAuthProvider\n * @param tokenOrOptions - Either a token string or full options object\n */\n constructor(tokenOrOptions: string | TokenAuthProviderOptions) {\n // Handle simple string constructor for convenience\n const options: TokenAuthProviderOptions =\n typeof tokenOrOptions === \"string\"\n ? { tokens: { access_token: tokenOrOptions, token_type: \"Bearer\" } }\n : tokenOrOptions;\n\n super(options);\n // Save the initial tokens using the persistence strategy\n this.tokenPersistence.saveTokens(options.tokens);\n }\n\n get redirectUrl(): string | URL {\n // No redirect URL needed for token-based auth\n return \"\";\n }\n\n get clientMetadata(): OAuthClientMetadata {\n return {\n redirect_uris: [],\n };\n }\n\n clientInformation(): OAuthClientInformation | undefined {\n return {\n client_id: \"token-client\",\n };\n }\n\n redirectToAuthorization(_authorizationUrl: URL): void {\n // No-op - tokens are already available\n }\n\n saveCodeVerifier(_codeVerifier: string): void {\n // No-op for token-based auth\n }\n\n codeVerifier(): string {\n // Return empty string as no code verifier is needed for token-based auth\n return \"\";\n }\n}\n","import {\n StreamableHTTPClientTransport,\n type StreamableHTTPClientTransportOptions,\n} from \"@modelcontextprotocol/sdk/client/streamableHttp.js\";\nimport type { CLIAuthProvider } from \"../providers/index.js\";\n\ntype RestartableStreamableHTTPClientTransportOpts = StreamableHTTPClientTransportOptions & {\n authProvider: CLIAuthProvider;\n};\n\n/**\n * A transport that extends StreamableHTTPClientTransport to support restarting\n * the connection after authentication. This is particularly useful when\n * implementing authentication flows that require redirection and reconnection.\n */\nexport class RestartableStreamableHTTPClientTransport extends StreamableHTTPClientTransport {\n private _cliAuthProvider: CLIAuthProvider;\n\n constructor(url: URL, opts: RestartableStreamableHTTPClientTransportOpts) {\n super(url, opts);\n this._cliAuthProvider = opts.authProvider; // Assign the authProvider from options so that we have access\n\n // Register this transport with the auth provider\n this._cliAuthProvider.registerTransport(this);\n }\n\n get authProvider(): CLIAuthProvider {\n return this._cliAuthProvider;\n }\n\n /**\n * Extends the start method to properly handle reconnection.\n * If the transport has already been started, it will disconnect first,\n * then start again to establish a fresh connection.\n */\n override async start() {\n try {\n await super.start();\n } catch (_error) {\n // ignore restart errors here\n }\n }\n\n override async close() {\n // do nothing for now\n }\n}\n"],"mappings":"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","names":["crypto","http","url","escapeHtml","error","url"]}