'JWT', 'alg' => self::$algorithm ]); $payload = array_merge($payload, [ 'iat' => time(), 'exp' => time() + self::getExpiration() ]); $base64UrlHeader = self::base64UrlEncode($header); $base64UrlPayload = self::base64UrlEncode(json_encode($payload)); $signature = hash_hmac( 'sha256', $base64UrlHeader . "." . $base64UrlPayload, self::getSecret(), true ); $base64UrlSignature = self::base64UrlEncode($signature); return $base64UrlHeader . "." . $base64UrlPayload . "." . $base64UrlSignature; } public static function decode($token) { $tokenParts = explode('.', $token); if (count($tokenParts) !== 3) { return null; } list($header, $payload, $signature) = $tokenParts; $validSignature = hash_hmac( 'sha256', $header . "." . $payload, self::getSecret(), true ); if (!hash_equals(self::base64UrlEncode($validSignature), $signature)) { return null; } $decoded = json_decode(self::base64UrlDecode($payload), true); if (isset($decoded['exp']) && $decoded['exp'] < time()) { return null; } return $decoded; } public static function getUserId($token) { $decoded = self::decode($token); return $decoded['user_id'] ?? null; } public static function getUserData($token) { return self::decode($token); } public static function refreshToken($token) { $decoded = self::decode($token); if (!$decoded) { return null; } // Verificar si está en el período de gracia (última hora) if ($decoded['exp'] - time() < 3600) { return self::encode([ 'user_id' => $decoded['user_id'], 'username' => $decoded['username'], 'role' => $decoded['role'] ]); } return null; } private static function base64UrlEncode($data) { return rtrim(strtr(base64_encode($data), '+/', '-_'), '='); } private static function base64UrlDecode($data) { return base64_decode(strtr($data, '-_', '+/')); } }