Security Considerations

Critical security practices for authentication automation

Authentication automation introduces security risks that must be carefully managed.

Credential Storage Best Practices

Never Hardcode Credentials

Critical Security Requirement: Never hardcode credentials in source code. Always use environment variables or secure credential stores.

// BAD - credentials in code
const credentials = {
  username: 'jane@university.edu',
  password: 'MyPassword123'
};

// GOOD - credentials from environment
const credentials = {
  username: process.env.UNIVERSITY_USERNAME,
  password: process.env.UNIVERSITY_PASSWORD
};

Use Secure Credential Stores

For production use, integrate with OS credential managers:

import keytar from 'keytar';

// Store credential
await keytar.setPassword('auth-mcp', 'university-library', password);

// Retrieve credential
const password = await keytar.getPassword('auth-mcp', 'university-library');

Environment Variable Protection

# Set secure permissions on .env
chmod 600 .env

# Never commit .env
echo ".env" >> .gitignore

# Use .env.example for documentation
cp .env .env.example
# Remove sensitive values from .env.example

Encryption At Rest

All saved state contains sensitive session cookies.

Encryption Implementation

Best Practice: State files use AES-256-CBC encryption with unique IV per file and scrypt-derived keys for brute-force resistance.

Key Management:

# Generate strong encryption key
openssl rand -hex 32 > .encryption_key
chmod 400 .encryption_key

# Use in environment
export STATE_ENCRYPTION_KEY=$(cat .encryption_key)

File Permissions:

# Restrict state directory
chmod 700 state/

# Restrict state files
chmod 600 state/*.encrypted.json

# Verify permissions
ls -la state/
# Should show: drwx------  (directory)
#             -rw-------   (files)

Never Commit Secrets

.gitignore Essentials

# Credentials
.env
.env.local
*.key

# State files
state/
*.encrypted.json

# Sensitive configs
config.json

# Logs may contain sensitive data
*.log
logs/

# Playwright artifacts
playwright-report/
test-results/

Pre-commit Hook

#!/bin/bash
# .git/hooks/pre-commit

# Check for potential secrets
if git diff --cached --name-only | xargs grep -l "password\|secret\|token" > /dev/null; then
  echo "Warning: Potential secrets detected!"
  echo "Review changes carefully before committing."
  exit 1
fi

Audit Logging

Track all authentication operations for security review:

class AuditLogger {
  constructor(logFile) {
    this.logFile = logFile;
  }

  async log(event, details) {
    const entry = {
      timestamp: new Date().toISOString(),
      event,
      details,
      user: process.env.USER,
      hostname: require('os').hostname()
    };

    await fs.appendFile(
      this.logFile,
      JSON.stringify(entry) + '\n'
    );
  }
}

// Usage in authenticate():
await auditLogger.log('authentication_attempt', {
  site,
  strategy,
  success: result.success
});

Log Rotation

// Rotate logs monthly
const logFile = `logs/audit-${new Date().toISOString().slice(0, 7)}.log`;

Review Logs

# Check recent auth attempts
tail -50 logs/audit-*.log | jq .

# Count authentications by site
cat logs/audit-*.log | jq -r '.details.site' | sort | uniq -c

Rate Limiting

Prevent Account Lockouts: Implement rate limiting to avoid triggering account security measures from repeated authentication attempts.

class RateLimiter {
  constructor() {
    this.attempts = new Map();
  }

  canAttempt(site) {
    const key = site;
    const now = Date.now();
    const attempts = this.attempts.get(key) || [];

    // Remove attempts older than 1 hour
    const recentAttempts = attempts.filter(t => now - t < 3600000);

    // Max 5 attempts per hour
    if (recentAttempts.length >= 5) {
      return false;
    }

    recentAttempts.push(now);
    this.attempts.set(key, recentAttempts);
    return true;
  }

  getRetryAfter(site) {
    const attempts = this.attempts.get(site) || [];
    if (attempts.length === 0) return 0;

    const oldestAttempt = Math.min(...attempts);
    const resetTime = oldestAttempt + 3600000; // 1 hour from oldest
    return Math.max(0, resetTime - Date.now());
  }
}

// Usage:
if (!rateLimiter.canAttempt(site)) {
  const retryAfter = rateLimiter.getRetryAfter(site);
  throw new Error(`Rate limit exceeded. Retry after ${retryAfter}ms`);
}

Additional Security Measures

Network Security

Critical Requirements: Always use HTTPS for authentication endpoints, validate TLS certificates (never disable verification), and consider VPN for institutional access.

Session Security

Implement robust session management practices:

  • Implement session timeout tracking
  • Clear sessions after extended inactivity
  • Re-authenticate periodically (don't rely on indefinite sessions)

Access Control

Principle of Least Privilege: Run MCP server with minimal privileges, use separate system user for automation if possible, and restrict file access to owner only.

Monitoring

Establish proactive security monitoring:

  • Watch for unusual authentication patterns
  • Alert on repeated failures
  • Track session usage frequency

Incident Response

Prepare for Compromise: Have documented procedures for compromised credentials, know how to revoke access quickly, and maintain backup authentication methods.