Skip to main content

A super simple JWT library for Python

Project description

SuperJWT full logo
A modern implementation of JSON Web Token (JWT) for Python.
With powerful Pydantic validation features.

GitHub Actions workflow status on main branch

Overview & Installation

SuperJWT is a minimalist JWT library for Python 3.10+ that combines the simplicity of JWT encoding/decoding with the power of Pydantic validation. It supports JWS (JSON Web Signature) format with HMAC-SHA2 algorithms and includes advanced features like token inspection and detached payload mode.

Key Features:

  • 🔐 Secure by default - JWS signature algorithm required.
  • 🪶 Minimalist - Clean, modern code with minimal dependencies.
  • ✔️ JWT validation - Easy claims validation with Pydantic models.
  • 🏷️ Type hints - IDE autocompletion with your JWT claims or JOSE headers.

Install via pip:

pip install superjwt

Usage

SuperJWT makes it easy to encode and decode JWT tokens with automatic validation and serialization. Here are the fundamental operations:

Basic Usage 🐣

Encode manually your claims from a dict. During decoding, validate your JWT content against the standard JWT claims.

from superjwt import JWTClaims, encode, decode

secret_key = "your-secret-key-of-len-32-bytes!"

compact: bytes = encode({"iss": "my-app", "sub": "John Doe"}, secret_key, "HS256")
#> b'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
#   .eyJpc3MiOiJteS1hcHAiLCJzdWIiOiJKb2huIERvZSJ9
#   .HwnUqTLFAMzNkMrokd0aI7c-zSJJpSVXMrYIhUyWe4s'
decoded: dict = decode(compact, secret_key, "HS256", claims_validation=JWTClaims)
#> {'iss': 'my-app', 'sub': 'John Doe'}

Define dynamically your claims with Pydantic and easily include 'iat' (Issued At) and 'exp' (Expiration). Validate your JWT content automatically during encoding and decoding.

from superjwt import JWTClaims, encode, decode

secret_key = "your-secret-key-of-len-32-bytes!"

claims = (
    JWTClaims(iss="my-app", sub="John Doe")
    .with_issued_at()
    .with_expiration(minutes=15)
)

compact: bytes = encode(claims, secret_key, "HS256")
#> b'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
#   .eyJpc3MiOiJteS1hcHAiLCJzdWIiOiJKb2huIERvZSIsImlhdCI6MTc2NzAyNzQ4MywiZXhwIjoxNzY3MDI4MzgzfQ
#   .ZXxZT8VzL8IPTov-enslCh57S2M5fQBtqULZx5zEAm8'
decoded: dict = decode(compact, secret_key, "HS256", claims_validation=JWTClaims)
#> {'iss': 'my-app', 'sub': 'John Doe', 'iat': 1767027483, 'exp': 1767028383}

Custom Claims and Validation

Redefine standard claims or define new custom ones. Validate automatically during encoding and decoding.

from typing import Annotated
from uuid import UUID

from pydantic import AfterValidator, Field
from superjwt import JWTClaims, Validation, decode, encode
from superjwt.exceptions import ClaimsValidationError

secret_key = "your-secret-key-of-len-32-bytes!"

class MyJWTClaims(JWTClaims):
    # redefine 'sub' as required integer
    sub: int = Field(default=...)

    # new custom claim:  'user_id' is required and must be a valid UUIDv4 string
    user_id: Annotated[str, AfterValidator(lambda x: str(UUID(x, version=4)))]
# Example - Validation PASSING

claims = (
    MyJWTClaims(sub=123, user_id="b2a4c791-2cf4-4e41-9a20-8532129ff47c")
    .with_expiration(minutes=15)
)
compact = encode(claims, secret_key, "HS256")
decoded = decode(compact, secret_key, "HS256", claims_validation=MyJWTClaims)
#> {'sub': 123, 'exp': 1767027591, 'user_id': 'b2a4c791-2cf4-4e41-9a20-8532129ff47c'}
# Example - Validation FAILING

# create a non-validated and invalid pydantic claims
invalid_claims = (
    MyJWTClaims.model_construct(**{"sub": "John Doe", "user_id": "invalid-uuid-string"})
    .with_issued_at()
    .with_expiration(minutes=10)
)

# disable claims default validation to create an invalid token
invalid_compact = encode(
    invalid_claims, secret_key, "HS256", claims_validation=Validation.DISABLE
)
try:
    decode(invalid_compact, secret_key, "HS256", claims_validation=MyJWTClaims)
except ClaimsValidationError as e:
    print("Claims validation error:", e)
#> Claims validation error: Claims validation failed
#    claim ('sub',) = John Doe -> validation failed (int_parsing): 
#      Input should be a valid integer, unable to parse string as an integer
#    claim ('user_id',) = invalid-uuid-string -> validation failed (value_error):
#      Value error, badly formed hexadecimal UUID string

Documentation

See full documentation

Test

  1. Clone repository

  2. Install dependencies

    pip install -e . --group test
    
  3. Run tests

    pytest
    

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

superjwt-0.4.1.tar.gz (27.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

superjwt-0.4.1-py3-none-any.whl (18.1 kB view details)

Uploaded Python 3

File details

Details for the file superjwt-0.4.1.tar.gz.

File metadata

  • Download URL: superjwt-0.4.1.tar.gz
  • Upload date:
  • Size: 27.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for superjwt-0.4.1.tar.gz
Algorithm Hash digest
SHA256 70f8b140c83b958ab08202b0ec554b7d04180e50c410bfdc728e44b9d6f2a71d
MD5 9e65e7beedde7ef2c53d2a5275a949e8
BLAKE2b-256 efbe21bc1f9db53db80b70f3a4e220ead9c4593c56d35e3dcfc41cb001484458

See more details on using hashes here.

Provenance

The following attestation bundles were made for superjwt-0.4.1.tar.gz:

Publisher: pypi.yml on ixunio/superjwt

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file superjwt-0.4.1-py3-none-any.whl.

File metadata

  • Download URL: superjwt-0.4.1-py3-none-any.whl
  • Upload date:
  • Size: 18.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for superjwt-0.4.1-py3-none-any.whl
Algorithm Hash digest
SHA256 a84e49be082737faeeeeb9c5d74a4ef886f4f774afd0ff9fd6799328cb024f30
MD5 65dbd7a1bb9880cbd64c9ca5db782760
BLAKE2b-256 06bb0fec371632344ac07f4d759a06443e08fdcf54fedd2ebdf02f381e6e2535

See more details on using hashes here.

Provenance

The following attestation bundles were made for superjwt-0.4.1-py3-none-any.whl:

Publisher: pypi.yml on ixunio/superjwt

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page