get_api_key() !== null; } public function authenticate(): ?int { $api_key = $this->get_api_key(); if (!$api_key) { return null; } $user_id = $this->validate_api_key($api_key); if (!$user_id) { throw new \Exception('Invalid API key'); } // Verify user still exists and is active $user = get_user_by('ID', $user_id); if (!$user) { throw new \Exception('User account not found'); } return (int) $user_id; } public function validate_credentials(): bool { $api_key = $this->get_api_key(); return $api_key && $this->validate_api_key($api_key) !== null; } public function get_priority(): int { return 20; // Lower priority than OAuth2 } public function requires_https(): bool { return true; // API keys should require HTTPS } public function get_allowed_methods(): array { return ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD']; } public function get_response_headers(): array { return []; } /** * Get API key from request (header or parameter) */ private function get_api_key(): ?string { // Check X-API-Key header if (isset($_SERVER['HTTP_X_API_KEY'])) { return sanitize_text_field($_SERVER['HTTP_X_API_KEY']); } // Check api_key parameter if (isset($_GET['api_key'])) { return sanitize_text_field($_GET['api_key']); } if (isset($_POST['api_key'])) { return sanitize_text_field($_POST['api_key']); } return null; } /** * Validate API key and return user ID */ private function validate_api_key(string $api_key): ?int { $stored_keys = get_option(self::API_KEY_STORAGE_OPTION, []); foreach ($stored_keys as $key_data) { if (hash_equals($key_data['key'], $api_key)) { // Check if key is active if (!$key_data['active']) { continue; } // Check expiration if set if (isset($key_data['expires']) && time() > $key_data['expires']) { continue; } // Update last used timestamp $this->update_last_used($api_key); return (int) $key_data['user_id']; } } return null; } /** * Update last used timestamp for API key */ private function update_last_used(string $api_key): void { $stored_keys = get_option(self::API_KEY_STORAGE_OPTION, []); foreach ($stored_keys as &$key_data) { if (hash_equals($key_data['key'], $api_key)) { $key_data['last_used'] = time(); break; } } update_option(self::API_KEY_STORAGE_OPTION, $stored_keys); } /** * Generate a new API key for a user */ public static function generate_api_key_for_user(int $user_id, string $name = '', ?int $expires_in = null): string { $api_key = 'wpak_' . bin2hex(random_bytes(24)); // 48 character key with prefix $expires = $expires_in ? time() + $expires_in : null; $stored_keys = get_option(self::API_KEY_STORAGE_OPTION, []); $stored_keys[] = [ 'key' => $api_key, 'user_id' => $user_id, 'name' => $name ?: 'API Key ' . date('Y-m-d H:i:s'), 'created' => time(), 'expires' => $expires, 'last_used' => null, 'active' => true, ]; update_option(self::API_KEY_STORAGE_OPTION, $stored_keys); return $api_key; } /** * Revoke an API key */ public static function revoke_api_key(string $api_key): bool { $stored_keys = get_option(self::API_KEY_STORAGE_OPTION, []); foreach ($stored_keys as &$key_data) { if (hash_equals($key_data['key'], $api_key)) { $key_data['active'] = false; $key_data['revoked'] = time(); update_option(self::API_KEY_STORAGE_OPTION, $stored_keys); return true; } } return false; } /** * List API keys for a user */ public static function get_user_api_keys(int $user_id): array { $stored_keys = get_option(self::API_KEY_STORAGE_OPTION, []); return array_filter($stored_keys, function($key_data) use ($user_id) { return $key_data['user_id'] === $user_id && $key_data['active']; }); } }