| "use strict"; |
| var __importDefault = (this && this.__importDefault) || function (mod) { |
| return (mod && mod.__esModule) ? mod : { "default": mod }; |
| }; |
| Object.defineProperty(exports, "__esModule", { value: true }); |
| exports.UnauthorizedError = void 0; |
| exports.auth = auth; |
| exports.discoverOAuthMetadata = discoverOAuthMetadata; |
| exports.startAuthorization = startAuthorization; |
| exports.exchangeAuthorization = exchangeAuthorization; |
| exports.refreshAuthorization = refreshAuthorization; |
| exports.registerClient = registerClient; |
| const pkce_challenge_1 = __importDefault(require("pkce-challenge")); |
| const types_js_1 = require("../types.js"); |
| const auth_js_1 = require("../shared/auth.js"); |
| class UnauthorizedError extends Error { |
| constructor(message) { |
| super(message !== null && message !== void 0 ? message : "Unauthorized"); |
| } |
| } |
| exports.UnauthorizedError = UnauthorizedError; |
| |
| |
| |
| |
| |
| |
| async function auth(provider, { serverUrl, authorizationCode }) { |
| const metadata = await discoverOAuthMetadata(serverUrl); |
| |
| let clientInformation = await Promise.resolve(provider.clientInformation()); |
| if (!clientInformation) { |
| if (authorizationCode !== undefined) { |
| throw new Error("Existing OAuth client information is required when exchanging an authorization code"); |
| } |
| if (!provider.saveClientInformation) { |
| throw new Error("OAuth client information must be saveable for dynamic registration"); |
| } |
| const fullInformation = await registerClient(serverUrl, { |
| metadata, |
| clientMetadata: provider.clientMetadata, |
| }); |
| await provider.saveClientInformation(fullInformation); |
| clientInformation = fullInformation; |
| } |
| |
| if (authorizationCode !== undefined) { |
| const codeVerifier = await provider.codeVerifier(); |
| const tokens = await exchangeAuthorization(serverUrl, { |
| metadata, |
| clientInformation, |
| authorizationCode, |
| codeVerifier, |
| redirectUri: provider.redirectUrl, |
| }); |
| await provider.saveTokens(tokens); |
| return "AUTHORIZED"; |
| } |
| const tokens = await provider.tokens(); |
| |
| if (tokens === null || tokens === void 0 ? void 0 : tokens.refresh_token) { |
| try { |
| |
| const newTokens = await refreshAuthorization(serverUrl, { |
| metadata, |
| clientInformation, |
| refreshToken: tokens.refresh_token, |
| }); |
| await provider.saveTokens(newTokens); |
| return "AUTHORIZED"; |
| } |
| catch (error) { |
| console.error("Could not refresh OAuth tokens:", error); |
| } |
| } |
| |
| const { authorizationUrl, codeVerifier } = await startAuthorization(serverUrl, { |
| metadata, |
| clientInformation, |
| redirectUrl: provider.redirectUrl |
| }); |
| await provider.saveCodeVerifier(codeVerifier); |
| await provider.redirectToAuthorization(authorizationUrl); |
| return "REDIRECT"; |
| } |
| |
| |
| |
| |
| |
| |
| async function discoverOAuthMetadata(serverUrl, opts) { |
| var _a; |
| const url = new URL("/.well-known/oauth-authorization-server", serverUrl); |
| let response; |
| try { |
| response = await fetch(url, { |
| headers: { |
| "MCP-Protocol-Version": (_a = opts === null || opts === void 0 ? void 0 : opts.protocolVersion) !== null && _a !== void 0 ? _a : types_js_1.LATEST_PROTOCOL_VERSION |
| } |
| }); |
| } |
| catch (error) { |
| |
| if (error instanceof TypeError) { |
| response = await fetch(url); |
| } |
| else { |
| throw error; |
| } |
| } |
| if (response.status === 404) { |
| return undefined; |
| } |
| if (!response.ok) { |
| throw new Error(`HTTP ${response.status} trying to load well-known OAuth metadata`); |
| } |
| return auth_js_1.OAuthMetadataSchema.parse(await response.json()); |
| } |
| |
| |
| |
| async function startAuthorization(serverUrl, { metadata, clientInformation, redirectUrl, }) { |
| const responseType = "code"; |
| const codeChallengeMethod = "S256"; |
| let authorizationUrl; |
| if (metadata) { |
| authorizationUrl = new URL(metadata.authorization_endpoint); |
| if (!metadata.response_types_supported.includes(responseType)) { |
| throw new Error(`Incompatible auth server: does not support response type ${responseType}`); |
| } |
| if (!metadata.code_challenge_methods_supported || |
| !metadata.code_challenge_methods_supported.includes(codeChallengeMethod)) { |
| throw new Error(`Incompatible auth server: does not support code challenge method ${codeChallengeMethod}`); |
| } |
| } |
| else { |
| authorizationUrl = new URL("/authorize", serverUrl); |
| } |
| |
| const challenge = await (0, pkce_challenge_1.default)(); |
| const codeVerifier = challenge.code_verifier; |
| const codeChallenge = challenge.code_challenge; |
| authorizationUrl.searchParams.set("response_type", responseType); |
| authorizationUrl.searchParams.set("client_id", clientInformation.client_id); |
| authorizationUrl.searchParams.set("code_challenge", codeChallenge); |
| authorizationUrl.searchParams.set("code_challenge_method", codeChallengeMethod); |
| authorizationUrl.searchParams.set("redirect_uri", String(redirectUrl)); |
| return { authorizationUrl, codeVerifier }; |
| } |
| |
| |
| |
| async function exchangeAuthorization(serverUrl, { metadata, clientInformation, authorizationCode, codeVerifier, redirectUri, }) { |
| const grantType = "authorization_code"; |
| let tokenUrl; |
| if (metadata) { |
| tokenUrl = new URL(metadata.token_endpoint); |
| if (metadata.grant_types_supported && |
| !metadata.grant_types_supported.includes(grantType)) { |
| throw new Error(`Incompatible auth server: does not support grant type ${grantType}`); |
| } |
| } |
| else { |
| tokenUrl = new URL("/token", serverUrl); |
| } |
| |
| const params = new URLSearchParams({ |
| grant_type: grantType, |
| client_id: clientInformation.client_id, |
| code: authorizationCode, |
| code_verifier: codeVerifier, |
| redirect_uri: String(redirectUri), |
| }); |
| if (clientInformation.client_secret) { |
| params.set("client_secret", clientInformation.client_secret); |
| } |
| const response = await fetch(tokenUrl, { |
| method: "POST", |
| headers: { |
| "Content-Type": "application/x-www-form-urlencoded", |
| }, |
| body: params, |
| }); |
| if (!response.ok) { |
| throw new Error(`Token exchange failed: HTTP ${response.status}`); |
| } |
| return auth_js_1.OAuthTokensSchema.parse(await response.json()); |
| } |
| |
| |
| |
| async function refreshAuthorization(serverUrl, { metadata, clientInformation, refreshToken, }) { |
| const grantType = "refresh_token"; |
| let tokenUrl; |
| if (metadata) { |
| tokenUrl = new URL(metadata.token_endpoint); |
| if (metadata.grant_types_supported && |
| !metadata.grant_types_supported.includes(grantType)) { |
| throw new Error(`Incompatible auth server: does not support grant type ${grantType}`); |
| } |
| } |
| else { |
| tokenUrl = new URL("/token", serverUrl); |
| } |
| |
| const params = new URLSearchParams({ |
| grant_type: grantType, |
| client_id: clientInformation.client_id, |
| refresh_token: refreshToken, |
| }); |
| if (clientInformation.client_secret) { |
| params.set("client_secret", clientInformation.client_secret); |
| } |
| const response = await fetch(tokenUrl, { |
| method: "POST", |
| headers: { |
| "Content-Type": "application/x-www-form-urlencoded", |
| }, |
| body: params, |
| }); |
| if (!response.ok) { |
| throw new Error(`Token refresh failed: HTTP ${response.status}`); |
| } |
| return auth_js_1.OAuthTokensSchema.parse(await response.json()); |
| } |
| |
| |
| |
| async function registerClient(serverUrl, { metadata, clientMetadata, }) { |
| let registrationUrl; |
| if (metadata) { |
| if (!metadata.registration_endpoint) { |
| throw new Error("Incompatible auth server: does not support dynamic client registration"); |
| } |
| registrationUrl = new URL(metadata.registration_endpoint); |
| } |
| else { |
| registrationUrl = new URL("/register", serverUrl); |
| } |
| const response = await fetch(registrationUrl, { |
| method: "POST", |
| headers: { |
| "Content-Type": "application/json", |
| }, |
| body: JSON.stringify(clientMetadata), |
| }); |
| if (!response.ok) { |
| throw new Error(`Dynamic client registration failed: HTTP ${response.status}`); |
| } |
| return auth_js_1.OAuthClientInformationFullSchema.parse(await response.json()); |
| } |
| |