UNPKG

@civic/auth-mcp

Version:

Civic Auth integration for MCP servers

157 lines (152 loc) 6.19 kB
import { Request, RequestHandler } from 'express'; import { IncomingMessage } from 'node:http'; import { AuthInfo } from '@modelcontextprotocol/sdk/server/auth/types.js'; import { JWTPayload } from 'jose'; export { CLIAuthProvider, CLIAuthProviderOptions, CLIClient, CivicAuthProvider, CivicAuthProviderOptions, DEFAULT_CALLBACK_PORT, DEFAULT_MCP_ROUTE, DEFAULT_SCOPES, DEFAULT_WELLKNOWN_URL, InMemoryTokenPersistence, PUBLIC_CIVIC_CLIENT_ID, RestartableStreamableHTTPClientTransport, TokenAuthProvider, TokenAuthProviderOptions, TokenPersistence } from './client/index.js'; import '@modelcontextprotocol/sdk/client/auth.js'; import '@modelcontextprotocol/sdk/shared/auth.js'; import '@modelcontextprotocol/sdk/client/sse.js'; import '@modelcontextprotocol/sdk/client/streamableHttp.js'; import '@modelcontextprotocol/sdk/client/index.js'; interface CivicAuthOptions<TAuthInfo extends ExtendedAuthInfo, TRequest extends IncomingMessage = IncomingMessage> { /** * The URL to the auth server's well-known OIDC configuration * Defaults to https://auth.civic.com/oauth/.well-known/openid-configuration */ wellKnownUrl?: string; /** * OAuth scopes to support * Defaults to ['openid', 'profile', 'email'] */ scopesSupported?: string[]; /** * The issuer URL for the resource server * Defaults to the server's base URL */ issuerUrl?: string | URL; /** * Base path for auth endpoints * Defaults to '/' */ basePath?: string; /** * The MCP route to protect with authentication * Defaults to '/mcp' */ mcpRoute?: string; /** * Optional callback to enrich the auth info with custom data * Called after successful token verification * @param authInfo The verified auth info from the token. Null if no token was provided. * @param request Optional request object that may contain headers or other data * @returns Enriched auth info with custom data */ onLogin?: (authInfo: ExtendedAuthInfo | null, request?: TRequest) => Promise<TAuthInfo | null>; /** * Optional OAuth client ID / Tenant ID. * When set, the access token must include *either* a "client_id" field or "tid" field that matches it. */ clientId?: string; /** * Whether to allow dynamic client registration by adding client ID as subdomain. * When true, the client ID will be added as a subdomain to the auth server URL. * When false (default), the auth server URL will be used as-is without subdomain prefixing. * Defaults to false. */ allowDynamicClientRegistration?: boolean; } interface OIDCWellKnownConfiguration { issuer: string; authorization_endpoint: string; token_endpoint: string; jwks_uri: string; scopes_supported?: string[]; response_types_supported?: string[]; grant_types_supported?: string[]; token_endpoint_auth_methods_supported?: string[]; introspection_endpoint?: string; revocation_endpoint?: string; registration_endpoint?: string; } interface ExtendedAuthInfo extends AuthInfo { extra?: { sub?: string; email?: string; name?: string; picture?: string; }; } /** * Custom error class for all authentication errors */ declare class AuthenticationError extends Error { } /** * Custom error class for JWT verification failures */ declare class JWTVerificationError extends AuthenticationError { originalError?: Error | undefined; constructor(message: string, originalError?: Error | undefined); } type AccessTokenPayload = JWTPayload & { client_id: string | undefined; tid: string | undefined; }; /** * Core authentication functionality that can be used with any framework */ declare class McpServerAuth<TAuthInfo extends ExtendedAuthInfo, TRequest extends IncomingMessage = IncomingMessage> { private oidcConfig; private jwks; private options; private constructor(); /** * Initialize the auth core by fetching OIDC configuration */ static init<TAuthInfo extends ExtendedAuthInfo, TRequest extends IncomingMessage = IncomingMessage>(options?: CivicAuthOptions<TAuthInfo, TRequest>): Promise<McpServerAuth<TAuthInfo, TRequest>>; /** * Get the OAuth Protected Resource metadata * @param issuerUrl The issuer URL of the resource server (e.g., https://my-server.com) */ getProtectedResourceMetadata(issuerUrl: string): { resource: string; authorization_servers: string[]; scopes_supported: string[]; bearer_methods_supported: string[]; }; /** * Create auth info from a token (or null) and request * @param token The JWT token (can be null) * @param payload The JWT payload if token was already verified * @param request Optional request object to pass to onLogin callback * @returns ExtendedAuthInfo if successful, null otherwise */ private createAuthInfo; /** * Extract and verify bearer token from authorization header * @param authHeader The Authorization header value * @returns Object with token and payload if valid, throws if invalid token, returns null values if no token */ private extractBearerToken; /** * Handle a request by extracting and verifying the bearer token * @param request The request object * @returns ExtendedAuthInfo if valid * @throws Error if authentication fails */ handleRequest(request: TRequest): Promise<TAuthInfo>; } /** * Express middleware that configures an MCP server to use Civic Auth * as its authorization server. * * This middleware: * 1. Exposes /.well-known/oauth-protected-resource metadata * 2. Validates bearer tokens using Civic's JWKS * 3. Attaches user info to the request * * @param options Configuration options * @returns Express middleware */ declare function auth<TAuthInfo extends ExtendedAuthInfo>(options?: CivicAuthOptions<TAuthInfo, Request>): Promise<RequestHandler>; export { type AccessTokenPayload, AuthenticationError, type CivicAuthOptions, type ExtendedAuthInfo, JWTVerificationError, McpServerAuth, type OIDCWellKnownConfiguration, auth };