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_issued_at()
    .with_expiration(minutes=15)
)
compact = encode(claims, secret_key, "HS256")
decoded = decode(compact, secret_key, "HS256", claims_validation=MyJWTClaims)
#> {'sub': 123, 'iat': 1767026691, '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.0.tar.gz (26.4 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.0-py3-none-any.whl (17.3 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: superjwt-0.4.0.tar.gz
  • Upload date:
  • Size: 26.4 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.0.tar.gz
Algorithm Hash digest
SHA256 0ffbc059501f32d8f0199a9f420738b4a2e3184d3930e074da3d2b7064ebe9f7
MD5 fdd5a07446673ac14da886a4ae246b03
BLAKE2b-256 c3dfb905c911f99514e030f10a89dfedcefde714f1db1c3ba803dcfae4fb39a8

See more details on using hashes here.

Provenance

The following attestation bundles were made for superjwt-0.4.0.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.0-py3-none-any.whl.

File metadata

  • Download URL: superjwt-0.4.0-py3-none-any.whl
  • Upload date:
  • Size: 17.3 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.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b31a04d6efd76a879eab9979012501abdb10958c9c13e50dd9c4367e8e58efa0
MD5 206b636e625fe4223e6466e73fd1c206
BLAKE2b-256 192dcd8c9a21b129d078eb92c363a2641a7ecb2b5b239f6a60233d7058c2f979

See more details on using hashes here.

Provenance

The following attestation bundles were made for superjwt-0.4.0-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