jwt — JSON Web Tokens

Небольшая реализация стандарта JSON Web Token (JWT) для MicroPython. JWT — это компактный, безопасный для URL контейнер для JSON-полезной нагрузки, который издатель подписывает, чтобы проверяющая сторона могла обнаружить подделку и истечение срока действия.

Этот порт для MicroPython намеренно крошечный:

  • Поддерживается только HS256 (HMAC с SHA-256). Алгоритмы RSA / ECDSA / EdDSA не реализованы; издатель и проверяющая сторона должны использовать общий симметричный секретный ключ.

  • Необязательное утверждение exp (срок действия) учитывается. Другие зарегистрированные утверждения (nbf, iat, iss, aud, sub, jti) передаются в полезной нагрузке без изменений, но не проверяются; приложение проверяет их, если это для него важно.

  • Ротация ключей, JWKS и обработка списка аудитории не поддерживаются.

Функции

jwt.encode(payload: dict, key: bytes | str, algorithm: str = 'HS256') str

Кодирует payload в подписанный JWT и возвращает результирующую компактную сериализацию (str вида "header.payload.signature", где каждый сегмент закодирован в Base64-URL).

payload

Сериализуемый в JSON словарь утверждений. Стандартные утверждения (exp, iat, sub, …) передаются без изменений; пользовательские ключи приложения допускаются.

key

Общий секрет HMAC. Предпочтителен bytes; str автоматически кодируется в UTF-8.

algorithm

Должен быть "HS256" (по умолчанию). Любое другое значение вызывает exceptions.InvalidAlgorithmError.

jwt.decode(token: str, key: bytes | str, algorithms: list = ['HS256']) dict

Проверяет подпись token и (при наличии) его утверждение exp и возвращает декодированный словарь полезной нагрузки. Вызывает подкласс exceptions.PyJWTError при любой ошибке — вызывающая сторона обычно перехватывает базовый класс.

token

Компактная строка JWT, созданная функцией encode() (или любым совместимым издателем).

key

Общий секрет HMAC. Должен совпадать с ключом, использованным при кодировании.

algorithms

Список алгоритмов, которые вызывающая сторона готова принять. HS256 должен присутствовать, и заголовок alg токена должен быть в этом списке. По умолчанию ["HS256"].

Вызывает:

  • exceptions.InvalidAlgorithmErrorHS256 отсутствует в algorithms или заголовок alg токена отличается от HS256.

  • exceptions.InvalidTokenError — токен сформирован неверно (не разбивается на три сегмента Base64-URL или сегмент не удаётся декодировать / разобрать как JSON).

  • exceptions.InvalidSignatureError — подпись не совпадает с пересчитанным HMAC по заголовку и полезной нагрузке.

  • exceptions.ExpiredSignatureError — полезная нагрузка содержит утверждение exp, значение которого меньше текущего времени Unix. Чтобы эта проверка имела смысл, должны быть установлены часы камеры; см. ntptime.settime().

Исключения

Все исключения вложены в атрибут модуля jwt.exceptions.

exception exceptions.PyJWTError

Базовый класс для любой ошибки JWT. Перехватывайте его, если вам не нужно различать описанные ниже случаи.

exception exceptions.InvalidTokenError

Токен структурно некорректен — неверное количество сегментов, сегмент, который не удаётся декодировать из Base64, или JSON, который не удаётся разобрать. Подкласс exceptions.PyJWTError.

exception exceptions.InvalidAlgorithmError

Алгоритм токена отсутствует в списке принимаемых вызывающей стороной, либо вызывающая сторона запросила алгоритм, отличный от HS256. Подкласс exceptions.PyJWTError.

exception exceptions.InvalidSignatureError

Подпись токена не совпадает с HMAC, вычисленным по заголовку и полезной нагрузке с использованием предоставленного ключа. Подкласс exceptions.PyJWTError.

exception exceptions.ExpiredSignatureError

Утверждение exp токена находится в прошлом. Подкласс exceptions.PyJWTError. Чтобы эта проверка имела смысл, должно быть установлено реальное время камеры (через ntptime.settime()).

Пример

Цикл выпуска/проверки с симметричным секретом:

import jwt
import time

SECRET = b"keep-this-out-of-source-control"

payload = {
    "sub": "kitchen-cam",
    "role": "admin",
    "exp": time.time() + 3600,                 # 1 hour from now
}

token = jwt.encode(payload, SECRET)
print("token:", token)

try:
    claims = jwt.decode(token, SECRET)
except jwt.exceptions.PyJWTError as e:
    print("rejected:", type(e).__name__)
else:
    print("subject:", claims["sub"])

Для подписи и проверки используется один и тот же секрет, поэтому проверяющая сторона должна располагать ключом, использованным издателем. Для сервисов, где издателем является камера (выдающая токены сопряжённому телефону), храните секрет в файловой системе камеры и обращайтесь с ним как с любыми другими долгоживущими учётными данными — см. Эксплуатация: ключи, истечение срока и устранение неполадок.

Примечание

Этот модуль опирается на hmac и hashlib, оба из которых встроены в камеру. Никакой внешней настройки не требуется. Ключи могут быть любой длины, но конструкция HMAC наиболее эффективна с ключами длиной не менее размера блока SHA-256 (32 байта).