* - X-API-Key: * - Query parameter: ?api_key= (dev only) */ /** * Check if request is authenticated * * @return bool True if authenticated, false otherwise */ function authenticate() { // Development mode: allow localhost without auth if (isDevelopmentMode()) { return true; } $api_key = extractApiKey(); if (!$api_key) { return false; } // Validate against configured keys $valid_keys = getValidApiKeys(); return in_array($api_key, $valid_keys, true); } /** * Check if running in development mode (localhost) * * @return bool True if development mode */ function isDevelopmentMode() { $host = $_SERVER['HTTP_HOST'] ?? $_SERVER['SERVER_NAME'] ?? 'unknown'; // Allow localhost and 127.0.0.1 without auth return in_array($host, ['localhost:8000', 'localhost', '127.0.0.1:8000', '127.0.0.1']); } /** * Extract API key from request * * Checks multiple sources in order of security: * 1. Authorization: Bearer header * 2. X-API-Key header * 3. Query parameter (least secure, for dev only) * * @return string|null API key or null if not found */ function extractApiKey() { // Check Authorization: Bearer header if (isset($_SERVER['HTTP_AUTHORIZATION'])) { if (preg_match('/Bearer\s+(.*)$/i', $_SERVER['HTTP_AUTHORIZATION'], $matches)) { return trim($matches[1]); } } // Check X-API-Key header if (isset($_SERVER['HTTP_X_API_KEY'])) { return trim($_SERVER['HTTP_X_API_KEY']); } // Check query parameter (least secure) if (isset($_GET['api_key'])) { return trim($_GET['api_key']); } return null; } /** * Get list of valid API keys * * Loads keys from: * 1. Environment variable API_KEY * 2. .api_keys file (one key per line) * 3. Default dev key (for development only) * * @return array List of valid API keys */ function getValidApiKeys() { $keys = []; // Load from environment variable $env_key = getenv('API_KEY'); if ($env_key) { $keys[] = $env_key; } // Load from .api_keys file $config_file = __DIR__ . '/.api_keys'; if (file_exists($config_file)) { $file_keys = file($config_file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); if ($file_keys) { // Filter out comments and empty lines $file_keys = array_filter($file_keys, function($line) { $line = trim($line); return $line && substr($line, 0, 1) !== '#'; }); $keys = array_merge($keys, array_values($file_keys)); } } // Fallback to dev key if no keys configured (DEV MODE ONLY) if (empty($keys)) { error_log("WARNING: Using default dev API key. Configure proper API keys for production!"); $keys[] = 'dev_key_12345'; } return array_unique($keys); } /** * Send error response and exit * * @param string $message Error message * @param int $status_code HTTP status code */ function sendUnauthorizedResponse($message = "Unauthorized", $status_code = 401) { http_response_code($status_code); header('Content-Type: application/json'); header('WWW-Authenticate: Bearer realm="API"'); echo json_encode([ 'success' => false, 'error' => $message, 'status' => $status_code ]); exit; } /** * Require authentication or send error * * Call this at the beginning of protected endpoints */ function requireAuth() { if (!authenticate()) { sendUnauthorizedResponse("Valid API key required"); } } /** * Generate a new random API key * * @return string 64-character hex API key */ function generateApiKey() { return bin2hex(random_bytes(32)); } // Example usage (for testing): if (basename(__FILE__) == basename($_SERVER['SCRIPT_FILENAME'])) { header('Content-Type: text/plain'); echo "PDF Accessibility Checker - Authentication Module\n"; echo "=================================================\n\n"; if (isset($_GET['generate'])) { echo "New API Key:\n"; echo generateApiKey() . "\n\n"; echo "Add this to your .api_keys file or API_KEY environment variable.\n"; } else if (isset($_GET['test'])) { echo "Testing authentication...\n\n"; $api_key = extractApiKey(); if ($api_key) { echo "API Key found: " . substr($api_key, 0, 8) . "...\n"; if (authenticate()) { echo "✅ Authentication successful!\n"; } else { echo "❌ Authentication failed - invalid key\n"; } } else { echo "❌ No API key provided\n"; echo "\nTry:\n"; echo " - Add header: X-API-Key: \n"; echo " - Or query param: ?api_key=&test=1\n"; } echo "\nValid keys configured: " . count(getValidApiKeys()) . "\n"; } else { echo "Available actions:\n"; echo " ?generate - Generate new API key\n"; echo " ?test - Test authentication\n"; echo "\nExample:\n"; echo " php auth.php?generate\n"; echo " curl -H 'X-API-Key: your-key' http://localhost:8000/auth.php?test\n"; } } ?>