fastmcp 3.23.1 → 3.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/auth/OAuthProxy.ts","../../src/auth/utils/claimsExtractor.ts","../../src/auth/utils/consent.ts","../../src/auth/utils/jwtIssuer.ts","../../src/auth/utils/pkce.ts","../../src/auth/utils/tokenStore.ts","../../src/auth/providers/AzureProvider.ts","../../src/auth/providers/GitHubProvider.ts","../../src/auth/providers/GoogleProvider.ts","../../src/auth/utils/diskStore.ts","../../src/auth/utils/jwks.ts"],"sourcesContent":["/**\n * OAuth 2.1 Proxy Implementation\n * Provides DCR-compatible interface for non-DCR OAuth providers\n */\n\nimport { randomBytes } from \"crypto\";\n\nimport type {\n AuthorizationParams,\n ClientCode,\n DCRRequest,\n DCRResponse,\n OAuthError,\n OAuthProxyConfig,\n OAuthTransaction,\n ProxyDCRClient,\n RefreshRequest,\n TokenRequest,\n TokenResponse,\n TokenStorage,\n UpstreamTokenSet,\n} from \"./types.js\";\n\nimport { ClaimsExtractor } from \"./utils/claimsExtractor.js\";\nimport { ConsentManager } from \"./utils/consent.js\";\nimport { JWTIssuer } from \"./utils/jwtIssuer.js\";\nimport { PKCEUtils } from \"./utils/pkce.js\";\nimport {\n EncryptedTokenStorage,\n MemoryTokenStorage,\n} from \"./utils/tokenStore.js\";\n\n/**\n * OAuth 2.1 Proxy\n * Acts as transparent intermediary between MCP clients and upstream OAuth providers\n */\nexport class OAuthProxy {\n private claimsExtractor: ClaimsExtractor | null = null;\n private cleanupInterval: NodeJS.Timeout | null = null;\n private clientCodes: Map<string, ClientCode> = new Map();\n private config: OAuthProxyConfig;\n private consentManager: ConsentManager;\n private jwtIssuer?: JWTIssuer;\n private registeredClients: Map<string, ProxyDCRClient> = new Map();\n private tokenStorage: TokenStorage;\n private transactions: Map<string, OAuthTransaction> = new Map();\n\n constructor(config: OAuthProxyConfig) {\n this.config = {\n allowedRedirectUriPatterns: [\"https://*\", \"http://localhost:*\"],\n authorizationCodeTtl: 300, // 5 minutes\n consentRequired: true,\n enableTokenSwap: true, // Enabled by default for security\n redirectPath: \"/oauth/callback\",\n transactionTtl: 600, // 10 minutes\n ...config,\n };\n\n // Set up token storage with encryption by default (matches Python's secure defaults)\n let storage = config.tokenStorage || new MemoryTokenStorage();\n\n // Wrap storage with encryption if not already encrypted\n // Check if it's already an EncryptedTokenStorage instance\n const isAlreadyEncrypted =\n storage.constructor.name === \"EncryptedTokenStorage\";\n\n if (!isAlreadyEncrypted && config.encryptionKey !== false) {\n // Auto-generate encryption key if not provided\n const encryptionKey =\n typeof config.encryptionKey === \"string\"\n ? config.encryptionKey\n : this.generateSigningKey();\n\n storage = new EncryptedTokenStorage(storage, encryptionKey);\n }\n\n this.tokenStorage = storage;\n this.consentManager = new ConsentManager(\n config.consentSigningKey || this.generateSigningKey(),\n );\n\n // Initialize JWT issuer if token swap is enabled\n if (this.config.enableTokenSwap) {\n // Auto-generate signing key if not provided\n const signingKey = this.config.jwtSigningKey || this.generateSigningKey();\n\n this.jwtIssuer = new JWTIssuer({\n audience: this.config.baseUrl,\n issuer: this.config.baseUrl,\n signingKey: signingKey,\n });\n }\n\n // Initialize claims extractor (enabled by default)\n const claimsConfig =\n config.customClaimsPassthrough !== undefined\n ? config.customClaimsPassthrough\n : true; // Default: enabled\n\n if (claimsConfig !== false) {\n this.claimsExtractor = new ClaimsExtractor(claimsConfig);\n }\n\n // Start periodic cleanup\n this.startCleanup();\n }\n\n /**\n * OAuth authorization endpoint\n */\n async authorize(params: AuthorizationParams): Promise<Response> {\n // Validate parameters\n if (!params.client_id || !params.redirect_uri || !params.response_type) {\n throw new OAuthProxyError(\n \"invalid_request\",\n \"Missing required parameters\",\n );\n }\n\n if (params.response_type !== \"code\") {\n throw new OAuthProxyError(\n \"unsupported_response_type\",\n \"Only 'code' response type is supported\",\n );\n }\n\n // Validate PKCE if provided\n if (params.code_challenge && !params.code_challenge_method) {\n throw new OAuthProxyError(\n \"invalid_request\",\n \"code_challenge_method required when code_challenge is present\",\n );\n }\n\n // Create transaction\n const transaction = await this.createTransaction(params);\n\n // If consent required, show consent screen\n if (this.config.consentRequired && !transaction.consentGiven) {\n return this.consentManager.createConsentResponse(\n transaction,\n this.getProviderName(),\n );\n }\n\n // Redirect to upstream provider\n return this.redirectToUpstream(transaction);\n }\n\n /**\n * Stop cleanup interval and destroy resources\n */\n destroy(): void {\n if (this.cleanupInterval) {\n clearInterval(this.cleanupInterval);\n this.cleanupInterval = null;\n }\n\n this.transactions.clear();\n this.clientCodes.clear();\n this.registeredClients.clear();\n }\n\n /**\n * Token endpoint - exchange authorization code for tokens\n */\n async exchangeAuthorizationCode(\n request: TokenRequest,\n ): Promise<TokenResponse> {\n if (request.grant_type !== \"authorization_code\") {\n throw new OAuthProxyError(\n \"unsupported_grant_type\",\n \"Only authorization_code grant type is supported\",\n );\n }\n\n const clientCode = this.clientCodes.get(request.code);\n if (!clientCode) {\n throw new OAuthProxyError(\n \"invalid_grant\",\n \"Invalid or expired authorization code\",\n );\n }\n\n // Validate client\n if (clientCode.clientId !== request.client_id) {\n throw new OAuthProxyError(\"invalid_client\", \"Client ID mismatch\");\n }\n\n // Validate PKCE if used\n if (clientCode.codeChallenge) {\n if (!request.code_verifier) {\n throw new OAuthProxyError(\n \"invalid_request\",\n \"code_verifier required for PKCE\",\n );\n }\n\n const valid = PKCEUtils.validateChallenge(\n request.code_verifier,\n clientCode.codeChallenge,\n clientCode.codeChallengeMethod,\n );\n\n if (!valid) {\n throw new OAuthProxyError(\"invalid_grant\", \"Invalid PKCE verifier\");\n }\n }\n\n // Check if code was already used\n if (clientCode.used) {\n throw new OAuthProxyError(\n \"invalid_grant\",\n \"Authorization code already used\",\n );\n }\n\n // Mark code as used\n clientCode.used = true;\n this.clientCodes.set(request.code, clientCode);\n\n // Return tokens based on token swap setting\n if (this.config.enableTokenSwap && this.jwtIssuer) {\n // Token swap pattern: issue short-lived JWTs and store upstream tokens\n return await this.issueSwappedTokens(\n clientCode.clientId,\n clientCode.upstreamTokens,\n );\n } else {\n // Pass-through pattern: return upstream tokens directly\n const response: TokenResponse = {\n access_token: clientCode.upstreamTokens.accessToken,\n expires_in: clientCode.upstreamTokens.expiresIn,\n token_type: clientCode.upstreamTokens.tokenType,\n };\n\n if (clientCode.upstreamTokens.refreshToken) {\n response.refresh_token = clientCode.upstreamTokens.refreshToken;\n }\n\n if (clientCode.upstreamTokens.idToken) {\n response.id_token = clientCode.upstreamTokens.idToken;\n }\n\n if (clientCode.upstreamTokens.scope.length > 0) {\n response.scope = clientCode.upstreamTokens.scope.join(\" \");\n }\n\n return response;\n }\n }\n\n /**\n * Token endpoint - refresh access token\n */\n async exchangeRefreshToken(request: RefreshRequest): Promise<TokenResponse> {\n if (request.grant_type !== \"refresh_token\") {\n throw new OAuthProxyError(\n \"unsupported_grant_type\",\n \"Only refresh_token grant type is supported\",\n );\n }\n\n // Exchange refresh token with upstream provider\n const tokenResponse = await fetch(this.config.upstreamTokenEndpoint, {\n body: new URLSearchParams({\n client_id: this.config.upstreamClientId,\n client_secret: this.config.upstreamClientSecret,\n grant_type: \"refresh_token\",\n refresh_token: request.refresh_token,\n ...(request.scope && { scope: request.scope }),\n }),\n headers: {\n \"Content-Type\": \"application/x-www-form-urlencoded\",\n },\n method: \"POST\",\n });\n\n if (!tokenResponse.ok) {\n const error = (await tokenResponse.json()) as {\n error?: string;\n error_description?: string;\n };\n throw new OAuthProxyError(\n error.error || \"invalid_grant\",\n error.error_description,\n );\n }\n\n const tokens = (await tokenResponse.json()) as {\n access_token: string;\n expires_in: number;\n id_token?: string;\n refresh_token?: string;\n scope?: string;\n token_type?: string;\n };\n\n return {\n access_token: tokens.access_token,\n expires_in: tokens.expires_in,\n id_token: tokens.id_token,\n refresh_token: tokens.refresh_token,\n scope: tokens.scope,\n token_type: tokens.token_type || \"Bearer\",\n };\n }\n\n /**\n * Get OAuth discovery metadata\n */\n getAuthorizationServerMetadata(): {\n authorizationEndpoint: string;\n codeChallengeMethodsSupported?: string[];\n dpopSigningAlgValuesSupported?: string[];\n grantTypesSupported?: string[];\n introspectionEndpoint?: string;\n issuer: string;\n jwksUri?: string;\n opPolicyUri?: string;\n opTosUri?: string;\n registrationEndpoint?: string;\n responseModesSupported?: string[];\n responseTypesSupported: string[];\n revocationEndpoint?: string;\n scopesSupported?: string[];\n serviceDocumentation?: string;\n tokenEndpoint: string;\n tokenEndpointAuthMethodsSupported?: string[];\n tokenEndpointAuthSigningAlgValuesSupported?: string[];\n uiLocalesSupported?: string[];\n } {\n return {\n authorizationEndpoint: `${this.config.baseUrl}/oauth/authorize`,\n codeChallengeMethodsSupported: [\"S256\", \"plain\"],\n grantTypesSupported: [\"authorization_code\", \"refresh_token\"],\n issuer: this.config.baseUrl,\n registrationEndpoint: `${this.config.baseUrl}/oauth/register`,\n responseTypesSupported: [\"code\"],\n scopesSupported: this.config.scopes || [],\n tokenEndpoint: `${this.config.baseUrl}/oauth/token`,\n tokenEndpointAuthMethodsSupported: [\n \"client_secret_basic\",\n \"client_secret_post\",\n ],\n };\n }\n\n /**\n * Handle OAuth callback from upstream provider\n */\n async handleCallback(request: Request): Promise<Response> {\n const url = new URL(request.url);\n const code = url.searchParams.get(\"code\");\n const state = url.searchParams.get(\"state\");\n const error = url.searchParams.get(\"error\");\n\n // Check for errors from upstream\n if (error) {\n const errorDescription = url.searchParams.get(\"error_description\");\n throw new OAuthProxyError(error, errorDescription || undefined);\n }\n\n if (!code || !state) {\n throw new OAuthProxyError(\n \"invalid_request\",\n \"Missing code or state parameter\",\n );\n }\n\n // Retrieve transaction\n const transaction = this.transactions.get(state);\n if (!transaction) {\n throw new OAuthProxyError(\"invalid_request\", \"Invalid or expired state\");\n }\n\n // Exchange code with upstream provider\n const upstreamTokens = await this.exchangeUpstreamCode(code, transaction);\n\n // Generate authorization code for client\n const clientCode = this.generateAuthorizationCode(\n transaction,\n upstreamTokens,\n );\n\n // Clean up transaction\n this.transactions.delete(state);\n\n // Redirect to client callback with code\n const redirectUrl = new URL(transaction.clientCallbackUrl);\n redirectUrl.searchParams.set(\"code\", clientCode);\n redirectUrl.searchParams.set(\"state\", transaction.state);\n\n return new Response(null, {\n headers: {\n Location: redirectUrl.toString(),\n },\n status: 302,\n });\n }\n\n /**\n * Handle consent form submission\n */\n async handleConsent(request: Request): Promise<Response> {\n const formData = await request.formData();\n const transactionId = formData.get(\"transaction_id\") as string;\n const action = formData.get(\"action\") as string;\n\n if (!transactionId) {\n throw new OAuthProxyError(\"invalid_request\", \"Missing transaction_id\");\n }\n\n const transaction = this.transactions.get(transactionId);\n if (!transaction) {\n throw new OAuthProxyError(\n \"invalid_request\",\n \"Invalid or expired transaction\",\n );\n }\n\n if (action === \"deny\") {\n // User denied consent\n this.transactions.delete(transactionId);\n const redirectUrl = new URL(transaction.clientCallbackUrl);\n redirectUrl.searchParams.set(\"error\", \"access_denied\");\n redirectUrl.searchParams.set(\n \"error_description\",\n \"User denied authorization\",\n );\n redirectUrl.searchParams.set(\"state\", transaction.state);\n\n return new Response(null, {\n headers: {\n Location: redirectUrl.toString(),\n },\n status: 302,\n });\n }\n\n // User approved, mark consent and redirect to upstream\n transaction.consentGiven = true;\n this.transactions.set(transactionId, transaction);\n\n return this.redirectToUpstream(transaction);\n }\n\n /**\n * Load upstream tokens from a FastMCP JWT\n */\n async loadUpstreamTokens(\n fastmcpToken: string,\n ): Promise<null | UpstreamTokenSet> {\n if (!this.jwtIssuer) {\n return null;\n }\n\n // Verify FastMCP JWT\n const result = await this.jwtIssuer.verify(fastmcpToken);\n if (!result.valid || !result.claims?.jti) {\n return null;\n }\n\n // Look up token mapping\n const mapping = (await this.tokenStorage.get(\n `mapping:${result.claims.jti}`,\n )) as {\n upstreamTokenKey: string;\n } | null;\n\n if (!mapping) {\n return null;\n }\n\n // Retrieve upstream tokens\n const upstreamTokens = (await this.tokenStorage.get(\n `upstream:${mapping.upstreamTokenKey}`,\n )) as null | UpstreamTokenSet;\n\n return upstreamTokens;\n }\n\n /**\n * RFC 7591 Dynamic Client Registration\n */\n async registerClient(request: DCRRequest): Promise<DCRResponse> {\n // Validate required fields\n if (!request.redirect_uris || request.redirect_uris.length === 0) {\n throw new OAuthProxyError(\n \"invalid_client_metadata\",\n \"redirect_uris is required\",\n );\n }\n\n // Validate redirect URIs\n for (const uri of request.redirect_uris) {\n if (!this.validateRedirectUri(uri)) {\n throw new OAuthProxyError(\n \"invalid_redirect_uri\",\n `Invalid redirect URI: ${uri}`,\n );\n }\n }\n\n // Store client registration (indexed by primary redirect URI)\n const clientId = this.config.upstreamClientId;\n const client: ProxyDCRClient = {\n callbackUrl: request.redirect_uris[0],\n clientId,\n clientSecret: this.config.upstreamClientSecret,\n metadata: {\n client_name: request.client_name,\n client_uri: request.client_uri,\n contacts: request.contacts,\n jwks: request.jwks,\n jwks_uri: request.jwks_uri,\n logo_uri: request.logo_uri,\n policy_uri: request.policy_uri,\n scope: request.scope,\n software_id: request.software_id,\n software_version: request.software_version,\n tos_uri: request.tos_uri,\n },\n registeredAt: new Date(),\n };\n\n this.registeredClients.set(request.redirect_uris[0], client);\n\n // Return RFC 7591 compliant response\n const response: DCRResponse = {\n client_id: clientId,\n client_id_issued_at: Math.floor(Date.now() / 1000),\n // Echo back optional metadata\n client_name: request.client_name,\n client_secret: this.config.upstreamClientSecret,\n client_secret_expires_at: 0, // Never expires\n client_uri: request.client_uri,\n contacts: request.contacts,\n grant_types: request.grant_types || [\n \"authorization_code\",\n \"refresh_token\",\n ],\n jwks: request.jwks,\n jwks_uri: request.jwks_uri,\n logo_uri: request.logo_uri,\n policy_uri: request.policy_uri,\n redirect_uris: request.redirect_uris,\n response_types: request.response_types || [\"code\"],\n scope: request.scope,\n software_id: request.software_id,\n software_version: request.software_version,\n token_endpoint_auth_method:\n request.token_endpoint_auth_method || \"client_secret_basic\",\n tos_uri: request.tos_uri,\n };\n\n return response;\n }\n\n /**\n * Clean up expired transactions and codes\n */\n private cleanup(): void {\n const now = Date.now();\n\n // Clean up expired transactions\n for (const [id, transaction] of this.transactions.entries()) {\n if (transaction.expiresAt.getTime() < now) {\n this.transactions.delete(id);\n }\n }\n\n // Clean up expired codes\n for (const [code, clientCode] of this.clientCodes.entries()) {\n if (clientCode.expiresAt.getTime() < now) {\n this.clientCodes.delete(code);\n }\n }\n\n // Clean up token storage\n void this.tokenStorage.cleanup();\n }\n\n /**\n * Create a new OAuth transaction\n */\n private async createTransaction(\n params: AuthorizationParams,\n ): Promise<OAuthTransaction> {\n const transactionId = this.generateId();\n const proxyPkce = PKCEUtils.generatePair(\"S256\");\n\n const transaction: OAuthTransaction = {\n clientCallbackUrl: params.redirect_uri,\n clientCodeChallenge: params.code_challenge || \"\",\n clientCodeChallengeMethod: params.code_challenge_method || \"plain\",\n clientId: params.client_id,\n createdAt: new Date(),\n expiresAt: new Date(\n Date.now() + (this.config.transactionTtl || 600) * 1000,\n ),\n id: transactionId,\n proxyCodeChallenge: proxyPkce.challenge,\n proxyCodeVerifier: proxyPkce.verifier,\n scope: params.scope ? params.scope.split(\" \") : this.config.scopes || [],\n state: params.state || this.generateId(),\n };\n\n this.transactions.set(transactionId, transaction);\n\n return transaction;\n }\n\n /**\n * Exchange authorization code with upstream provider\n */\n private async exchangeUpstreamCode(\n code: string,\n transaction: OAuthTransaction,\n ): Promise<UpstreamTokenSet> {\n const tokenResponse = await fetch(this.config.upstreamTokenEndpoint, {\n body: new URLSearchParams({\n client_id: this.config.upstreamClientId,\n client_secret: this.config.upstreamClientSecret,\n code,\n code_verifier: transaction.proxyCodeVerifier,\n grant_type: \"authorization_code\",\n redirect_uri: `${this.config.baseUrl}${this.config.redirectPath}`,\n }),\n headers: {\n \"Content-Type\": \"application/x-www-form-urlencoded\",\n },\n method: \"POST\",\n });\n\n if (!tokenResponse.ok) {\n const error = (await tokenResponse.json()) as {\n error?: string;\n error_description?: string;\n };\n throw new OAuthProxyError(\n error.error || \"server_error\",\n error.error_description,\n );\n }\n\n const tokens = (await tokenResponse.json()) as {\n access_token: string;\n expires_in?: number;\n id_token?: string;\n refresh_token?: string;\n scope?: string;\n token_type?: string;\n };\n\n return {\n accessToken: tokens.access_token,\n expiresIn: tokens.expires_in || 3600,\n idToken: tokens.id_token,\n issuedAt: new Date(),\n refreshToken: tokens.refresh_token,\n scope: tokens.scope ? tokens.scope.split(\" \") : transaction.scope,\n tokenType: tokens.token_type || \"Bearer\",\n };\n }\n\n /**\n * Extract JTI from a JWT token\n */\n private async extractJti(token: string): Promise<string> {\n if (!this.jwtIssuer) {\n throw new Error(\"JWT issuer not initialized\");\n }\n\n const result = await this.jwtIssuer.verify(token);\n if (!result.valid || !result.claims?.jti) {\n throw new Error(\"Failed to extract JTI from token\");\n }\n\n return result.claims.jti;\n }\n\n /**\n * Extract custom claims from upstream tokens\n * Combines claims from access token and ID token (if present)\n */\n private async extractUpstreamClaims(\n upstreamTokens: UpstreamTokenSet,\n ): Promise<null | Record<string, unknown>> {\n if (!this.claimsExtractor) {\n return null;\n }\n\n const allClaims: Record<string, unknown> = {};\n\n // Extract from access token (if JWT format)\n const accessClaims = await this.claimsExtractor.extract(\n upstreamTokens.accessToken,\n \"access\",\n );\n if (accessClaims) {\n Object.assign(allClaims, accessClaims);\n }\n\n // Extract from ID token (if present and JWT format)\n if (upstreamTokens.idToken) {\n const idClaims = await this.claimsExtractor.extract(\n upstreamTokens.idToken,\n \"id\",\n );\n if (idClaims) {\n // Access token claims take precedence over ID token claims\n for (const [key, value] of Object.entries(idClaims)) {\n if (!(key in allClaims)) {\n allClaims[key] = value;\n }\n }\n }\n }\n\n return Object.keys(allClaims).length > 0 ? allClaims : null;\n }\n\n /**\n * Generate authorization code for client\n */\n private generateAuthorizationCode(\n transaction: OAuthTransaction,\n upstreamTokens: UpstreamTokenSet,\n ): string {\n const code = this.generateId();\n\n const clientCode: ClientCode = {\n clientId: transaction.clientId,\n code,\n codeChallenge: transaction.clientCodeChallenge,\n codeChallengeMethod: transaction.clientCodeChallengeMethod,\n createdAt: new Date(),\n expiresAt: new Date(\n Date.now() + (this.config.authorizationCodeTtl || 300) * 1000,\n ),\n transactionId: transaction.id,\n upstreamTokens,\n };\n\n this.clientCodes.set(code, clientCode);\n\n return code;\n }\n\n /**\n * Generate secure random ID\n */\n private generateId(): string {\n return randomBytes(32).toString(\"base64url\");\n }\n\n /**\n * Generate signing key for consent cookies\n */\n private generateSigningKey(): string {\n return randomBytes(32).toString(\"hex\");\n }\n\n /**\n * Get provider name for display\n */\n private getProviderName(): string {\n const url = new URL(this.config.upstreamAuthorizationEndpoint);\n return url.hostname;\n }\n\n /**\n * Issue swapped tokens (JWT pattern)\n * Issues short-lived FastMCP JWTs and stores upstream tokens securely\n */\n private async issueSwappedTokens(\n clientId: string,\n upstreamTokens: UpstreamTokenSet,\n ): Promise<TokenResponse> {\n if (!this.jwtIssuer) {\n throw new Error(\"JWT issuer not initialized\");\n }\n\n // Extract custom claims from upstream tokens\n const customClaims = await this.extractUpstreamClaims(upstreamTokens);\n\n // Store upstream tokens\n const upstreamTokenKey = this.generateId();\n await this.tokenStorage.save(\n `upstream:${upstreamTokenKey}`,\n upstreamTokens,\n upstreamTokens.expiresIn,\n );\n\n // Issue FastMCP access token with custom claims\n const accessToken = this.jwtIssuer.issueAccessToken(\n clientId,\n upstreamTokens.scope,\n customClaims || undefined,\n );\n\n // Decode JWT to get JTI\n const accessJti = await this.extractJti(accessToken);\n\n // Store token mapping\n await this.tokenStorage.save(\n `mapping:${accessJti}`,\n {\n clientId,\n createdAt: new Date(),\n expiresAt: new Date(Date.now() + upstreamTokens.expiresIn * 1000),\n jti: accessJti,\n scope: upstreamTokens.scope,\n upstreamTokenKey,\n },\n upstreamTokens.expiresIn,\n );\n\n const response: TokenResponse = {\n access_token: accessToken,\n expires_in: 3600, // FastMCP JWT expiration (1 hour)\n scope: upstreamTokens.scope.join(\" \"),\n token_type: \"Bearer\",\n };\n\n // Issue refresh token if upstream provided one\n if (upstreamTokens.refreshToken) {\n const refreshToken = this.jwtIssuer.issueRefreshToken(\n clientId,\n upstreamTokens.scope,\n customClaims || undefined,\n );\n const refreshJti = await this.extractJti(refreshToken);\n\n // Store refresh token mapping\n await this.tokenStorage.save(\n `mapping:${refreshJti}`,\n {\n clientId,\n createdAt: new Date(),\n expiresAt: new Date(Date.now() + 2592000 * 1000), // 30 days\n jti: refreshJti,\n scope: upstreamTokens.scope,\n upstreamTokenKey,\n },\n 2592000, // 30 days\n );\n\n response.refresh_token = refreshToken;\n }\n\n return response;\n }\n\n /**\n * Match URI against pattern (supports wildcards)\n */\n private matchesPattern(uri: string, pattern: string): boolean {\n const regex = new RegExp(\n \"^\" + pattern.replace(/\\*/g, \".*\").replace(/\\?/g, \".\") + \"$\",\n );\n return regex.test(uri);\n }\n\n /**\n * Redirect to upstream OAuth provider\n */\n private redirectToUpstream(transaction: OAuthTransaction): Response {\n const authUrl = new URL(this.config.upstreamAuthorizationEndpoint);\n\n authUrl.searchParams.set(\"client_id\", this.config.upstreamClientId);\n authUrl.searchParams.set(\n \"redirect_uri\",\n `${this.config.baseUrl}${this.config.redirectPath}`,\n );\n authUrl.searchParams.set(\"response_type\", \"code\");\n authUrl.searchParams.set(\"state\", transaction.id);\n\n if (transaction.scope.length > 0) {\n authUrl.searchParams.set(\"scope\", transaction.scope.join(\" \"));\n }\n\n // Add PKCE if not forwarding client PKCE\n if (!this.config.forwardPkce) {\n authUrl.searchParams.set(\n \"code_challenge\",\n transaction.proxyCodeChallenge,\n );\n authUrl.searchParams.set(\"code_challenge_method\", \"S256\");\n }\n\n return new Response(null, {\n headers: {\n Location: authUrl.toString(),\n },\n status: 302,\n });\n }\n\n /**\n * Start periodic cleanup of expired transactions and codes\n */\n private startCleanup(): void {\n this.cleanupInterval = setInterval(() => {\n this.cleanup();\n }, 60000); // Run every minute\n }\n\n /**\n * Validate redirect URI against allowed patterns\n */\n private validateRedirectUri(uri: string): boolean {\n try {\n const url = new URL(uri);\n const patterns = this.config.allowedRedirectUriPatterns || [];\n\n for (const pattern of patterns) {\n if (this.matchesPattern(uri, pattern)) {\n return true;\n }\n }\n\n // Default: allow https and localhost\n return (\n url.protocol === \"https:\" ||\n url.hostname === \"localhost\" ||\n url.hostname === \"127.0.0.1\"\n );\n } catch {\n return false;\n }\n }\n}\n\n/**\n * OAuth Proxy Error\n */\nexport class OAuthProxyError extends Error {\n constructor(\n public code: string,\n public description?: string,\n public statusCode: number = 400,\n ) {\n super(code);\n this.name = \"OAuthProxyError\";\n }\n\n toJSON(): OAuthError {\n return {\n error: this.code,\n error_description: this.description,\n };\n }\n\n toResponse(): Response {\n return new Response(JSON.stringify(this.toJSON()), {\n headers: { \"Content-Type\": \"application/json\" },\n status: this.statusCode,\n });\n }\n}\n","/**\n * ClaimsExtractor\n * Securely extracts and filters custom claims from upstream OAuth tokens\n */\n\nimport type { CustomClaimsPassthroughConfig } from \"../types.js\";\n\nexport class ClaimsExtractor {\n private config: CustomClaimsPassthroughConfig;\n\n // Claims that MUST NOT be copied from upstream (protect proxy's JWT integrity)\n private readonly PROTECTED_CLAIMS = new Set([\n \"aud\",\n \"client_id\",\n \"exp\",\n \"iat\",\n \"iss\",\n \"jti\",\n \"nbf\",\n ]);\n\n constructor(config: boolean | CustomClaimsPassthroughConfig) {\n // Handle boolean shorthand: true = default config, false = disabled\n if (typeof config === \"boolean\") {\n config = config ? {} : { fromAccessToken: false, fromIdToken: false };\n }\n\n // Apply defaults\n this.config = {\n allowComplexClaims: config.allowComplexClaims || false,\n allowedClaims: config.allowedClaims,\n blockedClaims: config.blockedClaims || [],\n claimPrefix:\n config.claimPrefix !== undefined ? config.claimPrefix : false, // Default: no prefix\n fromAccessToken: config.fromAccessToken !== false, // Default: true\n fromIdToken: config.fromIdToken !== false, // Default: true\n maxClaimValueSize: config.maxClaimValueSize || 2000,\n };\n }\n\n /**\n * Extract claims from a token (access token or ID token)\n */\n async extract(\n token: string,\n tokenType: \"access\" | \"id\",\n ): Promise<null | Record<string, unknown>> {\n // Check if this token type is enabled\n if (tokenType === \"access\" && !this.config.fromAccessToken) {\n return null;\n }\n if (tokenType === \"id\" && !this.config.fromIdToken) {\n return null;\n }\n\n // Detect if token is JWT format (3 parts separated by dots)\n if (!this.isJWT(token)) {\n // Opaque token - no claims to extract\n return null;\n }\n\n // Decode JWT payload (base64url decode only, no signature verification)\n // We trust the token because it came from upstream via server-to-server exchange\n const payload = this.decodeJWTPayload(token);\n if (!payload) {\n return null;\n }\n\n // Filter and validate claims\n const filtered = this.filterClaims(payload);\n\n // Apply prefix if configured\n return this.applyPrefix(filtered);\n }\n\n /**\n * Apply prefix to claim names (if configured)\n */\n private applyPrefix(\n claims: Record<string, unknown>,\n ): Record<string, unknown> {\n const prefix = this.config.claimPrefix;\n\n // No prefix configured or explicitly disabled\n if (prefix === false || prefix === \"\" || prefix === undefined) {\n return claims;\n }\n\n // Apply prefix to all claim names\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(claims)) {\n result[`${prefix}${key}`] = value;\n }\n\n return result;\n }\n\n /**\n * Decode JWT payload without signature verification\n * Safe because token came from trusted upstream via server-to-server exchange\n */\n private decodeJWTPayload(token: string): null | Record<string, unknown> {\n try {\n const parts = token.split(\".\");\n if (parts.length !== 3) {\n return null;\n }\n\n // Decode the payload (middle part)\n const payload = Buffer.from(parts[1], \"base64url\").toString(\"utf-8\");\n return JSON.parse(payload) as Record<string, unknown>;\n } catch (error) {\n // Invalid JWT format or JSON\n console.warn(`Failed to decode JWT payload: ${error}`);\n return null;\n }\n }\n\n /**\n * Filter claims based on security rules\n */\n private filterClaims(\n claims: Record<string, unknown>,\n ): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(claims)) {\n // RULE 1: Skip protected claims (ALWAYS enforced)\n if (this.PROTECTED_CLAIMS.has(key)) {\n continue;\n }\n\n // RULE 2: Skip blocked claims\n if (this.config.blockedClaims?.includes(key)) {\n continue;\n }\n\n // RULE 3: If allowlist exists, only include allowed claims\n if (\n this.config.allowedClaims &&\n !this.config.allowedClaims.includes(key)\n ) {\n continue;\n }\n\n // RULE 4: Validate claim value\n if (!this.isValidClaimValue(value)) {\n console.warn(`Skipping claim '${key}' due to invalid value`);\n continue;\n }\n\n result[key] = value;\n }\n\n return result;\n }\n\n /**\n * Check if a token is in JWT format\n */\n private isJWT(token: string): boolean {\n return token.split(\".\").length === 3;\n }\n\n /**\n * Validate a claim value (type and size checks)\n */\n private isValidClaimValue(value: unknown): boolean {\n if (value === null || value === undefined) {\n return false;\n }\n\n const type = typeof value;\n\n // Primitive types (string, number, boolean) are always allowed\n if (type === \"string\") {\n const maxSize = this.config.maxClaimValueSize ?? 2000;\n return (value as string).length <= maxSize;\n }\n\n if (type === \"number\" || type === \"boolean\") {\n return true;\n }\n\n // Arrays and objects only if explicitly allowed\n if (Array.isArray(value) || type === \"object\") {\n // Complex types not allowed by default (security)\n if (!this.config.allowComplexClaims) {\n return false;\n }\n\n // Check serialized size\n try {\n const stringified = JSON.stringify(value);\n const maxSize = this.config.maxClaimValueSize ?? 2000;\n return stringified.length <= maxSize;\n } catch {\n // Can't serialize - reject\n return false;\n }\n }\n\n // Unknown type - reject\n return false;\n }\n}\n","/**\n * Consent Management\n * Handles user consent flow for OAuth authorization\n */\n\nimport { createHmac } from \"crypto\";\n\nimport type { ConsentData, OAuthTransaction } from \"../types.js\";\n\n/**\n * Manages consent screens and cookie signing\n */\nexport class ConsentManager {\n private signingKey: string;\n\n constructor(signingKey: string) {\n this.signingKey = signingKey || this.generateDefaultKey();\n }\n\n /**\n * Create HTTP response with consent screen\n */\n createConsentResponse(\n transaction: OAuthTransaction,\n provider: string,\n ): Response {\n const consentData: ConsentData = {\n clientName: \"MCP Client\",\n provider,\n scope: transaction.scope,\n timestamp: Date.now(),\n transactionId: transaction.id,\n };\n\n const html = this.generateConsentScreen(consentData);\n\n return new Response(html, {\n headers: {\n \"Content-Type\": \"text/html; charset=utf-8\",\n },\n status: 200,\n });\n }\n\n /**\n * Generate HTML for consent screen\n */\n generateConsentScreen(data: ConsentData): string {\n const { clientName, provider, scope, transactionId } = data;\n\n return `\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>Authorization Request</title>\n <style>\n * {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n }\n\n body {\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif;\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n min-height: 100vh;\n display: flex;\n justify-content: center;\n align-items: center;\n padding: 20px;\n }\n\n .consent-container {\n background: white;\n border-radius: 12px;\n box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);\n max-width: 480px;\n width: 100%;\n padding: 40px;\n }\n\n .header {\n text-align: center;\n margin-bottom: 30px;\n }\n\n .header h1 {\n color: #1a202c;\n font-size: 24px;\n margin-bottom: 8px;\n }\n\n .header p {\n color: #718096;\n font-size: 14px;\n }\n\n .app-info {\n background: #f7fafc;\n border-radius: 8px;\n padding: 20px;\n margin-bottom: 24px;\n }\n\n .app-info h2 {\n color: #2d3748;\n font-size: 18px;\n margin-bottom: 12px;\n }\n\n .app-name {\n color: #667eea;\n font-weight: 600;\n }\n\n .permissions {\n margin-top: 16px;\n }\n\n .permissions h3 {\n color: #4a5568;\n font-size: 14px;\n margin-bottom: 8px;\n font-weight: 600;\n }\n\n .permissions ul {\n list-style: none;\n }\n\n .permissions li {\n color: #718096;\n font-size: 14px;\n padding: 6px 0;\n padding-left: 24px;\n position: relative;\n }\n\n .permissions li:before {\n content: \"✓\";\n position: absolute;\n left: 0;\n color: #48bb78;\n font-weight: bold;\n }\n\n .warning {\n background: #fffaf0;\n border-left: 4px solid #ed8936;\n padding: 12px 16px;\n margin-bottom: 24px;\n border-radius: 4px;\n }\n\n .warning p {\n color: #744210;\n font-size: 13px;\n line-height: 1.5;\n }\n\n .actions {\n display: flex;\n gap: 12px;\n }\n\n button {\n flex: 1;\n padding: 14px 24px;\n border: none;\n border-radius: 6px;\n font-size: 16px;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.2s;\n }\n\n .approve {\n background: #667eea;\n color: white;\n }\n\n .approve:hover {\n background: #5a67d8;\n transform: translateY(-1px);\n box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);\n }\n\n .deny {\n background: #e2e8f0;\n color: #4a5568;\n }\n\n .deny:hover {\n background: #cbd5e0;\n }\n\n .footer {\n margin-top: 24px;\n text-align: center;\n color: #a0aec0;\n font-size: 12px;\n }\n </style>\n</head>\n<body>\n <div class=\"consent-container\">\n <div class=\"header\">\n <h1>🔐 Authorization Request</h1>\n <p>via ${this.escapeHtml(provider)}</p>\n </div>\n\n <div class=\"app-info\">\n <h2>\n <span class=\"app-name\">${this.escapeHtml(clientName || \"An application\")}</span>\n requests access\n </h2>\n\n <div class=\"permissions\">\n <h3>This will allow the app to:</h3>\n <ul>\n ${scope.map((s) => `<li>${this.escapeHtml(this.formatScope(s))}</li>`).join(\"\")}\n </ul>\n </div>\n </div>\n\n <div class=\"warning\">\n <p>\n <strong>⚠️ Important:</strong> Only approve if you trust this application.\n By approving, you authorize it to access your account information.\n </p>\n </div>\n\n <form method=\"POST\" action=\"/oauth/consent\">\n <input type=\"hidden\" name=\"transaction_id\" value=\"${this.escapeHtml(transactionId)}\">\n <div class=\"actions\">\n <button type=\"submit\" name=\"action\" value=\"deny\" class=\"deny\">\n Deny\n </button>\n <button type=\"submit\" name=\"action\" value=\"approve\" class=\"approve\">\n Approve\n </button>\n </div>\n </form>\n\n <div class=\"footer\">\n <p>This consent is required to prevent unauthorized access.</p>\n </div>\n </div>\n</body>\n</html>\n `.trim();\n }\n\n /**\n * Sign consent data for cookie\n */\n signConsentCookie(data: ConsentData): string {\n const payload = JSON.stringify(data);\n const signature = this.sign(payload);\n\n return `${Buffer.from(payload).toString(\"base64\")}.${signature}`;\n }\n\n /**\n * Validate and parse consent cookie\n */\n validateConsentCookie(cookie: string): ConsentData | null {\n try {\n const [payloadB64, signature] = cookie.split(\".\");\n\n if (!payloadB64 || !signature) {\n return null;\n }\n\n const payload = Buffer.from(payloadB64, \"base64\").toString(\"utf8\");\n const expectedSignature = this.sign(payload);\n\n if (signature !== expectedSignature) {\n return null;\n }\n\n const data = JSON.parse(payload) as ConsentData;\n\n // Check if consent is still valid (5 minutes)\n const age = Date.now() - data.timestamp;\n if (age > 5 * 60 * 1000) {\n return null;\n }\n\n return data;\n } catch {\n return null;\n }\n }\n\n /**\n * Escape HTML to prevent XSS\n */\n private escapeHtml(text: string): string {\n const map: Record<string, string> = {\n \"'\": \"&#x27;\",\n '\"': \"&quot;\",\n \"/\": \"&#x2F;\",\n \"&\": \"&amp;\",\n \"<\": \"&lt;\",\n \">\": \"&gt;\",\n };\n\n return text.replace(/[&<>\"'/]/g, (char) => map[char] || char);\n }\n\n /**\n * Format scope for display\n */\n private formatScope(scope: string): string {\n // Convert scope names to readable format\n const scopeMap: Record<string, string> = {\n email: \"Access your email address\",\n openid: \"Verify your identity\",\n profile: \"View your basic profile information\",\n \"read:user\": \"Read your user information\",\n \"write:user\": \"Modify your user information\",\n };\n\n return scopeMap[scope] || scope.replace(/_/g, \" \").replace(/:/g, \" - \");\n }\n\n /**\n * Generate default signing key if none provided\n */\n private generateDefaultKey(): string {\n return `fastmcp-consent-${Date.now()}-${Math.random()}`;\n }\n\n /**\n * Sign a payload using HMAC-SHA256\n */\n private sign(payload: string): string {\n return createHmac(\"sha256\", this.signingKey).update(payload).digest(\"hex\");\n }\n}\n","/**\n * JWT Issuer for OAuth Proxy\n * Issues and validates short-lived JWTs that reference upstream provider tokens\n */\n\nimport { createHmac, pbkdf2, randomBytes } from \"crypto\";\nimport { promisify } from \"util\";\n\nconst pbkdf2Async = promisify(pbkdf2);\n\n/**\n * JWT Claims for FastMCP tokens\n */\nexport interface JWTClaims {\n /** Additional custom claims from upstream tokens */\n [key: string]: unknown;\n /** Audience */\n aud: string;\n /** Client ID */\n client_id: string;\n /** Expiration time (seconds since epoch) */\n exp: number;\n /** Issued at time (seconds since epoch) */\n iat: number;\n /** Issuer */\n iss: string;\n /** JWT ID (unique identifier) */\n jti: string;\n /** Scopes */\n scope: string[];\n}\n\n/**\n * JWT Issuer configuration\n */\nexport interface JWTIssuerConfig {\n /** Token expiration in seconds (default: 3600 = 1 hour) */\n accessTokenTtl?: number;\n /** Audience for issued tokens */\n audience: string;\n /** Issuer identifier */\n issuer: string;\n /** Refresh token expiration in seconds (default: 2592000 = 30 days) */\n refreshTokenTtl?: number;\n /** Secret key for signing tokens */\n signingKey: string;\n}\n\n/**\n * Token validation result\n */\nexport interface TokenValidationResult {\n /** Decoded claims if valid */\n claims?: JWTClaims;\n /** Error message if invalid */\n error?: string;\n /** Whether token is valid */\n valid: boolean;\n}\n\n/**\n * JWT Header\n */\ninterface JWTHeader {\n alg: string;\n typ: string;\n}\n\n/**\n * JWT Issuer\n * Issues and validates HS256-signed JWTs for the OAuth proxy\n */\nexport class JWTIssuer {\n private accessTokenTtl: number;\n private audience: string;\n private issuer: string;\n private refreshTokenTtl: number;\n private signingKey: Buffer;\n\n constructor(config: JWTIssuerConfig) {\n this.issuer = config.issuer;\n this.audience = config.audience;\n this.accessTokenTtl = config.accessTokenTtl || 3600; // 1 hour\n this.refreshTokenTtl = config.refreshTokenTtl || 2592000; // 30 days\n this.signingKey = Buffer.from(config.signingKey);\n }\n\n /**\n * Derive a signing key from a secret\n * Uses PBKDF2 for key derivation\n */\n static async deriveKey(\n secret: string,\n iterations: number = 100000,\n ): Promise<string> {\n const salt = Buffer.from(\"fastmcp-oauth-proxy\");\n const key = await pbkdf2Async(secret, salt, iterations, 32, \"sha256\");\n return key.toString(\"base64\");\n }\n\n /**\n * Issue an access token\n */\n issueAccessToken(\n clientId: string,\n scope: string[],\n additionalClaims?: Record<string, unknown>,\n ): string {\n const now = Math.floor(Date.now() / 1000);\n const jti = this.generateJti();\n\n const claims: JWTClaims = {\n aud: this.audience,\n client_id: clientId,\n exp: now + this.accessTokenTtl,\n iat: now,\n iss: this.issuer,\n jti,\n scope,\n // Merge additional claims (custom claims from upstream)\n ...(additionalClaims || {}),\n };\n\n return this.signToken(claims);\n }\n\n /**\n * Issue a refresh token\n */\n issueRefreshToken(\n clientId: string,\n scope: string[],\n additionalClaims?: Record<string, unknown>,\n ): string {\n const now = Math.floor(Date.now() / 1000);\n const jti = this.generateJti();\n\n const claims: JWTClaims = {\n aud: this.audience,\n client_id: clientId,\n exp: now + this.refreshTokenTtl,\n iat: now,\n iss: this.issuer,\n jti,\n scope,\n // Merge additional claims (custom claims from upstream)\n ...(additionalClaims || {}),\n };\n\n return this.signToken(claims);\n }\n\n /**\n * Validate a JWT token\n */\n async verify(token: string): Promise<TokenValidationResult> {\n try {\n const parts = token.split(\".\");\n if (parts.length !== 3) {\n return {\n error: \"Invalid token format\",\n valid: false,\n };\n }\n\n const [headerB64, payloadB64, signatureB64] = parts;\n\n // Verify signature\n const expectedSignature = this.sign(`${headerB64}.${payloadB64}`);\n if (signatureB64 !== expectedSignature) {\n return {\n error: \"Invalid signature\",\n valid: false,\n };\n }\n\n // Decode claims\n const claims: JWTClaims = JSON.parse(\n Buffer.from(payloadB64, \"base64url\").toString(\"utf-8\"),\n );\n\n // Validate claims\n const now = Math.floor(Date.now() / 1000);\n\n if (claims.exp <= now) {\n return {\n claims,\n error: \"Token expired\",\n valid: false,\n };\n }\n\n if (claims.iss !== this.issuer) {\n return {\n claims,\n error: \"Invalid issuer\",\n valid: false,\n };\n }\n\n if (claims.aud !== this.audience) {\n return {\n claims,\n error: \"Invalid audience\",\n valid: false,\n };\n }\n\n return {\n claims,\n valid: true,\n };\n } catch (error) {\n return {\n error: error instanceof Error ? error.message : \"Validation failed\",\n valid: false,\n };\n }\n }\n\n /**\n * Generate unique JWT ID\n */\n private generateJti(): string {\n return randomBytes(16).toString(\"base64url\");\n }\n\n /**\n * Sign data with HMAC-SHA256\n */\n private sign(data: string): string {\n const hmac = createHmac(\"sha256\", this.signingKey);\n hmac.update(data);\n return hmac.digest(\"base64url\");\n }\n\n /**\n * Sign a JWT token\n */\n private signToken(claims: JWTClaims): string {\n const header: JWTHeader = {\n alg: \"HS256\",\n typ: \"JWT\",\n };\n\n const headerB64 = Buffer.from(JSON.stringify(header)).toString(\"base64url\");\n const payloadB64 = Buffer.from(JSON.stringify(claims)).toString(\n \"base64url\",\n );\n\n const signature = this.sign(`${headerB64}.${payloadB64}`);\n\n return `${headerB64}.${payloadB64}.${signature}`;\n }\n}\n","/**\n * PKCE (Proof Key for Code Exchange) Utilities\n * Implements RFC 7636 for OAuth 2.0 public clients\n */\n\nimport { createHash, randomBytes } from \"crypto\";\n\nimport type { PKCEPair } from \"../types.js\";\n\n/**\n * PKCE utility class for generating and validating code challenges\n */\nexport class PKCEUtils {\n /**\n * Generate a code challenge from a verifier\n * @param verifier The code verifier\n * @param method Challenge method: 'S256' or 'plain' (default: 'S256')\n * @returns Base64URL-encoded challenge string\n */\n static generateChallenge(\n verifier: string,\n method: \"plain\" | \"S256\" = \"S256\",\n ): string {\n if (method === \"plain\") {\n return verifier;\n }\n\n if (method === \"S256\") {\n const hash = createHash(\"sha256\");\n hash.update(verifier);\n return PKCEUtils.base64URLEncode(hash.digest());\n }\n\n throw new Error(`Unsupported challenge method: ${method}`);\n }\n\n /**\n * Generate a complete PKCE pair (verifier + challenge)\n * @param method Challenge method: 'S256' or 'plain' (default: 'S256')\n * @returns Object containing verifier and challenge\n */\n static generatePair(method: \"plain\" | \"S256\" = \"S256\"): PKCEPair {\n const verifier = PKCEUtils.generateVerifier();\n const challenge = PKCEUtils.generateChallenge(verifier, method);\n\n return {\n challenge,\n verifier,\n };\n }\n\n /**\n * Generate a cryptographically secure code verifier\n * @param length Length of verifier (43-128 characters, default: 128)\n * @returns Base64URL-encoded verifier string\n */\n static generateVerifier(length: number = 128): string {\n if (length < 43 || length > 128) {\n throw new Error(\"PKCE verifier length must be between 43 and 128\");\n }\n\n // Generate random bytes and encode as base64url\n // Need more bytes because base64 encoding expands data\n const byteLength = Math.ceil((length * 3) / 4);\n const randomBytesBuffer = randomBytes(byteLength);\n\n return PKCEUtils.base64URLEncode(randomBytesBuffer).slice(0, length);\n }\n\n /**\n * Validate a code verifier against a challenge\n * @param verifier The code verifier to validate\n * @param challenge The expected challenge\n * @param method The challenge method used\n * @returns True if verifier matches challenge\n */\n static validateChallenge(\n verifier: string,\n challenge: string,\n method: string,\n ): boolean {\n if (!verifier || !challenge) {\n return false;\n }\n\n if (method === \"plain\") {\n return verifier === challenge;\n }\n\n if (method === \"S256\") {\n const computedChallenge = PKCEUtils.generateChallenge(verifier, \"S256\");\n return computedChallenge === challenge;\n }\n\n // Unknown method\n return false;\n }\n\n /**\n * Encode a buffer as base64url (RFC 4648)\n * @param buffer Buffer to encode\n * @returns Base64URL-encoded string\n */\n private static base64URLEncode(buffer: Buffer): string {\n return buffer\n .toString(\"base64\")\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\")\n .replace(/=/g, \"\");\n }\n}\n","/**\n * Token Storage Implementations\n * Secure storage for OAuth tokens and transaction state\n */\n\nimport {\n createCipheriv,\n createDecipheriv,\n randomBytes,\n scryptSync,\n} from \"crypto\";\n\nimport type { TokenStorage } from \"../types.js\";\n\ninterface StorageEntry {\n expiresAt: number;\n value: unknown;\n}\n\n/**\n * Encrypted token storage wrapper\n * Encrypts values using AES-256-GCM before storing\n */\nexport class EncryptedTokenStorage implements TokenStorage {\n private algorithm = \"aes-256-gcm\";\n private backend: TokenStorage;\n private encryptionKey: Buffer;\n\n constructor(backend: TokenStorage, encryptionKey: string) {\n this.backend = backend;\n // Synchronously derive key using scrypt\n const salt = Buffer.from(\"fastmcp-oauth-proxy-salt\");\n this.encryptionKey = scryptSync(encryptionKey, salt, 32);\n }\n\n async cleanup(): Promise<void> {\n await this.backend.cleanup();\n }\n\n async delete(key: string): Promise<void> {\n await this.backend.delete(key);\n }\n\n async get(key: string): Promise<null | unknown> {\n const encrypted = await this.backend.get(key);\n\n if (!encrypted) {\n return null;\n }\n\n try {\n const decrypted = await this.decrypt(\n encrypted as string,\n this.encryptionKey,\n );\n return JSON.parse(decrypted);\n } catch (error) {\n console.error(\"Failed to decrypt value:\", error);\n return null;\n }\n }\n\n async save(key: string, value: unknown, ttl?: number): Promise<void> {\n const encrypted = await this.encrypt(\n JSON.stringify(value),\n this.encryptionKey,\n );\n await this.backend.save(key, encrypted, ttl);\n }\n\n private async decrypt(ciphertext: string, key: Buffer): Promise<string> {\n const parts = ciphertext.split(\":\");\n if (parts.length !== 3) {\n throw new Error(\"Invalid encrypted data format\");\n }\n\n const [ivHex, authTagHex, encrypted] = parts;\n const iv = Buffer.from(ivHex, \"hex\");\n const authTag = Buffer.from(authTagHex, \"hex\");\n\n const decipher = createDecipheriv(this.algorithm, key, iv);\n // Use type assertion for GCM-specific method\n (decipher as unknown as { setAuthTag(buffer: Buffer): void }).setAuthTag(\n authTag,\n );\n\n let decrypted = decipher.update(encrypted, \"hex\", \"utf8\");\n decrypted += decipher.final(\"utf8\");\n\n return decrypted;\n }\n\n private async encrypt(plaintext: string, key: Buffer): Promise<string> {\n const iv = randomBytes(16);\n const cipher = createCipheriv(this.algorithm, key, iv);\n\n let encrypted = cipher.update(plaintext, \"utf8\", \"hex\");\n encrypted += cipher.final(\"hex\");\n\n // Use type assertion for GCM-specific method\n const authTag = (\n cipher as unknown as { getAuthTag(): Buffer }\n ).getAuthTag();\n\n // Return format: iv:authTag:encrypted\n return `${iv.toString(\"hex\")}:${authTag.toString(\"hex\")}:${encrypted}`;\n }\n}\n\n/**\n * In-memory token storage with TTL support\n */\nexport class MemoryTokenStorage implements TokenStorage {\n private cleanupInterval: NodeJS.Timeout | null = null;\n private store: Map<string, StorageEntry> = new Map();\n\n constructor(cleanupIntervalMs: number = 60000) {\n // Run cleanup every minute by default\n this.cleanupInterval = setInterval(\n () => void this.cleanup(),\n cleanupIntervalMs,\n );\n }\n\n async cleanup(): Promise<void> {\n const now = Date.now();\n const keysToDelete: string[] = [];\n\n for (const [key, entry] of this.store.entries()) {\n if (entry.expiresAt < now) {\n keysToDelete.push(key);\n }\n }\n\n for (const key of keysToDelete) {\n this.store.delete(key);\n }\n }\n\n async delete(key: string): Promise<void> {\n this.store.delete(key);\n }\n\n /**\n * Destroy the storage and clear cleanup interval\n */\n destroy(): void {\n if (this.cleanupInterval) {\n clearInterval(this.cleanupInterval);\n this.cleanupInterval = null;\n }\n this.store.clear();\n }\n\n async get(key: string): Promise<null | unknown> {\n const entry = this.store.get(key);\n\n if (!entry) {\n return null;\n }\n\n if (entry.expiresAt < Date.now()) {\n this.store.delete(key);\n return null;\n }\n\n return entry.value;\n }\n\n async save(key: string, value: unknown, ttl?: number): Promise<void> {\n const expiresAt = ttl ? Date.now() + ttl * 1000 : Number.MAX_SAFE_INTEGER;\n\n this.store.set(key, {\n expiresAt,\n value,\n });\n }\n\n /**\n * Get the number of stored items\n */\n size(): number {\n return this.store.size;\n }\n}\n","/**\n * Microsoft Azure/Entra ID OAuth Provider\n * Pre-configured OAuth Proxy for Microsoft Identity Platform\n */\n\nimport type { OAuthProviderConfig } from \"../types.js\";\n\nimport { OAuthProxy } from \"../OAuthProxy.js\";\n\nexport interface AzureProviderConfig extends OAuthProviderConfig {\n /** Azure AD tenant ID or 'common', 'organizations', 'consumers' */\n tenantId?: string;\n}\n\n/**\n * Microsoft Azure AD / Entra ID OAuth 2.0 Provider\n * Supports Microsoft accounts and organizational accounts\n */\nexport class AzureProvider extends OAuthProxy {\n constructor(config: AzureProviderConfig) {\n const tenantId = config.tenantId || \"common\";\n\n super({\n baseUrl: config.baseUrl,\n consentRequired: config.consentRequired,\n scopes: config.scopes || [\"openid\", \"profile\", \"email\"],\n upstreamAuthorizationEndpoint: `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/authorize`,\n upstreamClientId: config.clientId,\n upstreamClientSecret: config.clientSecret,\n upstreamTokenEndpoint: `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`,\n });\n }\n}\n","/**\n * GitHub OAuth Provider\n * Pre-configured OAuth Proxy for GitHub OAuth Apps\n */\n\nimport type { OAuthProviderConfig } from \"../types.js\";\n\nimport { OAuthProxy } from \"../OAuthProxy.js\";\n\n/**\n * GitHub OAuth 2.0 Provider\n * Supports GitHub OAuth Apps\n */\nexport class GitHubProvider extends OAuthProxy {\n constructor(config: OAuthProviderConfig) {\n super({\n baseUrl: config.baseUrl,\n consentRequired: config.consentRequired,\n scopes: config.scopes || [\"read:user\", \"user:email\"],\n upstreamAuthorizationEndpoint: \"https://github.com/login/oauth/authorize\",\n upstreamClientId: config.clientId,\n upstreamClientSecret: config.clientSecret,\n upstreamTokenEndpoint: \"https://github.com/login/oauth/access_token\",\n });\n }\n}\n","/**\n * Google OAuth Provider\n * Pre-configured OAuth Proxy for Google Identity Platform\n */\n\nimport type { OAuthProviderConfig } from \"../types.js\";\n\nimport { OAuthProxy } from \"../OAuthProxy.js\";\n\n/**\n * Google OAuth 2.0 Provider\n * Supports Google Sign-In and Google APIs\n */\nexport class GoogleProvider extends OAuthProxy {\n constructor(config: OAuthProviderConfig) {\n super({\n baseUrl: config.baseUrl,\n consentRequired: config.consentRequired,\n scopes: config.scopes || [\"openid\", \"profile\", \"email\"],\n upstreamAuthorizationEndpoint:\n \"https://accounts.google.com/o/oauth2/v2/auth\",\n upstreamClientId: config.clientId,\n upstreamClientSecret: config.clientSecret,\n upstreamTokenEndpoint: \"https://oauth2.googleapis.com/token\",\n });\n }\n}\n","/**\n * Disk-based Token Storage Implementation\n * Provides persistent file-based storage for OAuth tokens and transaction state\n */\n\nimport { mkdir, readdir, readFile, rm, stat, writeFile } from \"fs/promises\";\nimport { join } from \"path\";\n\nimport type { TokenStorage } from \"../types.js\";\n\nexport interface DiskStoreOptions {\n /**\n * How often to run cleanup (in milliseconds)\n * @default 60000 (1 minute)\n */\n cleanupIntervalMs?: number;\n\n /**\n * Directory path for storing data\n */\n directory: string;\n\n /**\n * File extension for stored files\n * @default \".json\"\n */\n fileExtension?: string;\n}\n\ninterface StorageEntry {\n expiresAt: number;\n value: unknown;\n}\n\n/**\n * Disk-based token storage with TTL support\n * Persists tokens to filesystem for survival across server restarts\n */\nexport class DiskStore implements TokenStorage {\n private cleanupInterval: NodeJS.Timeout | null = null;\n private directory: string;\n private fileExtension: string;\n\n constructor(options: DiskStoreOptions) {\n this.directory = options.directory;\n this.fileExtension = options.fileExtension || \".json\";\n\n // Ensure directory exists\n void this.ensureDirectory();\n\n // Start periodic cleanup\n const cleanupIntervalMs = options.cleanupIntervalMs || 60000;\n this.cleanupInterval = setInterval(() => {\n void this.cleanup();\n }, cleanupIntervalMs);\n }\n\n /**\n * Clean up expired entries\n */\n async cleanup(): Promise<void> {\n try {\n await this.ensureDirectory();\n const files = await readdir(this.directory);\n const now = Date.now();\n\n for (const file of files) {\n if (!file.endsWith(this.fileExtension)) {\n continue;\n }\n\n try {\n const filePath = join(this.directory, file);\n const content = await readFile(filePath, \"utf-8\");\n const entry: StorageEntry = JSON.parse(content);\n\n if (entry.expiresAt < now) {\n await rm(filePath);\n }\n } catch (error) {\n // If file is corrupted or can't be read, delete it\n console.warn(`Failed to read/parse file ${file}, deleting:`, error);\n try {\n await rm(join(this.directory, file));\n } catch {\n // Ignore deletion errors\n }\n }\n }\n } catch (error) {\n console.error(\"Cleanup failed:\", error);\n }\n }\n\n /**\n * Delete a value\n */\n async delete(key: string): Promise<void> {\n const filePath = this.getFilePath(key);\n try {\n await rm(filePath);\n } catch (error) {\n // File might not exist, which is fine\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") {\n console.error(`Failed to delete key ${key}:`, error);\n }\n }\n }\n\n /**\n * Destroy the storage and clear cleanup interval\n */\n destroy(): void {\n if (this.cleanupInterval) {\n clearInterval(this.cleanupInterval);\n this.cleanupInterval = null;\n }\n }\n\n /**\n * Retrieve a value\n */\n async get(key: string): Promise<null | unknown> {\n const filePath = this.getFilePath(key);\n\n try {\n const content = await readFile(filePath, \"utf-8\");\n const entry: StorageEntry = JSON.parse(content);\n\n // Check if expired\n if (entry.expiresAt < Date.now()) {\n await rm(filePath);\n return null;\n }\n\n return entry.value;\n } catch (error) {\n // File doesn't exist or is corrupted\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n return null;\n }\n console.error(`Failed to read key ${key}:`, error);\n return null;\n }\n }\n\n /**\n * Save a value with optional TTL\n */\n async save(key: string, value: unknown, ttl?: number): Promise<void> {\n await this.ensureDirectory();\n\n const filePath = this.getFilePath(key);\n const expiresAt = ttl ? Date.now() + ttl * 1000 : Number.MAX_SAFE_INTEGER;\n\n const entry: StorageEntry = {\n expiresAt,\n value,\n };\n\n try {\n await writeFile(filePath, JSON.stringify(entry, null, 2), \"utf-8\");\n } catch (error) {\n console.error(`Failed to save key ${key}:`, error);\n throw error;\n }\n }\n\n /**\n * Get the number of stored items\n */\n async size(): Promise<number> {\n try {\n await this.ensureDirectory();\n const files = await readdir(this.directory);\n return files.filter((f) => f.endsWith(this.fileExtension)).length;\n } catch {\n return 0;\n }\n }\n\n /**\n * Ensure storage directory exists\n */\n private async ensureDirectory(): Promise<void> {\n try {\n const stats = await stat(this.directory);\n if (!stats.isDirectory()) {\n throw new Error(`Path ${this.directory} exists but is not a directory`);\n }\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n await mkdir(this.directory, { recursive: true });\n } else {\n throw error;\n }\n }\n }\n\n /**\n * Get file path for a key\n */\n private getFilePath(key: string): string {\n // Sanitize key to prevent directory traversal\n const sanitizedKey = key.replace(/[^a-zA-Z0-9_-]/g, \"_\");\n return join(this.directory, `${sanitizedKey}${this.fileExtension}`);\n }\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\n/**\n * JWKS (JSON Web Key Set) Verifier\n * Provides JWT verification using public keys from JWKS endpoints\n *\n * Requires the 'jose' package as an optional peer dependency.\n * Install with: npm install jose\n */\n\nimport type { TokenVerificationResult, TokenVerifier } from \"../types.js\";\nimport type { JWTClaims } from \"./jwtIssuer.js\";\n\n/**\n * Token verification result\n */\nexport interface JWKSVerificationResult {\n claims?: JWTClaims;\n error?: string;\n valid: boolean;\n}\n\n/**\n * JWKS configuration options\n */\nexport interface JWKSVerifierConfig {\n /**\n * Expected token audience\n */\n audience?: string;\n\n /**\n * Cache duration for JWKS keys in milliseconds\n * @default 3600000 (1 hour)\n */\n cacheDuration?: number;\n\n /**\n * Cooldown duration between JWKS refetches in milliseconds\n * @default 30000 (30 seconds)\n */\n cooldownDuration?: number;\n\n /**\n * Expected token issuer\n */\n issuer?: string;\n\n /**\n * JWKS endpoint URL (e.g., https://provider.com/.well-known/jwks.json)\n */\n jwksUri: string;\n}\n\n/**\n * JWKS Verifier\n * Verifies JWTs using public keys from a JWKS endpoint\n *\n * This class requires the 'jose' package to be installed:\n * ```bash\n * npm install jose\n * ```\n *\n * @example\n * ```typescript\n * const verifier = new JWKSVerifier({\n * jwksUri: 'https://accounts.google.com/.well-known/jwks.json',\n * audience: 'your-client-id',\n * issuer: 'https://accounts.google.com'\n * });\n *\n * const result = await verifier.verify(token);\n * if (result.valid) {\n * console.log('Token claims:', result.claims);\n * }\n * ```\n */\nexport class JWKSVerifier implements TokenVerifier {\n private config: Required<JWKSVerifierConfig>;\n private jose: any;\n private joseLoaded = false;\n private jwksCache: any;\n\n constructor(config: JWKSVerifierConfig) {\n this.config = {\n cacheDuration: 3600000, // 1 hour\n cooldownDuration: 30000, // 30 seconds\n ...config,\n audience: config.audience || \"\",\n issuer: config.issuer || \"\",\n };\n }\n\n /**\n * Get the JWKS URI being used\n */\n getJwksUri(): string {\n return this.config.jwksUri;\n }\n\n /**\n * Refresh the JWKS cache\n * Useful if you need to force a key refresh\n */\n async refreshKeys(): Promise<void> {\n await this.loadJose();\n\n // Recreate the JWKS cache to force a refresh\n this.jwksCache = this.jose.createRemoteJWKSet(\n new URL(this.config.jwksUri),\n {\n cacheMaxAge: this.config.cacheDuration,\n cooldownDuration: this.config.cooldownDuration,\n },\n );\n }\n\n /**\n * Verify a JWT token using JWKS\n *\n * @param token - The JWT token to verify\n * @returns Verification result with claims if valid\n *\n * @example\n * ```typescript\n * const result = await verifier.verify(token);\n * if (result.valid) {\n * console.log('User:', result.claims?.client_id);\n * } else {\n * console.error('Invalid token:', result.error);\n * }\n * ```\n */\n async verify(token: string): Promise<TokenVerificationResult> {\n try {\n // Ensure jose is loaded\n await this.loadJose();\n\n // Verify the token using JWKS\n const verifyOptions: any = {};\n\n if (this.config.audience) {\n verifyOptions.audience = this.config.audience;\n }\n\n if (this.config.issuer) {\n verifyOptions.issuer = this.config.issuer;\n }\n\n const { payload } = await this.jose.jwtVerify(\n token,\n this.jwksCache,\n verifyOptions,\n );\n\n // Map jose claims to TokenVerificationResult format\n // Store all claims as Record<string, unknown> for compatibility\n const claims: Record<string, unknown> = {\n aud: payload.aud,\n client_id: payload.client_id || payload.sub,\n exp: payload.exp,\n iat: payload.iat,\n iss: payload.iss,\n jti: payload.jti || \"\",\n scope: this.parseScope(payload.scope),\n ...payload, // Include all other claims\n };\n\n return {\n claims,\n valid: true,\n };\n } catch (error: any) {\n return {\n error: error.message || \"Token verification failed\",\n valid: false,\n };\n }\n }\n\n /**\n * Lazy load the jose library\n * Only loads when verification is first attempted\n */\n private async loadJose(): Promise<void> {\n if (this.joseLoaded) {\n return;\n }\n\n try {\n this.jose = await import(\"jose\");\n this.joseLoaded = true;\n\n // Create the JWKS cache with the configured URI\n this.jwksCache = this.jose.createRemoteJWKSet(\n new URL(this.config.jwksUri),\n {\n cacheMaxAge: this.config.cacheDuration,\n cooldownDuration: this.config.cooldownDuration,\n },\n );\n } catch (error: any) {\n throw new Error(\n `JWKS verification requires the 'jose' package.\\n` +\n `Install it with: npm install jose\\n\\n` +\n `If you don't need JWKS support, use HS256 signing instead (default).\\n\\n` +\n `Original error: ${error.message}`,\n );\n }\n }\n\n /**\n * Parse scope from token payload\n * Handles both string (space-separated) and array formats\n */\n private parseScope(scope: unknown): string[] {\n if (!scope) {\n return [];\n }\n\n if (typeof scope === \"string\") {\n return scope.split(\" \").filter(Boolean);\n }\n\n if (Array.isArray(scope)) {\n return scope;\n }\n\n return [];\n }\n}\n"],"mappings":"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","names":["randomBytes","createHmac","randomBytes","randomBytes","randomBytes"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fastmcp",
3
- "version": "3.23.1",
3
+ "version": "3.24.0",
4
4
  "main": "dist/FastMCP.js",
5
5
  "scripts": {
6
6
  "build": "tsup",
@@ -21,6 +21,16 @@
21
21
  "description": "A TypeScript framework for building MCP servers.",
22
22
  "module": "dist/FastMCP.js",
23
23
  "types": "dist/FastMCP.d.ts",
24
+ "exports": {
25
+ ".": {
26
+ "import": "./dist/FastMCP.js",
27
+ "types": "./dist/FastMCP.d.ts"
28
+ },
29
+ "./auth": {
30
+ "import": "./dist/auth/index.js",
31
+ "types": "./dist/auth/index.d.ts"
32
+ }
33
+ },
24
34
  "dependencies": {
25
35
  "@modelcontextprotocol/sdk": "^1.17.2",
26
36
  "@standard-schema/spec": "^1.0.0",
@@ -36,6 +46,14 @@
36
46
  "zod": "^3.25.76",
37
47
  "zod-to-json-schema": "^3.24.6"
38
48
  },
49
+ "peerDependencies": {
50
+ "jose": "^5.0.0"
51
+ },
52
+ "peerDependenciesMeta": {
53
+ "jose": {
54
+ "optional": true
55
+ }
56
+ },
39
57
  "repository": {
40
58
  "url": "https://github.com/punkpeye/fastmcp"
41
59
  },
@@ -85,7 +103,8 @@
85
103
  "tsup": {
86
104
  "entry": [
87
105
  "src/FastMCP.ts",
88
- "src/bin/fastmcp.ts"
106
+ "src/bin/fastmcp.ts",
107
+ "src/auth/index.ts"
89
108
  ],
90
109
  "format": [
91
110
  "esm"