jsonwebtoken подписывает и проверяет JSON Web Token тремя вызовами: jwt.sign(), jwt.verify() и jwt.decode(). Уровень JWS он обрабатывает через пакеты jws и jwa, а криптографию выполняет с помощью node:crypto, поэтому ключами могут быть строки PEM, буферы или экземпляры KeyObject. jwt.decode() только разбирает токен — подпись он никогда не проверяет, и код, который читает из него утверждения, доверяет всему, что написал отправитель.
Версия 9 закрыла классические пути для подмены алгоритма, и проверка подтвердила это для 9.0.3: без параметра algorithms список разрешённых алгоритмов определяется типом ключа, токен HS256, подписанный текстом открытого ключа, отклоняется, а alg: none проходит, только если указать none в списке и вообще не передавать ключ. И всё же передавайте algorithms: этот параметр документирует контракт и продолжит работать, если тип ключа когда-нибудь изменится.
Список алгоритмов ограничен набором RFC 7518: EdDSA, Ed25519 и ES256K нет. Токен от издателя, который подписывает Ed25519 (это обычное дело для jose, а также для стеков на Go и Rust), здесь проверить нельзя; используйте вместо этого jose. ES256 также требует ключ P-256, и при попытке подписать под этим именем ключом P-384 библиотека выбрасывает исключение, а не создаёт токен, который отклонили бы другие библиотеки.
Подписи ECDSA внутри токена — это 64-байтовый формат raw r‖s, который предписывает JWS. Если токен собран вручную из вывода openssl dgst, SHA256withECDSA из Java или облачного KMS, его подпись закодирована в DER и проверка завершается ошибкой "ES256" signatures must be "64" bytes: вставьте токен в отладчик JWT, чтобы увидеть длину подписи, и исправьте подпись с помощью конвертера DER ⇄ raw.
Две настройки по умолчанию ведут себя не так, как предполагают многие команды: одна строже, другая мягче. clockTolerance равен нулю, поэтому расхождение часов между серверами в несколько секунд уже приводит к ошибке jwt expired, а exp необязателен, поэтому срок действия токена, выпущенного без него, никогда не истекает. Задавайте expiresIn при подписи и maxAge или явное требование exp при проверке; секреты HMAC проверяйте инструментом проверки секретов JWT.