itsdangerous

Cryptographically signs data for safe passing to untrusted environments — generates signed tokens with optional expiration. itsdangerous features: Signer for basic HMAC signing, URLSafeSerializer for URL-safe signed JSON (stateless tokens), URLSafeTimedSerializer for timed tokens with expiration, TimestampSigner for signed timestamps, BadSignature exception on invalid signatures, SignatureExpired exception on expired tokens, multiple secret key rotation support (fallback_unsafe_secret_keys), salt parameter for domain separation, and separator customization. Used by Flask for session cookies and password reset tokens.

Evaluated Mar 06, 2026 (0d ago) v2.x
Homepage ↗ Repo ↗ Developer Tools python itsdangerous signing token HMAC URL-safe timed Flask
⚙ Agent Friendliness
68
/ 100
Can an agent use this?
🔒 Security
89
/ 100
Is it safe for agents?
⚡ Reliability
90
/ 100
Does it work consistently?

Score Breakdown

⚙ Agent Friendliness

MCP Quality
--
Documentation
88
Error Messages
85
Auth Simplicity
95
Rate Limits
99

🔒 Security

TLS Enforcement
90
Auth Strength
88
Scope Granularity
90
Dep. Hygiene
92
Secret Handling
85

HMAC signing using hashlib. Payload is NOT encrypted — only signed. Do not put secrets in payload. SECRET_KEY must be random and at least 32 bytes: secrets.token_hex(32). Use different salts for different token types to prevent token substitution attacks. Timing-safe comparison used internally for signature verification — prevents timing attacks.

⚡ Reliability

Uptime/SLA
90
Version Stability
90
Breaking Changes
88
Error Recovery
90
AF Security Reliability

Best When

Flask ecosystem token generation (password reset, email verification, CSRF) and stateless signed session data — itsdangerous is the Pallets-ecosystem standard for HMAC-signed tokens.

Avoid When

Standard JWT (use pyjwt), encrypted tokens (use Fernet), large payloads, or when interoperability with other JWT libraries is required.

Use Cases

  • Agent signed token — from itsdangerous import URLSafeTimedSerializer; s = URLSafeTimedSerializer('SECRET_KEY'); token = s.dumps({'user_id': 42, 'action': 'reset'}); payload = s.loads(token, max_age=3600) — timed token; agent generates expiring signed tokens for password reset, email verification; loads() raises SignatureExpired after max_age seconds
  • Agent stateless session — from itsdangerous import URLSafeSerializer; s = URLSafeSerializer('SECRET_KEY', salt='session'); session_token = s.dumps({'user_id': 42, 'role': 'admin'}); data = s.loads(session_token) — URL-safe session; agent creates stateless signed session tokens; no DB required; data is readable but tamper-proof
  • Agent signature verification — from itsdangerous import URLSafeTimedSerializer, BadSignature, SignatureExpired; try: data = s.loads(token, max_age=3600) except SignatureExpired: return 'Token expired' except BadSignature: return 'Invalid token' — verification; agent validates tokens with specific error handling for expired vs tampered
  • Agent key rotation — s = URLSafeTimedSerializer('NEW_KEY', fallback_unsafe_secret_keys=['OLD_KEY']); data = s.loads(old_token) — key rotation; agent supports rolling secret key updates; old tokens signed with OLD_KEY still verify; new tokens use NEW_KEY; gradual migration without invalidating existing tokens
  • Agent domain separation — s1 = URLSafeSerializer('SECRET', salt='password-reset'); s2 = URLSafeSerializer('SECRET', salt='email-verify'); token1 = s1.dumps(user_id); s2.loads(token1) — raises BadSignature — salt prevents cross-domain token reuse; agent uses different salts for different token types to prevent substitution attacks

Not For

  • JWT tokens — itsdangerous uses a custom format; for standard JWT use pyjwt or python-jose
  • Encryption — itsdangerous signs but does NOT encrypt; payload is base64-readable; for encrypted tokens use cryptography Fernet
  • Large payloads — URLSafe serializers produce long tokens for large data; for large signed blobs use signed references to DB records

Interface

REST API
No
GraphQL
No
gRPC
No
MCP Server
No
SDK
Yes
Webhooks
No

Authentication

Methods: none
OAuth: No Scopes: No

No auth — signing library. Provides building blocks for auth token generation.

Pricing

Model: open_source
Free tier: Yes
Requires CC: No

itsdangerous is BSD 3-Clause licensed. Created by Armin Ronacher (Pallets). Free for all use.

Agent Metadata

Pagination
none
Idempotent
Full
Retry Guidance
Not documented

Known Gotchas

  • Payload is readable — URLSafeSerializer encodes with base64 (not encryption); anyone can decode the payload: import base64; base64.b64decode(token.split('.')[0] + '=='); agent code must NOT put sensitive data (passwords, PII) in token payload; token proves authenticity not secrecy; for secrets use Fernet encryption
  • max_age is in seconds not datetime — s.loads(token, max_age=3600) expires after 3600 seconds (1 hour); agent code with complex expiry: compute seconds: max_age=int(timedelta(days=1).total_seconds()); SignatureExpired has date_signed attribute for when token was created
  • Same salt required for loads — token generated with salt='reset' must be loaded with salt='reset'; mismatched salt raises BadSignature not helpful error; agent code: use constants for salts to avoid typos: RESET_SALT = 'password-reset'; s.dumps(data, salt=RESET_SALT) / s.loads(token, salt=RESET_SALT)
  • SECRET_KEY must be kept secret — itsdangerous security depends entirely on SECRET_KEY secrecy; anyone with SECRET_KEY can forge tokens; agent code: load from env var: SECRET_KEY = os.environ['SECRET_KEY']; rotate key periodically; use fallback_unsafe_secret_keys for graceful rotation
  • dumps() on URLSafeTimedSerializer needs no extra args — s.dumps(payload) works; but s.dumps(payload, salt=...) overrides class salt; agent code: set salt in constructor URLSafeTimedSerializer('key', salt='domain'); do not pass salt to dumps() for consistency; passing salt to dumps() overrides constructor salt
  • BadSignature is parent of SignatureExpired — catch order matters: except BadSignature catches both; except SignatureExpired catches only expired; agent code: catch in order: try: data = s.loads(token) except SignatureExpired: handle_expired() except BadSignature: handle_tampered() — SignatureExpired must come before BadSignature

Alternatives

Full Evaluation Report

Detailed scoring breakdown, competitive positioning, security analysis, and improvement recommendations for itsdangerous.

$99

Scores are editorial opinions as of 2026-03-06.

5208
Packages Evaluated
26151
Need Evaluation
173
Need Re-evaluation
Community Powered