JOSEError и её подклассы

В основе системы обработки ошибок в библиотеке лежит JOSEError — общий предок для всех исключений, связанных с операциями над JWS (подписи), JWE (шифрование) и JWT (токены).

JOSEError наследуется от стандартного Error и служит маркером для всех криптографических и структурных ошибок, возникающих внутри библиотеки jose.

Ключевая особенность: любые специфические ошибки (подпись, расшифровка, валидация claims) всегда можно отловить через проверку на instanceof JOSEError, не разбирая каждую разновидность отдельно.

import { JOSEError } from 'jose';

try {
  // операции с JWT / JWS / JWE
} catch (err) {
  if (err instanceof JOSEError) {
    // обработка всех ошибок jose
  }
}

Иерархия ошибок в jose

Библиотека строит строгую иерархию исключений. Это важно для точного разделения причин сбоя:

  • JOSEError — базовый класс

    • JWSInvalid

      • JWSSignatureVerificationFailed
    • JWEInvalid

      • JWEDecryptionFailed
    • JWTInvalid

      • JWTExpired
      • JWTClaimValidationFailed
      • JWTMalformed

Такая структура позволяет различать:

  • ошибки криптографической проверки
  • ошибки структуры токена
  • ошибки в claims (payload)

JOSEError как фундаментальная абстракция

JOSEError не используется напрямую как сигнал конкретной проблемы. Его роль — унификация обработки.

Типичные свойства:

  • name — имя ошибки (строка)
  • message — описание причины
  • code — машинно-ориентированный код (в некоторых версиях)
  • стек вызовов (stack trace)
try {
  // verify / decrypt / decode
} catch (e) {
  if (e instanceof JOSEError) {
    console.error(e.message);
  }
}

Ошибки JWS (подписи)

JWS (JSON Web Signature) отвечает за проверку подписи токена.

JWSInvalid

Базовая ошибка для всех проблем с JWS-структурой.

Причины:

  • некорректный формат compact serialization
  • отсутствие сегментов (header.payload.signature)
  • повреждённая строка токена

JWSSignatureVerificationFailed

Возникает при неуспешной проверке подписи.

Причины:

  • неверный публичный ключ
  • изменён payload после подписи
  • несовпадение алгоритма (alg mismatch)
import { jwtVerify } from 'jose';

try {
  await jwtVerify(token, publicKey);
} catch (err) {
  if (err.name === 'JWSSignatureVerificationFailed') {
    // токен подделан или ключ неверный
  }
}

Ошибки JWE (шифрование)

JWE (JSON Web Encryption) отвечает за шифрование и расшифровку данных.

JWEInvalid

Базовый класс ошибок JWE-слоя.

Причины:

  • неправильная структура токена
  • некорректные параметры заголовка
  • несовместимые алгоритмы шифрования

JWEDecryptionFailed

Одна из наиболее частых ошибок при работе с JWE.

Причины:

  • неправильный приватный ключ
  • повреждённый ciphertext
  • неверный alg или enc
  • использование другого ключа, чем при шифровании
import { jwtDecrypt } from 'jose';

try {
  await jwtDecrypt(token, privateKey);
} catch (err) {
  if (err.name === 'JWEDecryptionFailed') {
    // невозможно расшифровать токен
  }
}

Ошибки JWT (высокоуровневый слой)

JWT в библиотеке jose строится поверх JWS/JWE и добавляет проверку claims.

JWTInvalid

Общий тип ошибок JWT-валидации.

Причины:

  • некорректный формат токена
  • отсутствуют обязательные поля (exp, iat, sub)
  • повреждённая структура payload

JWTExpired

Возникает при превышении срока действия токена (exp).

try {
  await jwtVerify(token, key);
} catch (err) {
  if (err.name === 'JWTExpired') {
    // токен устарел
  }
}

Особенность: проверка exp происходит автоматически при валидации.


JWTClaimValidationFailed

Ошибка возникает при несоответствии claims ожидаемым значениям.

Типичные случаи:

  • aud не совпадает с ожидаемым
  • iss не соответствует доверенному issuer
  • sub отсутствует или некорректен
await jwtVerify(token, key, {
  issuer: 'https://auth.server'
});

Если iss отличается — выбрасывается JWTClaimValidationFailed.


JWTMalformed

Ошибка структуры JWT до стадии криптографической проверки.

Причины:

  • меньше или больше 3 частей (header.payload.signature)
  • неверный base64url encoding
  • мусорные символы

Практика обработки ошибок JOSE

Корректная стратегия обработки ошибок в приложениях, использующих jose, обычно строится на двух уровнях:

1. Общая обработка JOSEError

import { JOSEError } from 'jose';

try {
  await jwtVerify(token, key);
} catch (err) {
  if (err instanceof JOSEError) {
    // логирование и единый формат ответа
  }
}

2. Детализация по типу ошибки

catch (err) {
  if (err.name === 'JWTExpired') {
    // refresh token flow
  }

  if (err.name === 'JWSSignatureVerificationFailed') {
    // возможная атака или неверный ключ
  }
}

Поведение ошибок при цепочках операций

В сложных сценариях (например, decrypt → verify → validate claims) ошибка может возникать на разных уровнях:

  1. JWEDecryptionFailed — проблема расшифровки
  2. JWSInvalid — проблема подписи
  3. JWTClaimValidationFailed — проблема бизнес-логики

Важно: библиотека не агрегирует ошибки в одну — всегда возвращается первая критическая точка сбоя.


Типичные архитектурные подходы

Централизованный обработчик

Создаётся единая функция обработки JOSE-ошибок:

function handleJoseError(err) {
  switch (err.name) {
    case 'JWTExpired':
      return { status: 401, reason: 'expired' };

    case 'JWSSignatureVerificationFailed':
      return { status: 401, reason: 'invalid_signature' };

    case 'JWEDecryptionFailed':
      return { status: 400, reason: 'decrypt_failed' };

    default:
      return { status: 500, reason: 'unknown_jose_error' };
  }
}

Разделение уровней доверия

Ошибки JOSE часто делят на два класса:

  • критические безопасности

    • JWSSignatureVerificationFailed
    • JWEDecryptionFailed
  • логические (claims)

    • JWTExpired
    • JWTClaimValidationFailed

Такое разделение влияет на:

  • HTTP-коды
  • поведение refresh-токенов
  • аудит безопасности

Особенности отладки

При работе с JOSEError важны следующие аспекты:

  • сообщение ошибки часто минимально и не содержит чувствительных данных
  • стек вызовов полезен для диагностики алгоритма или ключа
  • name ошибки является основным идентификатором типа проблемы
  • различия между JWS и JWE часто являются первичным источником багов

Связь JOSEError с криптографическим уровнем

JOSEError не просто программное исключение, а отражение состояния криптографической операции:

  • нарушение целостности данных → JWS
  • невозможность расшифровки → JWE
  • несоответствие политике токена → JWT

Эта модель позволяет использовать библиотеку как строгий слой безопасности, где каждая ошибка является результатом конкретного криптографического контракта.