Problem Overview
When attempting to generate verification tokens in Flask using TimedJSONWebSignatureSerializer from the itsdangerous library (version 2.1.2), an import error occurs:
ImportError: cannot import name 'TimedJSONWebSignatureSerializer' from 'itsdangerous'
The clas simply doesn't exist in the installed version of the library.
Root Cause
The itsdangerous library deprecated and removed the TimedJSONWebSignatureSerializer class starting from version 2.0.0. The library documentation recommends using dedicated JWT libraries that natively support JWS/JWT standards instead.
Available Solutions
Option 1: Downgrade itsdangerous (not recommended)
Install a version prior to 2.0.0 to maintain backward compatibility:
pip install itsdangerous==1.1.0
Option 2: Switch to authlib (recommended)
The authlib library provides proper JWT support and is the suggested replacement:
pip install authlib
Implementation with authlib:
from authlib.jose import jwt, JoseError
from flask import current_app
def create_verification_token(user_id, action_type, **extra_data):
"""Create a JWT token for email verification."""
header_payload = {'alg': 'HS256'}
secret_key = current_app.config['SECRET_KEY']
payload_data = {
'user_id': user_id,
'action': action_type
}
payload_data.update(extra_data)
return jwt.encode(header=header_payload, payload=payload_data, key=secret_key)
def verify_token(token, required_action=None):
"""Verify the JWT token and extract payload data."""
secret_key = current_app.config['SECRET_KEY']
try:
decoded_payload = jwt.decode(token, secret_key)
if required_action and decoded_payload.get('action') != required_action:
return None
return decoded_payload
except JoseError:
return None
Option 3: Use itsdangerous.Serializer with built-in expiration
The current itsdangerous library still provides basic serialization with expiration support:
from itsdangerous import Serializer, BadSignature, SignatureExpired
from flask import current_app
def make_token(resource_id, action, expire_seconds=3600, **params):
"""Generate a signed token with expiration."""
signer = Serializer(current_app.config['SECRET_KEY'])
token_data = {
'resource': resource_id,
'op': action
}
token_data.update(params)
return signer.dumps(token_data)
def check_token(encrypted_token, target_action):
"""Validate and decode the token."""
verifier = Serializer(current_app.config['SECRET_KEY'])
try:
payload = verifier.loads(encrypted_token)
except SignatureExpired:
return None
except BadSignature:
return None
if payload.get('op') != target_action:
return None
return payload
Recommendation
For production Flask applications requiring robust JWT functionality, migrating to authlib is the best approach. It offers comprehensive JWT standard support, better security practices, and active maintenance.