Skip to main content
Glama
jakedx6
by jakedx6
auth.js5.92 kB
import { apiClient } from './api-client.js'; import { logger } from './logger.js'; import { UnauthorizedError } from './api-client.js'; export class AuthManager { constructor() { this.authContext = null; } static getInstance() { if (!AuthManager.instance) { AuthManager.instance = new AuthManager(); } return AuthManager.instance; } /** * Authenticate with various methods */ async authenticate(method, credentials) { try { switch (method) { case 'token': return await this.authenticateWithToken(credentials); case 'api_key': return await this.authenticateWithApiKey(credentials); default: throw new UnauthorizedError('Invalid authentication method'); } } catch (error) { logger.error('Authentication failed:', error); throw error; } } /** * Authenticate with user session token (legacy - not used with API) */ async authenticateWithToken(accessToken) { throw new UnauthorizedError('Token authentication not supported in API mode. Use API key authentication.'); } /** * Authenticate with API key via Helios-9 API */ async authenticateWithApiKey(apiKey) { // Set the API key in the client process.env.HELIOS_API_KEY = apiKey; // For MCP API keys (hel9_*), we skip the auth/validate endpoint // since MCP endpoints handle their own authentication if (apiKey.startsWith('hel9_')) { logger.info('MCP API key detected, using MCP authentication mode'); // Create a context that will be populated from API responses this.authContext = { userId: 'mcp-pending', // Will be updated from first API response tenantId: null, profile: { id: 'mcp-pending', email: 'mcp@helios9.app', full_name: 'MCP Service Account', avatar_url: null, created_at: new Date().toISOString(), updated_at: new Date().toISOString(), username: 'mcp-service', tenant_id: null }, authenticated: true }; logger.info('MCP authentication context created'); return this.authContext; } // For other API keys, validate normally const profile = await apiClient.authenticate(); this.authContext = { userId: profile.id, tenantId: profile.tenant_id || null, profile, authenticated: true }; logger.info(`Service authenticated via API key for user: ${profile.email}`); return this.authContext; } /** * Get current auth context */ getAuthContext() { if (!this.authContext || !this.authContext.authenticated) { throw new UnauthorizedError('No authenticated session'); } return this.authContext; } /** * Check if authenticated */ isAuthenticated() { return this.authContext?.authenticated ?? false; } /** * Ensure authenticated before API calls */ async ensureAuthenticated() { if (this.isAuthenticated()) { return this.authContext; } // Try to authenticate with API key if available const apiKey = process.env.HELIOS_API_KEY; if (!apiKey) { throw new UnauthorizedError('HELIOS_API_KEY environment variable is required'); } return await this.authenticate('api_key', apiKey); } /** * Clear authentication */ clearAuth() { this.authContext = null; logger.info('Authentication cleared'); } /** * Middleware for MCP operations that require authentication */ requireAuth(operation) { return async (...args) => { if (!this.isAuthenticated()) { throw new UnauthorizedError('Authentication required for this operation'); } return operation(...args); }; } /** * Get rate limiting info for current user */ getRateLimitInfo() { // Basic rate limiting - in production, you'd implement proper rate limiting const isServiceAccount = this.authContext?.profile?.email?.includes('mcp-service'); return { limit: isServiceAccount ? 1000 : 100, // requests per window window: 3600, // 1 hour in seconds current: 0 // would track actual usage }; } /** * Validate permissions for specific operations */ async validatePermission(resource, action, resourceId) { const context = this.getAuthContext(); // Admin role can do everything if (context.profile.role === 'admin') { return true; } // Basic permission checks switch (resource) { case 'project': return action === 'read' || action === 'create' || context.userId === resourceId; case 'task': case 'document': // For tasks and documents, check project ownership through the API service return true; // Simplified - actual checks happen in API service default: return false; } } } // Export singleton instance export const authManager = AuthManager.getInstance(); // Helper function for authentication export async function authenticate(method, credentials) { return authManager.authenticate(method, credentials); } // Helper function to require authentication export function requireAuth(operation) { return authManager.requireAuth(operation); }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/jakedx6/helios9-MCP-Server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server