Кастомные 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.
В 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. Их интерпретация полностью
определяется прикладной логикой.
После верификации токена 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 часто используются для хранения иерархических данных. На практике встречаются следующие модели:
Пример сложного 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.
Отсутствие жесткой типизации приводит к потенциальным конфликтам
имен. Например, использование ключей role, id,
type может пересекаться с внутренними соглашениями
различных сервисов.
Практика именования кастомных claims часто использует префиксы:
app_roleauth_permissionsx_departmentили доменные пространства:
billing.limituser.profile.levelТакая организация снижает вероятность пересечения семантики при интеграции нескольких систем.
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 часто применяются для реализации 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 не должны рассматриваться как защищенное хранилище данных. Подпись JWT обеспечивает целостность, но не конфиденциальность.
Типичные ограничения безопасности:
В сценариях, требующих конфиденциальности, используется JWE (JSON Web Encryption), а не JWS.
В Jsrsasign payload может формироваться динамически на основе состояния приложения.
function buildPayload(user) {
return {
sub: user.id,
role: user.role,
permissions: user.permissions,
session: {
loginTime: Date.now(),
deviceId: user.deviceId
}
};
}
Такая структура позволяет адаптировать токен под конкретный контекст выполнения без изменения механизма подписи.
Несмотря на наличие стандартного поля iat, кастомные
временные поля часто используются для доменной логики:
const payload = {
sub: "user-111",
accessWindow: {
start: 1710000000,
end: 1710086400
}
};
Валидация таких полей требует ручного сравнения с текущим временем.
Кастомные claims формируют основу расширяемости JWT в Jsrsasign. Отсутствие жесткой схемы позволяет использовать токены в различных сценариях:
Гибкость структуры компенсируется необходимостью строгой дисциплины при проектировании именования и валидации данных.