ID Token: структура и верификация

ID Token представляет собой JSON Web Token, используемый в протоколе OpenID Connect для передачи информации об аутентифицированном пользователе. Он всегда подписан, а в некоторых случаях может быть дополнительно зашифрован. В экосистеме JavaScript для работы с такими токенами широко применяется библиотека jose, реализующая стандарты JOSE (JSON Object Signing and Encryption).

ID Token отличается от Access Token тем, что его основная задача — идентификация пользователя, а не авторизация доступа к ресурсам. Его структура строго регламентирована спецификацией JWT (RFC 7519) и OpenID Connect Core.


Структура JWT, лежащего в основе ID Token

ID Token всегда представляет собой JWT, состоящий из трёх частей:

header.payload.signature

Каждая часть закодирована в Base64URL.

Header (заголовок)

Содержит метаданные о токене и алгоритме подписи:

{
  "alg": "RS256",
  "typ": "JWT",
  "kid": "abc123"
}

Ключевые поля:

  • alg — алгоритм подписи (RS256, ES256 и др.)
  • typ — тип токена (JWT)
  • kid — идентификатор ключа для проверки подписи

Payload (полезная нагрузка)

Содержит утверждения (claims), описывающие пользователя и контекст аутентификации:

{
  "iss": "https://auth.example.com",
  "sub": "248289761001",
  "aud": "client_id_123",
  "exp": 1714750000,
  "iat": 1714746400,
  "nonce": "n-0S6_WzA2Mj",
  "email": "user@example.com",
  "email_verified": true
}

Основные стандартные claims:

  • iss (issuer) — издатель токена
  • sub (subject) — идентификатор пользователя
  • aud (audience) — клиент, для которого токен предназначен
  • exp (expiration time) — время истечения
  • iat (issued at) — время выпуска
  • nonce — защита от replay-атак

Дополнительные claims могут включать:

  • name
  • preferred_username
  • picture
  • auth_time

Signature (подпись)

Подпись формируется на основе header и payload с использованием приватного ключа провайдера идентификации. Она гарантирует:

  • целостность данных
  • подлинность издателя

JOSE и роль библиотеки jose

JOSE (JSON Object Signing and Encryption) — семейство стандартов:

  • JWS (JSON Web Signature)
  • JWE (JSON Web Encryption)
  • JWK (JSON Web Key)
  • JWT (JSON Web Token)

Библиотека jose реализует эти стандарты в JavaScript и предоставляет инструменты для:

  • проверки подписи JWT
  • декодирования токенов
  • работы с JWKS (JSON Web Key Set)
  • шифрования и дешифрования

Проверка ID Token: общая логика

Верификация ID Token включает несколько обязательных этапов:

1. Проверка подписи

Токен должен быть проверен с использованием публичного ключа, полученного из JWKS endpoint провайдера.

2. Проверка issuer

Значение iss должно строго совпадать с ожидаемым URL провайдера.

3. Проверка audience

Поле aud должно содержать идентификатор клиентского приложения.

4. Проверка срока действия

  • exp должен быть больше текущего времени
  • iat не должен быть в будущем

5. Проверка nonce

Используется для предотвращения повторного использования токена.


Верификация ID Token с помощью jose

Получение JWKS

import { createRemoteJWKSet, jwtVerify } from 'jose'

const JWKS = createRemoteJWKSet(
  new URL('https://auth.example.com/.well-known/jwks.json')
)

JWKS содержит публичные ключи, соответствующие приватным ключам, которыми подписываются токены.


Проверка токена

const { payload, protectedHeader } = await jwtVerify(token, JWKS, {
  issuer: 'https://auth.example.com',
  audience: 'client_id_123'
})

После успешной проверки:

  • payload содержит claims ID Token
  • protectedHeader содержит данные заголовка

Разбор процесса верификации

Декодирование и выбор ключа

  1. Извлекается kid из header
  2. JWKS содержит набор ключей
  3. Выбирается ключ с соответствующим kid

Проверка криптографической подписи

Алгоритмы:

  • RS256 (RSA + SHA-256)
  • ES256 (ECDSA P-256 + SHA-256)

Проверка выполняется автоматически через jose:

  • вычисляется хэш
  • сравнивается подпись
  • при несоответствии выбрасывается ошибка

Проверка claims

После успешной криптографической проверки выполняется логическая валидация:

if (payload.iss !== expectedIssuer) throw new Error('Invalid issuer')
if (!payload.aud.includes(expectedAudience)) throw new Error('Invalid audience')
if (payload.exp < Math.floor(Date.now() / 1000)) throw new Error('Token expired')

Структура ID Token в контексте безопасности

ID Token не предназначен для авторизации API-запросов. Его использование ограничивается:

  • подтверждением личности
  • установлением сессии
  • передачей базового профиля пользователя

Ключевые требования безопасности:

  • обязательная проверка подписи
  • использование HTTPS
  • защита nonce
  • ограниченное время жизни токена
  • строгая проверка audience

Работа с JWKS и ротацией ключей

Провайдеры OpenID Connect регулярно обновляют ключи подписи. JWKS endpoint позволяет:

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

Библиотека jose кэширует JWKS и обновляет его при необходимости.


Типичные ошибки при верификации

Несовпадение issuer

Часто возникает при неправильной конфигурации окружений (dev/prod).

Ошибка audience

Появляется, если токен выдан другому клиенту.

Просроченный токен

Возникает при длительном хранении ID Token.

Отсутствие nonce проверки

Создаёт уязвимость к replay-атакам.


Использование ID Token в приложении

После успешной верификации payload может использоваться для:

  • создания пользовательской сессии
  • извлечения идентификатора пользователя (sub)
  • персонализации интерфейса
  • связывания с внутренней моделью пользователя

Структура sub остаётся стабильной и используется как основной ключ идентификации.


Особенности реализации в jose

Библиотека обеспечивает:

  • строгую реализацию RFC-стандартов
  • поддержку асинхронной загрузки ключей
  • минимизацию ручной криптографической логики
  • безопасные дефолты (например, запрет небезопасных алгоритмов)

Работа с JWT через jose сводится к одной операции — jwtVerify, которая объединяет:

  • декодирование
  • проверку подписи
  • проверку claims