@gohcltech/bitbucket-mcp
Version:
Bitbucket integration for Claude via Model Context Protocol
214 lines • 8.1 kB
JavaScript
/**
* @fileoverview Authentication service for token-based Bitbucket API authentication.
*
* This module provides a simple, stateless authentication service that supports
* two methods of authentication:
* 1. API Token Authentication (HTTP Basic Auth with username + token)
* 2. Repository Token Authentication (Bearer token)
*
* Unlike the v1.0 OAuth service, this implementation:
* - Does not require token refresh (tokens don't expire)
* - Uses simple HTTP Basic Auth or Bearer token authentication
* - No persistent web server or callback handling needed
* - Stateless and efficient
*/
import { AuthMethod } from './types.js';
import { AuthCapabilities } from './auth-capabilities.js';
/**
* Simple, stateless authentication service for token-based Bitbucket API access.
*
* Supports dual authentication methods without needing token refresh or persistent storage.
* All methods are pure functions that generate auth headers from the configured credentials.
*
* @example
* ```typescript
* const authConfig = ConfigManager.getInstance().getAuthConfig();
* const authService = new AuthService(authConfig);
* const authHeader = authService.getAuthHeader();
* // Use authHeader in API requests: headers[authHeader.name] = authHeader.value
* ```
*/
export class AuthService {
config;
capabilities;
/**
* Creates a new AuthService instance.
*
* @param config - Authentication configuration (from ConfigManager)
* @throws {Error} If configuration is invalid
*/
constructor(config) {
if (!config) {
throw new Error('Authentication configuration is required');
}
this.config = config;
this.capabilities = new AuthCapabilities(config);
}
/**
* Gets the authentication header for API requests.
*
* Returns the appropriate header based on the configured authentication method:
* - API Token: Returns HTTP Basic Auth header (username:token in base64)
* - Repository Token: Returns Bearer token header
*
* @returns Authorization header object with name and value
* @throws {Error} If authentication method is not properly configured
*/
getAuthHeader() {
switch (this.config.method) {
case AuthMethod.API_TOKEN:
return this.getBasicAuthHeader();
case AuthMethod.REPOSITORY_TOKEN:
return this.getBearerAuthHeader();
default:
throw new Error(`Unknown authentication method: ${this.config.method}`);
}
}
/**
* Gets HTTP Basic Auth header for API Token authentication.
*
* API Token authentication uses HTTP Basic Auth with username and API token.
* The format is: Authorization: Basic base64(username:apiToken)
*
* @private
* @returns Authorization header with Basic auth value
* @throws {Error} If API token credentials are missing
*/
getBasicAuthHeader() {
if (this.config.method !== AuthMethod.API_TOKEN) {
throw new Error('Invalid authentication method for Basic Auth');
}
const username = this.config.username;
const apiToken = this.config.apiToken;
if (!username || !apiToken) {
throw new Error('Username and API token are required for API Token authentication');
}
// Create Basic Auth header: base64(username:apiToken)
const credentials = `${username}:${apiToken}`;
const encodedCredentials = Buffer.from(credentials).toString('base64');
return {
name: 'Authorization',
value: `Basic ${encodedCredentials}`,
};
}
/**
* Gets Bearer token header for Repository Token authentication.
*
* Repository Token authentication uses Bearer token authentication.
* The format is: Authorization: Bearer <repositoryToken>
*
* @private
* @returns Authorization header with Bearer token value
* @throws {Error} If repository token is missing
*/
getBearerAuthHeader() {
if (this.config.method !== AuthMethod.REPOSITORY_TOKEN) {
throw new Error('Invalid authentication method for Bearer Auth');
}
const repositoryToken = this.config.repositoryToken;
if (!repositoryToken) {
throw new Error('Repository token is required for Repository Token authentication');
}
return {
name: 'Authorization',
value: `Bearer ${repositoryToken}`,
};
}
/**
* Gets the current authentication method being used.
*
* @returns The configured authentication method (API_TOKEN or REPOSITORY_TOKEN)
*/
getAuthMethod() {
return this.config.method;
}
/**
* Gets the configured workspace (if any).
*
* The workspace is an optional configuration that can be used as a default
* workspace for API requests when not otherwise specified.
*
* @returns The configured workspace name, or undefined if not set
*/
getWorkspace() {
return this.config.workspace;
}
/**
* Gets a human-readable description of the current authentication configuration.
*
* Useful for logging and debugging without exposing sensitive credentials.
* Credentials are masked in the output.
*
* @returns Description of authentication configuration (credentials redacted)
*/
getAuthDescription() {
switch (this.config.method) {
case AuthMethod.API_TOKEN:
return `API Token (username: ${this.config.username}, token: [REDACTED])`;
case AuthMethod.REPOSITORY_TOKEN:
return 'Repository Token ([REDACTED])';
default:
return 'Unknown authentication method';
}
}
/**
* Validates that the authentication configuration is properly set up.
*
* This is a basic validation to ensure required fields are present.
* More thorough validation (actual token validity) should be done by TokenValidator.
*
* @returns Object with isValid flag and error messages (if any)
*/
validate() {
const errors = [];
if (!this.config) {
errors.push('Authentication configuration is missing');
return { isValid: false, errors };
}
switch (this.config.method) {
case AuthMethod.API_TOKEN:
if (!this.config.username) {
errors.push('Username is required for API Token authentication');
}
if (!this.config.apiToken) {
errors.push('API token is required for API Token authentication');
}
if (this.config.apiToken && this.config.apiToken.length < 20) {
errors.push('API token appears to be too short (minimum 20 characters)');
}
break;
case AuthMethod.REPOSITORY_TOKEN:
if (!this.config.repositoryToken) {
errors.push('Repository token is required for Repository Token authentication');
}
break;
default:
errors.push(`Unknown authentication method: ${this.config.method}`);
}
return {
isValid: errors.length === 0,
errors,
};
}
/**
* Gets the authentication capabilities for this service.
*
* Capabilities determine which tools and features are available based on
* the authentication method and its associated permissions.
*
* @returns AuthCapabilities instance with available capabilities and tool access
*/
getCapabilities() {
return this.capabilities;
}
}
/**
* Convenience function to create an AuthService from configuration.
*
* @param config - Authentication configuration
* @returns Initialized AuthService instance
*/
export function createAuthService(config) {
return new AuthService(config);
}
//# sourceMappingURL=auth-service.js.map