buroventures-harald-code-core
Version:
Harald Code Core - Core functionality for AI-powered coding assistant
183 lines • 7.39 kB
JavaScript
/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import { getErrorMessage } from '../utils/errors.js';
/**
* Utility class for common OAuth operations.
*/
export class OAuthUtils {
/**
* Construct well-known OAuth endpoint URLs.
*/
static buildWellKnownUrls(baseUrl) {
const serverUrl = new URL(baseUrl);
const base = `${serverUrl.protocol}//${serverUrl.host}`;
return {
protectedResource: new URL('/.well-known/oauth-protected-resource', base).toString(),
authorizationServer: new URL('/.well-known/oauth-authorization-server', base).toString(),
};
}
/**
* Fetch OAuth protected resource metadata.
*
* @param resourceMetadataUrl The protected resource metadata URL
* @returns The protected resource metadata or null if not available
*/
static async fetchProtectedResourceMetadata(resourceMetadataUrl) {
try {
const response = await fetch(resourceMetadataUrl);
if (!response.ok) {
return null;
}
return (await response.json());
}
catch (error) {
console.debug(`Failed to fetch protected resource metadata from ${resourceMetadataUrl}: ${getErrorMessage(error)}`);
return null;
}
}
/**
* Fetch OAuth authorization server metadata.
*
* @param authServerMetadataUrl The authorization server metadata URL
* @returns The authorization server metadata or null if not available
*/
static async fetchAuthorizationServerMetadata(authServerMetadataUrl) {
try {
const response = await fetch(authServerMetadataUrl);
if (!response.ok) {
return null;
}
return (await response.json());
}
catch (error) {
console.debug(`Failed to fetch authorization server metadata from ${authServerMetadataUrl}: ${getErrorMessage(error)}`);
return null;
}
}
/**
* Convert authorization server metadata to OAuth configuration.
*
* @param metadata The authorization server metadata
* @returns The OAuth configuration
*/
static metadataToOAuthConfig(metadata) {
return {
authorizationUrl: metadata.authorization_endpoint,
tokenUrl: metadata.token_endpoint,
scopes: metadata.scopes_supported || [],
};
}
/**
* Discover OAuth configuration using the standard well-known endpoints.
*
* @param serverUrl The base URL of the server
* @returns The discovered OAuth configuration or null if not available
*/
static async discoverOAuthConfig(serverUrl) {
try {
const wellKnownUrls = this.buildWellKnownUrls(serverUrl);
// First, try to get the protected resource metadata
const resourceMetadata = await this.fetchProtectedResourceMetadata(wellKnownUrls.protectedResource);
if (resourceMetadata?.authorization_servers?.length) {
// Use the first authorization server
const authServerUrl = resourceMetadata.authorization_servers[0];
const authServerMetadataUrl = new URL('/.well-known/oauth-authorization-server', authServerUrl).toString();
const authServerMetadata = await this.fetchAuthorizationServerMetadata(authServerMetadataUrl);
if (authServerMetadata) {
const config = this.metadataToOAuthConfig(authServerMetadata);
if (authServerMetadata.registration_endpoint) {
console.log('Dynamic client registration is supported at:', authServerMetadata.registration_endpoint);
}
return config;
}
}
// Fallback: try /.well-known/oauth-authorization-server at the base URL
console.debug(`Trying OAuth discovery fallback at ${wellKnownUrls.authorizationServer}`);
const authServerMetadata = await this.fetchAuthorizationServerMetadata(wellKnownUrls.authorizationServer);
if (authServerMetadata) {
const config = this.metadataToOAuthConfig(authServerMetadata);
if (authServerMetadata.registration_endpoint) {
console.log('Dynamic client registration is supported at:', authServerMetadata.registration_endpoint);
}
return config;
}
return null;
}
catch (error) {
console.debug(`Failed to discover OAuth configuration: ${getErrorMessage(error)}`);
return null;
}
}
/**
* Parse WWW-Authenticate header to extract OAuth information.
*
* @param header The WWW-Authenticate header value
* @returns The resource metadata URI if found
*/
static parseWWWAuthenticateHeader(header) {
// Parse Bearer realm and resource_metadata
const match = header.match(/resource_metadata="([^"]+)"/);
if (match) {
return match[1];
}
return null;
}
/**
* Discover OAuth configuration from WWW-Authenticate header.
*
* @param wwwAuthenticate The WWW-Authenticate header value
* @returns The discovered OAuth configuration or null if not available
*/
static async discoverOAuthFromWWWAuthenticate(wwwAuthenticate) {
const resourceMetadataUri = this.parseWWWAuthenticateHeader(wwwAuthenticate);
if (!resourceMetadataUri) {
return null;
}
console.log(`Found resource metadata URI from www-authenticate header: ${resourceMetadataUri}`);
const resourceMetadata = await this.fetchProtectedResourceMetadata(resourceMetadataUri);
if (!resourceMetadata?.authorization_servers?.length) {
return null;
}
const authServerUrl = resourceMetadata.authorization_servers[0];
const authServerMetadataUrl = new URL('/.well-known/oauth-authorization-server', authServerUrl).toString();
const authServerMetadata = await this.fetchAuthorizationServerMetadata(authServerMetadataUrl);
if (authServerMetadata) {
console.log('OAuth configuration discovered successfully from www-authenticate header');
return this.metadataToOAuthConfig(authServerMetadata);
}
return null;
}
/**
* Extract base URL from an MCP server URL.
*
* @param mcpServerUrl The MCP server URL
* @returns The base URL
*/
static extractBaseUrl(mcpServerUrl) {
const serverUrl = new URL(mcpServerUrl);
return `${serverUrl.protocol}//${serverUrl.host}`;
}
/**
* Check if a URL is an SSE endpoint.
*
* @param url The URL to check
* @returns True if the URL appears to be an SSE endpoint
*/
static isSSEEndpoint(url) {
return url.includes('/sse') || !url.includes('/mcp');
}
/**
* Build a resource parameter for OAuth requests.
*
* @param endpointUrl The endpoint URL
* @returns The resource parameter value
*/
static buildResourceParameter(endpointUrl) {
const url = new URL(endpointUrl);
return `${url.protocol}//${url.host}`;
}
}
//# sourceMappingURL=oauth-utils.js.map