В спецификации JOSE (JSON Object Signing and Encryption)
идентификатор ключа kid является частью защищённого
заголовка JWS/JWE и служит для однозначного определения ключа, которым
выполняется подпись или шифрование. В контексте библиотеки
jose в JavaScript этот параметр становится критическим
элементом при ротации ключей, работе с JWKS (JSON Web Key Set) и
валидации токенов в распределённых системах.
kid хранится внутри JWK и пробрасывается в заголовок
токена:
{
"alg": "RS256",
"kid": "key-2026-01"
}
Его основная функция — связать токен с конкретным криптографическим ключом без необходимости перебора всех доступных ключей при проверке подписи.
kid при генерации токенаВ jose при создании JWT идентификатор ключа передаётся
через JWK:
import { SignJWT, exportJWK } from 'jose'
import { generateKeyPair } from 'jose'
const { privateKey } = await generateKeyPair('RS256')
const jwk = await exportJWK(privateKey)
jwk.kid = 'key-2026-01'
const token = await new SignJWT({ sub: '123' })
.setProtectedHeader({ alg: 'RS256', kid: jwk.kid })
.setIssuedAt()
.setExpirationTime('2h')
.sign(privateKey)
Здесь kid фиксируется одновременно в ключе и в заголовке
токена, обеспечивая их согласованность.
kidПри верификации токена библиотека jose использует
kid для выбора нужного ключа из набора.
Типичный сценарий — удалённое хранилище ключей:
import { jwtVerify, createRemoteJWKSet } from 'jose'
const JWKS = createRemoteJWKSet(
new URL('https://auth.example.com/.well-known/jwks.json')
)
const { payload } = await jwtVerify(token, JWKS)
Внутри createRemoteJWKSet происходит:
kidЕсли kid отсутствует или не найден, происходит попытка
перебора ключей, что значительно снижает производительность и может
приводить к отказу проверки.
kidРотация ключей — основная причина использования kid. При
смене криптографического материала система должна поддерживать несколько
активных ключей одновременно.
Типичный жизненный цикл:
kidПример набора ключей:
{
"keys": [
{
"kty": "RSA",
"kid": "key-2025-01",
"use": "sig"
},
{
"kty": "RSA",
"kid": "key-2026-01",
"use": "sig"
}
]
}
При валидации токена с изменившимся kid библиотека
выполняет поиск по текущему набору ключей. Если токен подписан старым
ключом, но он всё ещё присутствует в JWKS, проверка проходит
корректно.
Проблема возникает в двух случаях:
kid не совпадает с реальным идентификатором в JWKSВ таких случаях возникает ошибка:
JWSInvalid: Unable to find a key matching the kid
kidcreateRemoteJWKSet использует внутренний кеш:
kidПри ротации ключей важно учитывать задержку распространения
изменений. Типичная проблема — выпуск токена с новым kid,
который ещё не попал в кеш у потребителей.
kidВ некоторых архитектурах используется ручное управление ключами:
import { importJWK, jwtVerify } from 'jose'
const keys = {
'key-2026-01': await importJWK({
kty: 'RSA',
n: '...',
e: 'AQAB'
}),
}
async function verify(token) {
const { protectedHeader } = JSON.parse(
Buffer.from(token.split('.')[0], 'base64').toString()
)
const key = keys[protectedHeader.kid]
if (!key) throw new Error('Unknown kid')
return jwtVerify(token, key)
}
Такой подход используется в системах без JWKS endpoint или при строгом контроле над ключами.
kid1. Отсутствие kid в токене
Без kid невозможно быстро определить ключ, и библиотека
вынуждена проверять все доступные варианты.
2. Несовпадение kid в JWK и
заголовке
Если ключ экспортирован с одним идентификатором, а токен подписан с другим, проверка не пройдёт.
3. Дублирование kid
В JWKS наличие двух ключей с одинаковым kid делает выбор
неоднозначным и приводит к непредсказуемому поведению.
4. Преждевременное удаление ключей
Удаление старого ключа до истечения срока жизни всех токенов приводит к массовым ошибкам валидации.
kid при ротации ключейЧасто используется формат:
<алгоритм>-<дата>
RS256-2026-01
или
key-v1, key-v2, key-v3
При смене ключа оба активны одновременно:
Каждый деплой может публиковать новый набор ключей, не удаляя предыдущий.
kid с алгоритмами и JWKSkid не несёт криптографического значения. Его роль
исключительно идентификационная. При этом он тесно связан с:
alg (алгоритм подписи)kty (тип ключа)use (назначение ключа)Несоответствие между этими параметрами часто приводит к ошибкам
валидации даже при корректном kid.
jose при отсутствии точного совпаденияПри использовании createRemoteJWKSet алгоритм поиска
ключа выглядит так:
kidalgЭто делает систему устойчивой к частичным рассинхронизациям JWKS, но увеличивает стоимость проверки.
Стабильная схема работы с kid в распределённой системе
обычно включает:
kidkid mismatchТакая модель позволяет исключить массовые сбои при обновлении криптографического слоя без остановки сервиса