Сообщение об ошибке
Signature has expired
PyJWT (Python) — jwt.exceptions.ExpiredSignatureError
Что это означает
Утверждение exp в токене указывает на момент раньше текущего времени проверяющей стороны, поэтому PyJWT отклонил токен — концептуально уже после успешной проверки подписи. Формулировка немного вводит в заблуждение: у самой подписи срока действия нет, истёк срок действия токена.
Почему это происходит
Устаревший токен используют после окончания срока его жизни
частоЗакешированные учётные данные в долго работающем фоновом процессе, токен, сохранённый на стороне клиента и повторно отправленный после истечения TTL, или интеграционные тесты с токеном из фикстуры, сгенерированным несколько дней назад. Отказ здесь — правильное поведение.
Уход часов на хосте, где выполняется проверка
частоЕсли часы проверяющей стороны спешат, фактический срок жизни каждого токена сокращается. Обычно виноваты контейнеры и раннеры CI без синхронизации времени; даже уход на 60–120 секунд периодически ломает короткоживущие токены.
Издатель неправильно записывает exp
иногдаЗначение exp должно быть целым числом секунд с начала эпохи. Неправильно сериализованные объекты datetime или миллисекунды дают токены, которые просрочены уже в момент выпуска, — тогда каждая проверка сразу завершается ошибкой, и этим такой случай отличается от обычного истечения срока действия.
exp вычисляется из datetime без часового пояса
иногдаИздатели, которые вычисляют exp из datetime.now() (местное время без часового пояса) вместо datetime.now(timezone.utc), сдвигают срок жизни каждого токена на смещение сервера относительно UTC. В зависимости от того, по какую сторону от UTC находится издатель, токены либо истекают на несколько часов раньше, либо незаметно живут дольше задуманного TTL. PyJWT правильно кодирует datetime с часовым поясом — ловушка именно в объектах без него.
Как исправить
- 1.
Сгладьте небольшое расхождение часов параметром leeway
Параметр leeway (в секундах) действует на проверки exp и nbf. Задавайте не больше нескольких десятков секунд: большие значения незаметно продлевают срок жизни токенов.
python import jwt payload = jwt.decode( token, key, algorithms=["ES256"], leeway=30, # seconds of tolerated clock skew ) - 2.
Посмотрите на фактические метки времени
Прочитайте утверждения без проверки и сравните exp с часами хоста: по величине разницы видно, что это — истечение срока, расхождение часов или ошибка при выпуске токена.
python import jwt, time claims = jwt.decode(token, options={"verify_signature": False}) print("exp:", claims["exp"], "now:", int(time.time()), "delta:", int(time.time()) - claims["exp"], "s")