{"id":282,"library":"pyjwt","title":"PyJWT","description":"PyJWT is the canonical Python implementation of JSON Web Tokens (RFC 7519), supporting HMAC (HS256/384/512), RSA (RS256/384/512, PS256/384/512), EC (ES256/384/512), and OKP (EdDSA) algorithms. Current stable version is 2.12.1 (released March 2026). The project follows an irregular release cadence driven by security advisories and feature PRs, with several releases per year. Asymmetric algorithms (RS*, ES*, PS*, EdDSA) require the optional `cryptography` extra.","status":"active","version":"2.12.1","language":"python","source_language":"en","source_url":"https://github.com/jpadilla/pyjwt","tags":["jwt","authentication","security","token","jose","jwk","jwks","rfc7519"],"install":[{"cmd":"pip install pyjwt","lang":"bash","label":"HMAC-only (HS256/384/512)"},{"cmd":"pip install pyjwt[cryptography]","lang":"bash","label":"With asymmetric algorithm support (RS*, ES*, PS*, EdDSA)"}],"dependencies":[{"reason":"Required for RSA, EC, PS*, and EdDSA algorithms. Not needed for HMAC-only usage.","package":"cryptography","optional":true},{"reason":"Required on Python < 3.11 (added in 2.12.1).","package":"typing_extensions","optional":false}],"imports":[{"note":"Top-level module exposes encode(), decode(), get_unverified_header(), and all exception classes.","symbol":"jwt (module)","correct":"import jwt"},{"note":"Used for automatic JWKS endpoint fetching and key resolution (e.g. Auth0, Cognito).","symbol":"PyJWKClient","correct":"from jwt import PyJWKClient"},{"note":"Wraps a single JSON Web Key; returned by PyJWKClient.get_signing_key_from_jwt().","symbol":"PyJWK","correct":"from jwt import PyJWK"},{"note":"ExpiredSignature (no 'Error' suffix) was removed in 2.0. Use ExpiredSignatureError, InvalidAudienceError, InvalidIssuerError.","wrong":"from jwt.exceptions import ExpiredSignature","symbol":"ExpiredSignatureError","correct":"from jwt.exceptions import ExpiredSignatureError"},{"note":"InvalidAudience (no 'Error' suffix) was removed in 2.0.","wrong":"from jwt.exceptions import InvalidAudience","symbol":"InvalidAudienceError","correct":"from jwt.exceptions import InvalidAudienceError"},{"note":"Raised when PyJWKClient cannot reach the JWKS endpoint; exported at top level since 2.8.0.","symbol":"PyJWKClientConnectionError","correct":"from jwt import PyJWKClientConnectionError"}],"quickstart":{"code":"import os\nimport jwt\nfrom datetime import datetime, timezone, timedelta\n\nSECRET = os.environ.get('JWT_SECRET', 'change-me-use-32-plus-chars-prod!')\n\n# Encode\npayload = {\n    \"sub\": \"user-123\",\n    \"iss\": \"my-service\",\n    \"aud\": \"my-api\",\n    \"exp\": datetime.now(tz=timezone.utc) + timedelta(hours=1),\n    \"iat\": datetime.now(tz=timezone.utc),\n}\ntoken: str = jwt.encode(payload, SECRET, algorithm=\"HS256\")\nprint(\"token type:\", type(token))  # <class 'str'> in 2.x\n\n# Decode — always pass algorithms= to prevent alg confusion attacks\ntry:\n    decoded = jwt.decode(\n        token,\n        SECRET,\n        algorithms=[\"HS256\"],       # required; never omit\n        audience=\"my-api\",          # validates 'aud' claim\n        issuer=\"my-service\",        # validates 'iss' claim\n        options={\"require\": [\"exp\", \"iat\", \"sub\"]},\n    )\n    print(decoded)\nexcept jwt.ExpiredSignatureError:\n    print(\"token expired\")\nexcept jwt.InvalidTokenError as e:\n    print(\"invalid token:\", e)\n","lang":"python","description":"Encode and decode a signed JWT with HS256, validating exp/aud/iss claims. token is a str in PyJWT 2.x."},"warnings":[{"fix":"Remove any .decode('utf-8') calls on the encode() return value. It is already a str in 2.0+.","message":"jwt.encode() returns str in 2.x, not bytes. Calling .decode('utf-8') on the result raises AttributeError.","severity":"breaking","affected_versions":"<2.0"},{"fix":"Catch jwt.ExpiredSignatureError, jwt.InvalidAudienceError, and jwt.InvalidIssuerError respectively.","message":"Exception aliases ExpiredSignature, InvalidAudience, and InvalidIssuer were removed in 2.0. Code catching these names will silently fail to catch the exception.","severity":"breaking","affected_versions":"<2.0"},{"fix":"Use options={\"verify_signature\": False} to skip verification, e.g. jwt.decode(token, options={\"verify_signature\": False}).","message":"jwt.decode(token, key, verify=False) does nothing in 2.x and raises a deprecation warning. Passing extra kwargs to decode() is flagged RemovedInPyjwt3Warning.","severity":"breaking","affected_versions":"1.x pattern used in 2.x"},{"fix":"Upgrade to pyjwt>=2.12.0 immediately.","message":"CVE-2026-32597 (GHSA-752w-5fwx-jx9f, CVSS 7.5 HIGH): versions < 2.12.0 silently accept JWS tokens with unknown crit header extensions, violating RFC 7515 §4.1.11.","severity":"breaking","affected_versions":"<2.12.0"},{"fix":"Always pass a hard-coded allowlist: jwt.decode(token, key, algorithms=[\"HS256\"]). Never derive the list from the token header.","message":"algorithms= parameter is required in jwt.decode(). Omitting it accepts any algorithm, enabling alg:none and key-confusion attacks (CVE-2022-29217).","severity":"gotcha","affected_versions":"all 2.x"},{"fix":"Pass options={\"require\": [\"exp\", \"iat\", \"sub\"]} to enforce presence and validation of critical claims.","message":"Optional claims (exp, iat, nbf, sub, jti) are only validated when present. A token missing exp is accepted even if you call decode() without options.","severity":"gotcha","affected_versions":"all 2.x"},{"fix":"Install pyjwt[cryptography] when using any non-HMAC algorithm.","message":"RSA/EC/PS*/EdDSA algorithms silently fail with an unhelpful ImportError or InvalidAlgorithmError if the cryptography package is not installed.","severity":"gotcha","affected_versions":"all 2.x"}],"env_vars":null,"last_verified":"2026-05-12T12:49:10.897Z","next_check":"2026-06-26T00:00:00.000Z","problems":[{"fix":"Pass a list of explicitly allowed algorithms, matching the token's 'alg' header, to the `algorithms` parameter in `jwt.decode()`. Example: `jwt.decode(token, secret, algorithms=['HS256'])`","cause":"The `algorithms` parameter was either not provided or did not include the algorithm used to sign the token when calling `jwt.decode()`. PyJWT requires explicit declaration of allowed algorithms for security reasons.","error":"jwt.exceptions.InvalidAlgorithmError: The specified alg value is not allowed"},{"fix":"Install PyJWT with the `crypto` extra to include the `cryptography` dependency: `pip install \"pyjwt[crypto]\"` (note the quotes for shell compatibility).","cause":"You are attempting to use an asymmetric algorithm (such as RS*, ES*, PS*, or EdDSA) but the optional `cryptography` dependency for PyJWT is not installed.","error":"NotImplementedError: Algorithm 'RS256' could not be found. Do you have cryptography installed?"},{"fix":"Ensure the `key` parameter passed to `jwt.decode()` is the correct secret (for symmetric algorithms like HS256) or the correct public key (for asymmetric algorithms like RS256) that was used during the token's encoding.","cause":"The secret key or public key provided to `jwt.decode()` does not match the key used to sign the token, or the token itself is malformed or has been tampered with.","error":"jwt.exceptions.InvalidSignatureError: Signature verification failed"},{"fix":"Uninstall both packages (`pip uninstall jwt pyjwt`) to remove any conflicting installations, then reinstall only PyJWT (`pip install pyjwt`).","cause":"This error often occurs due to a naming conflict when both the `PyJWT` library (which provides the `jwt` module) and an older, incompatible `jwt` package are installed simultaneously.","error":"AttributeError: 'module' object has no attribute 'encode'"}],"ecosystem":"pypi","meta_description":null,"install_score":100,"install_tag":"verified","quickstart_score":80,"quickstart_tag":"verified","pypi_latest":null,"install_checks":{"last_tested":"2026-05-12","tag":"verified","tag_description":"installs cleanly on critical runtimes, fast import, recently tested","results":[{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.12,"mem_mb":4.9,"disk_size":"18.3M"},{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"cryptography","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.12,"mem_mb":4.9,"disk_size":"18.3M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.09,"mem_mb":4.9,"disk_size":"19M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"cryptography","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.08,"mem_mb":4.9,"disk_size":"19M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.15,"mem_mb":4.6,"disk_size":"19.9M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"cryptography","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.15,"mem_mb":4.6,"disk_size":"19.9M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.17,"mem_mb":4.6,"disk_size":"20M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"cryptography","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.13,"mem_mb":4.6,"disk_size":"20M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.12,"mem_mb":4.4,"disk_size":"11.8M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"cryptography","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.12,"mem_mb":4.4,"disk_size":"11.8M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.13,"mem_mb":4.4,"disk_size":"12M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"cryptography","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.17,"mem_mb":4.4,"disk_size":"12M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.11,"mem_mb":4.6,"disk_size":"11.4M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"cryptography","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.11,"mem_mb":4.6,"disk_size":"11.4M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.11,"mem_mb":4.6,"disk_size":"12M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"cryptography","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.11,"mem_mb":4.6,"disk_size":"12M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.12,"mem_mb":5,"disk_size":"17.8M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"cryptography","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.12,"mem_mb":5,"disk_size":"17.8M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.1,"mem_mb":5.4,"disk_size":"18M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"cryptography","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.1,"mem_mb":5.4,"disk_size":"18M"}]},"quickstart_checks":{"last_tested":"2026-04-23","tag":"verified","tag_description":"quickstart runs on critical runtimes, recently tested","results":[{"runtime":"python:3.10-alpine","exit_code":0},{"runtime":"python:3.10-slim","exit_code":0},{"runtime":"python:3.11-alpine","exit_code":0},{"runtime":"python:3.11-slim","exit_code":0},{"runtime":"python:3.12-alpine","exit_code":0},{"runtime":"python:3.12-slim","exit_code":0},{"runtime":"python:3.13-alpine","exit_code":0},{"runtime":"python:3.13-slim","exit_code":0},{"runtime":"python:3.9-alpine","exit_code":0},{"runtime":"python:3.9-slim","exit_code":0}]}}