12]); } /** * Verify password */ public static function verifyPassword(string $password, string $hash): bool { return password_verify($password, $hash); } /** * Generate JWT Token with HMAC-SHA256 signature * Includes user_id, company_id, role, iss, aud, and jti. */ public static function generateJWT(array $payload, int $expirySeconds = 86400): string { $header = self::base64UrlEncode(json_encode(['alg' => 'HS256', 'typ' => 'JWT'])); // Standard OWASP Claims $payload['iat'] = time(); $payload['exp'] = time() + $expirySeconds; $payload['iss'] = getenv('APP_URL'); // Issuer $payload['aud'] = 'nabeh_dashboard'; // Audience $payload['jti'] = bin2hex(random_bytes(16)); // JWT ID to prevent Replay Attacks $payloadEncoded = self::base64UrlEncode(json_encode($payload)); $secret = self::getJwtSecret(); $signature = hash_hmac('sha256', "$header.$payloadEncoded", $secret, true); $signatureEncoded = self::base64UrlEncode($signature); return "$header.$payloadEncoded.$signatureEncoded"; } /** * Verify JWT Token and return payload if valid, false otherwise */ public static function verifyJWT(string $token) { $parts = explode('.', $token); if (count($parts) !== 3) { return false; } list($headerEncoded, $payloadEncoded, $signatureEncoded) = $parts; $secret = self::getJwtSecret(); if (!$secret) { return false; } $signature = self::base64UrlDecode($signatureEncoded); $expectedSignature = hash_hmac('sha256', "$headerEncoded.$payloadEncoded", $secret, true); if (!hash_equals($signature, $expectedSignature)) { return false; } $payload = json_decode(self::base64UrlDecode($payloadEncoded), true); if (!$payload || !isset($payload['exp']) || time() >= $payload['exp']) { return false; } // Validate Issuer $expectedIssuer = getenv('APP_URL'); if (isset($payload['iss']) && $payload['iss'] !== $expectedIssuer) { return false; } return $payload; } private static function base64UrlEncode(string $data): string { return rtrim(strtr(base64_encode($data), '+/', '-_'), '='); } private static function base64UrlDecode(string $data): string { return base64_decode(strtr($data, '-_', '+/') . str_repeat('=', (4 - strlen($data) % 4) % 4)); } }