Error Handling
SuperJWT provides specific exceptions or warnings in different scenarios.
ExceptionsΒΆ
graph LR
SJE["SuperJWTError"] --> ITE["InvalidTokenError"]
SJE --> IAE["InvalidAlgorithmError"]
SJE --> IKE["InvalidKeyError"]
ITE --> SVFE["SignatureVerificationError"]
ITE --> SEE["SizeExceededError"]
ITE --> IHE["InvalidHeadersError"]
ITE --> IPE["InvalidPayloadError"]
IHE --> HVE["HeadersValidationError"]
IHE --> AME["AlgorithmMismatchError"]
IPE --> CVE["ClaimsValidationError"]
CVE --> TEE["TokenExpiredError"]
CVE --> TNVE["TokenNotYetValidError"]
IAE --> ANSE["AlgorithmNotSupportedError"]
SuperJWTError
βββββ InvalidTokenError
β βββββ SignatureVerificationError
β βββββ SizeExceededError
β βββββ InvalidHeadersError
β β βββββ HeadersValidationError
β β βββββ AlgorithmMismatchError
β βββ InvalidPayloadError
β βββββ ClaimsValidationError
β βββββ TokenExpiredError
β βββββ TokenNotYetValidError
βββββ InvalidAlgorithmError
β βββββ AlgorithmNotSupportedError
βββββ InvalidKeyError
SuperJWTErrorΒΆ
inherits from Exception
The base exception of the SuperJWT library. It can be used to catch all SuperJWT errors.
InvalidTokenErrorΒΆ
inherits from SuperJWTError
Generic error when token is invalid (bad format, cannot be verified, cannot be validated).
Code Example
SignatureVerificationErrorΒΆ
inherits from InvalidTokenError
Raised when signature verification fails. This happens when decoding with the wrong key or when the token has been tampered with.
Code Example
from superjwt import Alg, JWTClaims, decode, encode
from superjwt.exceptions import SignatureVerificationError
secret_key = "your-secret-key-of-len-32-bytes!"
token_a = encode(JWTClaims(sub="user123"), secret_key, Alg.HS256)
token_b = encode(JWTClaims(sub="user456"), secret_key, Alg.HS256)
# Forge a token
header_a, _payload_a, sig_a = token_a.split(b".")
_header_b, payload_b, _sig_b = token_b.split(b".")
forged = header_a + b"." + payload_b + b"." + sig_a
try:
decode(forged, secret_key, Alg.HS256)
except SignatureVerificationError as e:
print(e)
#> Signature verification failed, the token may have been tampered with!
from superjwt import Alg, JWTClaims, decode, encode
from superjwt.exceptions import SignatureVerificationError
secret_key = "your-secret-key-of-len-32-bytes!"
wrong_key = "a-different-key-also-32-bytes!!!"
claims = JWTClaims(sub="user123")
compact = encode(claims, secret_key, Alg.HS256)
try:
decode(compact, wrong_key, Alg.HS256)
except SignatureVerificationError as e:
print(e)
#> Signature verification failed, the token may have been tampered with!
InvalidHeadersErrorΒΆ
inherits from InvalidTokenError
Raised when JWT headers are malformed or contain invalid values.
Code Example
from superjwt import Alg, decode, encode
from superjwt.exceptions import InvalidHeadersError
secret_key = "your-secret-key-of-len-32-bytes!"
valid_token = encode({"sub": "test"}, secret_key, Alg.HS256)
parts = valid_token.split(b".")
invalid_compact = b".".join([b"!!!invalid-base64!!!", parts[1], parts[2]])
try:
# Create a token with invalid b64 header which is not supported
decode(invalid_compact, secret_key, Alg.HS256)
except InvalidHeadersError as e:
print(e)
#> Headers are not encoded as a valid Base64url
HeadersValidationErrorΒΆ
inherits from InvalidHeadersError
Raised when header data fails Pydantic validation (defaults to JOSEHeader).
Code Example
from superjwt import Alg, JOSEHeader, encode
from superjwt.exceptions import HeadersValidationError
secret_key = "your-secret-key-of-len-32-bytes!"
headers = JOSEHeader.model_construct(alg="INVALID_ALG", typ="JWT")
try:
encode({}, secret_key, Alg.HS256, headers=headers)
except HeadersValidationError as e:
print(e)
#> Header validation failed
#> header ('alg',) = INVALID_ALG -> validation failed (value_error):
#> Value error, 'INVALID_ALG' is not a valid algorithm
AlgorithmMismatchErrorΒΆ
inherits from InvalidHeadersError
Raised when the algorithm in the JWT header doesn't match the expected algorithm during encoding or decoding.
Code Example
from superjwt import Alg, JOSEHeader, Validation, decode, encode, inspect
from superjwt.exceptions import AlgorithmMismatchError
secret_key = "your-secret-key-of-len-32-bytes!"
compact = (
"eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9"
"."
"eyJpc3MiOiJ1c2VyLTEyMyJ9"
"."
"Mp0Pcwsz5VECK11Kf2ZZNF_SMKu5CgBeLN9ZOP04kZo"
)
print(inspect(compact).headers["alg"])
#> 'HS512'
try:
# Decode expecting HS256 but header says HS512
# even with headers validation disabled, an AlgorithmMismatchError is raised
decode(compact, secret_key, Alg.HS256, headers_validation=Validation.DISABLE)
except AlgorithmMismatchError as e:
print(e)
#> JWS algorithm 'HS512' does not match expected 'HS256'
InvalidPayloadErrorΒΆ
inherits from InvalidTokenError
Raised when the payload is not valid JSON or not a proper mapping (dict).
Code Example
import json
from superjwt import Alg, decode
from superjwt.exceptions import InvalidPayloadError
from superjwt.utils import urlsafe_b64encode
secret_key = "your-secret-key-of-len-32-bytes!"
# Create a token with invalid payload (not a JSON object)
header = urlsafe_b64encode(json.dumps({"alg": "HS256", "typ": "JWT"}).encode())
payload = urlsafe_b64encode(b"not-valid-json")
fake_signature = urlsafe_b64encode(b"fake")
malformed_token = header + b"." + payload + b"." + fake_signature
try:
decode(malformed_token, secret_key, Alg.HS256)
except InvalidPayloadError as e:
print(e)
#> The payload segment is not valid JSON
ClaimsValidationErrorΒΆ
inherits from InvalidPayloadError
Raised when claims data fails Pydantic validation.
Code Example
from superjwt import Alg, JWTClaims, Validation, decode, encode
from superjwt.exceptions import ClaimsValidationError
secret_key = "your-secret-key-of-len-32-bytes!"
invalid_claims = JWTClaims.model_construct(sub="user123", iss=12345)
# ENCODING
try:
encode(invalid_claims, secret_key, Alg.HS256)
except ClaimsValidationError as e:
print(e)
#> Claims validation failed
#> claim ('iss', 'str') = 12345 -> validation failed (string_type):
#> Input should be a valid string
invalid_compact = encode(
invalid_claims,
secret_key,
Alg.HS256,
validation=Validation.DISABLE
)
# DECODING
try:
decode(invalid_compact, secret_key, Alg.HS256, validation=JWTClaims)
except ClaimsValidationError as e:
print(e)
#> Claims validation failed
#> claim ('iss', 'str') = 12345 -> validation failed (string_type):
#> Input should be a valid string
from pydantic import Field
from superjwt import Alg, JWTClaims, Validation, decode, encode
from superjwt.exceptions import ClaimsValidationError
secret_key = "your-secret-key-of-len-32-bytes!"
# Example 2: Custom claims model with required field
class MyClaims(JWTClaims):
user_id: str = Field(default=...) # required field
invalid_claims = {"sub": "user123"}
# ENCODING
try:
encode(invalid_claims, secret_key, Alg.HS256, validation=MyClaims)
except ClaimsValidationError as e:
print(e)
#> Claims validation failed
#> claim ('user_id',) = ... -> validation failed (missing): Field required
invalid_compact = encode(
invalid_claims,
secret_key,
Alg.HS256,
validation=Validation.DISABLE
)
# DECODING
try:
decode(invalid_compact, secret_key, Alg.HS256, validation=MyClaims)
except ClaimsValidationError as e:
print(e)
#> Claims validation failed
#> claim ('user_id',) = ... -> validation failed (missing): Field required
TokenExpiredErrorΒΆ
inherits from ClaimsValidationError
Raised when the token's 'exp' claim indicates the token has expired.
Code Example
from datetime import datetime, timedelta, UTC
from superjwt import Alg, JWTClaims, Validation, decode, encode
from superjwt.exceptions import TokenExpiredError
secret_key = "your-secret-key-of-len-32-bytes!"
# Create an expired token (exp in the past)
expired_claims = JWTClaims.model_construct(
sub="user123",
exp=datetime.now(UTC) - timedelta(hours=1), # expired 1 hour ago
)
# Encode without validation to create the expired token
compact = encode(
expired_claims, secret_key, Alg.HS256, validation=Validation.DISABLE
)
try:
# Decode with validation will check exp claim
decode(compact, secret_key, Alg.HS256, validation=JWTClaims)
except TokenExpiredError as e:
print(e)
#> Token has expired
TokenNotYetValidErrorΒΆ
inherits from ClaimsValidationError
Raised when the token's 'nbf' (not before) claim indicates the token is not yet valid.
Code Example
from datetime import datetime, timedelta, UTC
from superjwt import Alg, JWTClaims, Validation, decode, encode
from superjwt.exceptions import TokenNotYetValidError
secret_key = "your-secret-key-of-len-32-bytes!"
# Create a token that won't be valid for another day
future_claims = JWTClaims.model_construct(
sub="user123",
nbf=datetime.now(UTC) + timedelta(days=1), # valid starting tomorrow
)
# Encode without validation to create the future token
compact = encode(
future_claims, secret_key, Alg.HS256, validation=Validation.DISABLE
)
try:
# Decode with validation will check nbf claim
decode(compact, secret_key, Alg.HS256, validation=JWTClaims)
except TokenNotYetValidError as e:
print(e)
#> Token is not yet valid
InvalidAlgorithmErrorΒΆ
inherits from SuperJWTError
Raised when an invalid algorithm name is provided.
Code Example
AlgorithmNotSupportedErrorΒΆ
inherits from InvalidAlgorithmError
Raised when an algorithm exists in the specification but is not yet implemented in the library.
Code Example
InvalidKeyErrorΒΆ
inherits from SuperJWTError
Raised when the provided key format is invalid for the selected algorithm.
Code Example
from superjwt.exceptions import InvalidKeyError
from superjwt.keys import OctKey
# Create a fake PEM-formatted key (asymmetric key format)
pem_key = b"""-----BEGIN RSA PRIVATE KEY-----
MIIBOgIBAAJBAKj34GkxFhD90vcNLYLInFEX6Ppy1tPf9Cnzj4p4WGeKLs1Pt8Qu
-----END RSA PRIVATE KEY-----"""
try:
# Try to use a PEM key for HMAC algorithm (symmetric)
OctKey.import_key(pem_key)
except InvalidKeyError as e:
print(e)
#> The specified key is an asymmetric key or x509 certificate
#> and should not be used as an HMAC secret.
WarningsΒΆ
SecurityWarningΒΆ
inherits from UserWarning
Base warning for security concerns.
KeyLengthSecurityWarningΒΆ
inherits from SecurityWarning
Raised when a key length/size is deemed insufficient but working.
Code Example
import warnings
from superjwt import OctKey
from superjwt.exceptions import KeyLengthSecurityWarning
# Capture warnings
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
# Use a very short key (less than 112 bits / 14 bytes)
weak_key = "short" # Only 5 bytes
OctKey.import_key(weak_key)
# Check if SecurityWarning was raised
if len(w) > 0 and issubclass(w[-1].category, KeyLengthSecurityWarning):
print(w[-1].message)
#> HMAC key size is 40 bits. Key size should be >= 112 bits for security