JWT
JWT создаёт и проверяет подписанные токены из трёх частей: header.payload.signature. Payload — JSON-объект claims в base64url; подпись защищает его от незаметного изменения, но не скрывает содержимое.
API находится в localzet\JWT. Для выпуска передают секрет HMAC или приватный ключ; для проверки — тот же HMAC-секрет либо соответствующий публичный ключ. Алгоритм всегда задаётся явно доверенным кодом приложения.
Подключение
Заголовок раздела «Подключение»Требуются PHP 8.2+, OpenSSL, mbstring и JSON. Для EdDSA дополнительно нужен sodium:
composer config repositories.localzet-jwt vcs https://github.com/localzet/JWTcomposer require localzet/jwt:dev-mainВыпуск и проверка
Заголовок раздела «Выпуск и проверка»use localzet\JWT;
$key = random_bytes(32);$claims = [ 'iss' => 'https://issuer.example.test', 'aud' => 'catalog', 'sub' => 'user:42', 'iat' => time(), 'exp' => time() + 300,];
$token = JWT::encode($claims, $key, 'HS256');$verified = JWT::decode($token, $key, 'HS256');
if (($verified['iss'] ?? null) !== 'https://issuer.example.test' || ($verified['aud'] ?? null) !== 'catalog') { throw new UnexpectedValueException('Unexpected token issuer or audience');}Ключ в примере генерируется для демонстрации одного вызова. В приложении храните стабильный секрет в защищённой конфигурации; иначе ранее выданные токены перестанут проверяться после перезапуска. Не передавайте HMAC-секрет клиенту: знающий секрет способен выпускать токены.
encode() принимает JSON-объект claims — ассоциативный массив либо объект. Обычный список, null и scalar payload отклоняются. decode() возвращает PHP-массив; пустой JSON-объект возвращается как [].
Что проверяется автоматически
Заголовок раздела «Что проверяется автоматически»До возврата claims decode():
- требует ровно три сегмента;
- декодирует base64url в канонической форме без padding;
- проверяет
typ = JWT, соответствиеalgпереданному алгоритму и отсутствие неподдерживаемыхcrit/b64; - проверяет подпись над исходными строками
header.payload; - декодирует payload и проверяет форму claims;
- проверяет тип
exp,nbf,iatпри их наличии, затем периодexp/nbfотносительноtime().
Значения NumericDate должны быть числами, не числовыми строками. При now >= exp токен просрочен; при now < nbf ещё не действует. Допуск clock skew не добавляется. Поле iat проверяется на числовой тип, но будущая дата выпуска сама по себе не отклоняется.
Наличие exp, nbf или iat не обязательно. Если политика приложения требует срок действия, проверяйте, что exp присутствует, и ограничивайте максимальный срок.
Что проверяет приложение
Заголовок раздела «Что проверяет приложение»Библиотека не выбирает допустимого issuer, audience, subject, scope и роль пользователя. Она не хранит revocation list, не связывает токен с серверной сессией и не делает проверку прав на конкретную операцию.
Для каждого ожидаемого issuer задайте доверенную конфигурацию ключей и алгоритмов. Не берите алгоритм для decode() прямо из непроверенного header. Значение kid — идентификатор, не URL для свободной загрузки ключа; сопоставляйте его с разрешённым набором ключей своего приложения.
До разбора ограничьте размер входной строки. Не записывайте полный bearer-токен в логи; в диагностике достаточно причины отказа и безопасного идентификатора запроса.
Алгоритмы и ключи
Заголовок раздела «Алгоритмы и ключи»| Алгоритм | Ключ подписи / проверки |
|---|---|
| HS256 | Случайный бинарный секрет не короче 32 байт. |
| HS384 | Секрет не короче 48 байт. |
| HS512 | Секрет не короче 64 байт. |
| RS256 / RS384 / RS512 | Приватный/public RSA PEM, минимум 2048 бит. |
| ES256 | EC PEM на prime256v1 (P-256). |
| ES384 | EC PEM на secp384r1 (P-384). |
| ES512 | EC PEM на secp521r1 (P-521). |
| EdDSA | Sodium secret/public signing key в бинарном виде. |
PEM не принимается как HMAC-секрет. Для ECDSA библиотека преобразует подпись OpenSSL DER в фиксированный JOSE-формат и обратно при проверке. none, SHA-1-варианты, HS256/64, ES256K и RSA-PSS не входят в допустимый набор API.
Отказ проверки
Заголовок раздела «Отказ проверки»Перехватывайте ошибку на границе авторизации и возвращайте единообразный отказ, не раскрывая клиенту детали ключей и OpenSSL. Не принимайте claims из неуспешного вызова и не продолжайте по decoded-but-unverified payload.
Внутри используются UnexpectedValueException для неподходящих токенов/ключей и RuntimeException для части ошибок кодирования/криптоопераций. Нарушение PHP-типов и ошибки sodium могут иметь собственные типы. Настройки алгоритма и ключа хранятся в статических полях на время вызова; API не предоставляет отдельного объекта verifier с неизменяемой policy.
Исходный код · AGPL-3.0