Skip to main content
Glama
auto-login.service.ts7.53 kB
import { Injectable, Logger, OnModuleInit } from '@nestjs/common'; import { AuthService } from './auth.service'; /** * Auto-Login Service * * Automatically authenticates users on server startup using credentials * from environment variables (TIMESHEET_USERNAME and TIMESHEET_PASSWORD). * * This is the ONLY authentication method available. Manual login has been * removed to prevent credential exposure to LLM providers. * * Security Benefits: * - Credentials never exposed to LLM or MCP client * - No credentials in chat logs or request traces * - Configured once in .env or MCP client config * - Auto-login on server startup * * Required Configuration: * - TIMESHEET_USERNAME: User email address * - TIMESHEET_PASSWORD: User password */ @Injectable() export class AutoLoginService implements OnModuleInit { private readonly logger = new Logger(AutoLoginService.name); constructor(private readonly authService: AuthService) {} /** * Lifecycle hook that runs after module initialization * Attempts auto-login if credentials are present in environment */ async onModuleInit() { await this.attemptAutoLogin(); } /** * Attempts to auto-login using environment variables * * Reads TIMESHEET_USERNAME and TIMESHEET_PASSWORD from environment. * If both are present, attempts authentication with backend API. * * Fails silently if: * - Environment variables not set * - Authentication fails * - User already authenticated * * This allows fallback to manual login tool if needed. */ private async attemptAutoLogin(): Promise<void> { try { // Check if user is already authenticated try { const existingToken = this.authService.getToken(); if (existingToken) { this.logger.log('User already authenticated (existing token found)'); const currentUser = this.authService.getCurrentUser(); if (currentUser) { this.logger.log( `Authenticated as: ${currentUser.name} (${currentUser.username})`, ); } return; } } catch (error) { // No existing token, proceed with auto-login attempt this.logger.log('No existing authentication found, attempting auto-login...'); } // Read credentials from environment variables const username = process.env.TIMESHEET_USERNAME; const password = process.env.TIMESHEET_PASSWORD; // Debug logging to help diagnose configuration issues this.logger.debug(`Environment check - TIMESHEET_USERNAME present: ${!!username}`); this.logger.debug(`Environment check - TIMESHEET_PASSWORD present: ${!!password}`); // Credentials are required - no fallback available if (!username || !password) { this.logger.warn( '⚠️ Authentication required: TIMESHEET_USERNAME or TIMESHEET_PASSWORD not set', ); this.logger.warn( '⚠️ Please configure credentials in your MCP server configuration (env section)', ); this.logger.warn( '⚠️ Example MCP config:', ); this.logger.warn( ' "timesheet-mcp": {', ); this.logger.warn( ' "command": "node",', ); this.logger.warn( ' "args": ["path/to/dist/main.js"],', ); this.logger.warn( ' "env": {', ); this.logger.warn( ' "TIMESHEET_USERNAME": "your.email@company.com",', ); this.logger.warn( ' "TIMESHEET_PASSWORD": "your-password"', ); this.logger.warn( ' }', ); this.logger.warn( ' }', ); this.logger.warn( '⚠️ Server will start but most tools will require authentication', ); return; } // Validate credentials format if (!this.isValidEmail(username)) { this.logger.warn( `Auto-login skipped: TIMESHEET_USERNAME is not a valid email format`, ); return; } if (password.length < 1) { this.logger.warn( 'Auto-login skipped: TIMESHEET_PASSWORD is empty', ); return; } // Attempt login this.logger.log(`Attempting auto-login for user: ${username}`); const result = await this.authService.login(username, password); if (result.success && result.user) { this.logger.log( `✓ Auto-login successful: ${result.user.name} (${result.user.username})`, ); this.logger.log( `User roles: ${result.user.roles?.join(', ') || 'No roles'}`, ); // Attempt automatic project/module configuration if (result.user?.id) { try { const autoConfigResult = await this.authService.autoConfigureUserAssignments( result.user.id, ); if (autoConfigResult.configured) { this.logger.log(`✓ ${autoConfigResult.message}`); if (autoConfigResult.project) { this.logger.log( ` Project: ${autoConfigResult.project.name} (ID: ${autoConfigResult.project.id})`, ); } if (autoConfigResult.modules && autoConfigResult.modules.length > 0) { const moduleNames = autoConfigResult.modules .map((m) => m.name) .join(', '); this.logger.log( ` Modules (${autoConfigResult.modules.length}): ${moduleNames}`, ); } } else if (autoConfigResult.success) { // Not configured but no error (e.g., multiple projects) this.logger.warn(`⚠️ ${autoConfigResult.message}`); } else { // Configuration failed this.logger.warn( `⚠️ Auto-configuration failed: ${autoConfigResult.message}`, ); this.logger.warn( ` Use quick_configure tool to configure manually`, ); } } catch (error) { this.logger.warn( `⚠️ Auto-configuration error: ${error.message}`, ); this.logger.warn(` Use quick_configure tool to configure manually`); } } else { // Fallback to old configuration check if (result.needsConfiguration) { this.logger.warn( '⚠️ Configuration needed: Use quick_configure tool', ); } else { this.logger.log('✓ User configuration complete'); } } } else { this.logger.error( `Auto-login failed: Invalid credentials or authentication error`, ); this.logger.error( 'Please check your TIMESHEET_USERNAME and TIMESHEET_PASSWORD', ); } } catch (error) { // Log error but don't throw - allow server to start even if auto-login fails this.logger.error( `Auto-login error: ${error.message}`, ); this.logger.error( 'Please verify your credentials and API connection', ); } } /** * Validates email format * Simple regex check for basic email validation */ private isValidEmail(email: string): boolean { const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; return emailRegex.test(email); } }

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/arshad-khan1/Timesheet-mcp'

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