<?php 
namespace App; 
 
use Firebase\JWT\JWT; 
use Firebase\JWT\Key; 
 
class Authenticator 
{ 
    public array $config; 
 
    public function __construct(array $config) 
    { 
        $this->config = $config; 
    } 
 
    public function authenticate(): bool 
    { 
        if (empty($this->config['auth_enabled'])) { 
            return true; 
        } 
 
        switch ($this->config['auth_method']) { 
            case 'apikey': 
                $headers = $this->getHeaders(); 
                $key = $headers['X-API-Key'] ?? ($_GET['api_key'] ?? null); 
                return in_array($key, $this->config['api_keys'], true); 
 
            case 'basic': 
                if (!isset($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW'])) { 
                    $this->requireBasicAuth(); 
                    return false; 
                } 
                $user = $_SERVER['PHP_AUTH_USER']; 
                $pass = $_SERVER['PHP_AUTH_PW']; 
                return isset($this->config['basic_users'][$user]) 
                    && $this->config['basic_users'][$user] === $pass; 
 
            case 'jwt': 
                $headers = $this->getHeaders(); 
                $authHeader = $headers['Authorization'] ?? ''; 
                if (preg_match('/Bearer\s(\S+)/', $authHeader, $matches)) { 
                    $jwt = $matches[1]; 
                    return $this->validateJwt($jwt); 
                } 
                return false; 
 
            case 'oauth': 
                // Placeholder for OAuth token validation 
                $headers = $this->getHeaders(); 
                $authHeader = $headers['Authorization'] ?? ''; 
                if (preg_match('/Bearer\s(\S+)/', $authHeader, $matches)) { 
                    $token = $matches[1]; 
                    // TODO: Validate $token with OAuth provider 
                    return false; 
                } 
                return false; 
 
            default: 
                return false; 
        } 
    } 
 
    public function requireAuth() 
    { 
        if (!$this->authenticate()) { 
            http_response_code(401); 
            header('Content-Type: application/json'); 
            echo json_encode(['error' => 'Unauthorized']); 
            exit; 
        } 
    } 
 
    public function createJwt(array $payload, int $expireSeconds = 3600): string 
    { 
        $now = time(); 
        $payload = array_merge([ 
            'iat' => $now, 
            'exp' => $now + $expireSeconds, 
            'iss' => $this->config['jwt_issuer'] ?? '', 
            'aud' => $this->config['jwt_audience'] ?? '', 
        ], $payload); 
 
        return JWT::encode($payload, $this->config['jwt_secret'], 'HS256'); 
    } 
 
    public function validateJwt(string $jwt): bool 
    { 
        try { 
            $decoded = JWT::decode($jwt, new Key($this->config['jwt_secret'], 'HS256')); 
            // Optionally: Validate iss/aud/exp 
            return true; 
        } catch (\Exception $e) { 
            return false; 
        } 
    } 
 
    private function getHeaders(): array 
    { 
        if (function_exists('getallheaders')) { 
            return getallheaders(); 
        } 
        // Fallback 
        $headers = []; 
        foreach ($_SERVER as $name => $value) { 
            if (str_starts_with($name, 'HTTP_')) { 
                $header = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5))))); 
                $headers[$header] = $value; 
            } 
        } 
        return $headers; 
    } 
 
    private function requireBasicAuth() 
    { 
        header('WWW-Authenticate: Basic realm="API"'); 
        http_response_code(401); 
        echo json_encode(['error' => 'Unauthorized']); 
        exit; 
    } 
}
 
 |