* - 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() { // DEV_MODE env var explicitly bypasses auth (set in Apache/env config) $dev_mode = getenv('DEV_MODE'); return ($dev_mode === 'true' || $dev_mode === '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 - dev only) if (isDevelopmentMode() && 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 only in development mode if (empty($keys) && isDevelopmentMode()) { 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"; } } ?>