Кастомные claims

Кастомные claims в JWT представляют собой расширение стандартной структуры payload, в котором размещаются данные, специфичные для конкретного приложения или доменной модели. В контексте Jsrsasign payload JWT формируется как JSON-объект, где помимо зарегистрированных полей допускается произвольное расширение структуры.

Основная идея claims заключается в передаче набора утверждений о субъекте токена. В спецификации выделяются зарегистрированные, публичные и приватные (кастомные) claims.

Зарегистрированные claims включают стандартные поля, такие как:

  • iss (issuer)
  • sub (subject)
  • aud (audience)
  • exp (expiration time)
  • nbf (not before)
  • iat (issued at)
  • jti (JWT ID)

Эти поля имеют фиксированную семантику и используются библиотеками для базовой валидации токена.

Публичные claims определяются через зарегистрированные пространства имен или URI, что снижает риск конфликтов имен.

Кастомные claims формируются произвольно и предназначены для передачи прикладных данных, не входящих в стандарт JWT.


Кастомные claims в Jsrsasign

В Jsrsasign JWT формируется как объект, передаваемый в методы генерации подписи. Payload может содержать любые ключи, интерпретируемые как claims.

const header = { alg: "HS256", typ: "JWT" };

const payload = {
  iss: "auth-service",
  sub: "user-123",
  iat: Math.floor(Date.now() / 1000),

  role: "admin",
  permissions: ["read", "write", "delete"],
  profile: {
    department: "engineering",
    level: 5
  }
};

const secret = "secret-key";

const token = KJUR.jws.JWS.sign(
  "HS256",
  JSON.stringify(header),
  JSON.stringify(payload),
  secret
);

В данном случае поля role, permissions и profile являются кастомными claims и не имеют фиксированного поведения в спецификации JWT. Их интерпретация полностью определяется прикладной логикой.


Извлечение и проверка кастомных claims

После верификации токена Jsrsasign позволяет получить payload в виде JSON-структуры.

const isValid = KJUR.jws.JWS.verifyJWT(token, secret, {
  alg: ["HS256"]
});

const decoded = KJUR.jws.JWS.parse(token);
const payloadObj = JSON.parse(decoded.payloadPP);

Доступ к кастомным claims осуществляется напрямую через свойства объекта:

const role = payloadObj.role;
const permissions = payloadObj.permissions;
const department = payloadObj.profile.department;

Jsrsasign не накладывает ограничений на структуру payload, что делает возможным использование вложенных объектов и массивов любой сложности.


Вложенные структуры и сложные claims

Кастомные claims часто используются для хранения иерархических данных. На практике встречаются следующие модели:

  • объект профиля пользователя
  • список ролей
  • матрица прав доступа
  • контекст сессии

Пример сложного payload:

const payload = {
  sub: "user-456",
  role: "manager",
  permissions: {
    projects: ["create", "update"],
    users: ["read"]
  },
  session: {
    device: "mobile",
    ip: "192.168.0.1",
    metadata: {
      locale: "ru-RU",
      theme: "dark"
    }
  }
};

Jsrsasign сериализует такую структуру без дополнительных преобразований, так как используется стандартный JSON.stringify.


Конфликты имен и область видимости claims

Отсутствие жесткой типизации приводит к потенциальным конфликтам имен. Например, использование ключей role, id, type может пересекаться с внутренними соглашениями различных сервисов.

Практика именования кастомных claims часто использует префиксы:

  • app_role
  • auth_permissions
  • x_department

или доменные пространства:

  • billing.limit
  • user.profile.level

Такая организация снижает вероятность пересечения семантики при интеграции нескольких систем.


Валидация кастомных claims

Jsrsasign обеспечивает криптографическую проверку подписи и базовую проверку стандартных claims, но валидация кастомных полей выполняется вручную после декодирования payload.

Типовой подход включает проверку:

  • наличия обязательных полей
  • допустимых значений
  • диапазонов
  • соответствия бизнес-правилам

Пример:

if (!payloadObj.permissions || !Array.isArray(payloadObj.permissions)) {
  throw new Error("Invalid permissions structure");
}

if (payloadObj.role !== "admin" && payloadObj.role !== "user") {
  throw new Error("Invalid role value");
}

Использование кастомных claims для авторизации

Кастомные claims часто применяются для реализации RBAC (Role-Based Access Control) и ABAC (Attribute-Based Access Control).

RBAC пример:

const payload = {
  sub: "user-789",
  role: "editor",
  permissions: ["edit_article", "publish_article"]
};

ABAC пример:

const payload = {
  sub: "user-789",
  attributes: {
    department: "finance",
    clearanceLevel: 3,
    region: "EU"
  }
};

Дальнейшая логика доступа строится на интерпретации этих атрибутов после проверки токена.


Ограничения и практические аспекты

Размер JWT ограничен общими ограничениями HTTP-заголовков и cookie. Избыточное использование кастомных claims приводит к увеличению размера токена и снижению производительности передачи.

Типичные ограничения:

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

Кастомные claims не шифруются по умолчанию, а лишь кодируются в base64url и подписываются. Это означает, что содержимое payload доступно для чтения после декодирования токена.


Безопасность кастомных claims

Кастомные claims не должны рассматриваться как защищенное хранилище данных. Подпись JWT обеспечивает целостность, но не конфиденциальность.

Типичные ограничения безопасности:

  • отсутствие хранения паролей
  • избегание токенизации секретных ключей
  • минимизация персональных данных

В сценариях, требующих конфиденциальности, используется JWE (JSON Web Encryption), а не JWS.


Динамическое формирование claims

В Jsrsasign payload может формироваться динамически на основе состояния приложения.

function buildPayload(user) {
  return {
    sub: user.id,
    role: user.role,
    permissions: user.permissions,
    session: {
      loginTime: Date.now(),
      deviceId: user.deviceId
    }
  };
}

Такая структура позволяет адаптировать токен под конкретный контекст выполнения без изменения механизма подписи.


Работа с датами в кастомных claims

Несмотря на наличие стандартного поля iat, кастомные временные поля часто используются для доменной логики:

const payload = {
  sub: "user-111",
  accessWindow: {
    start: 1710000000,
    end: 1710086400
  }
};

Валидация таких полей требует ручного сравнения с текущим временем.


Расширяемость модели claims

Кастомные claims формируют основу расширяемости JWT в Jsrsasign. Отсутствие жесткой схемы позволяет использовать токены в различных сценариях:

  • микросервисная архитектура
  • одностраничные приложения
  • сервер-сервер авторизация
  • распределенные системы идентификации

Гибкость структуры компенсируется необходимостью строгой дисциплины при проектировании именования и валидации данных.