CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-python-jose

JOSE implementation in Python providing JWT, JWS, JWE, and JWK functionality with multiple cryptographic backends.

75

1.44x
Overview
Eval results
Files

jwt-operations.mddocs/

JWT Operations

High-level JSON Web Token functionality providing comprehensive support for encoding, decoding, and validating JWT tokens with automatic claim validation, flexible key handling, and extensive configuration options.

Capabilities

Token Encoding

Creates JWT tokens from claims dictionaries with support for various signing algorithms and additional headers.

def encode(claims, key, algorithm='HS256', headers=None, access_token=None):
    """
    Encodes a claims set and returns a JWT string.
    
    Args:
        claims (dict): A claims set to sign. Can include standard claims
            (iss, sub, aud, exp, nbf, iat, jti) and custom claims
        key (str or bytes or dict): The key to use for signing. Supports:
            - String secrets for HMAC algorithms
            - RSA/EC private keys in PEM format
            - JWK dictionaries
        algorithm (str): The algorithm to use for signing. Defaults to 'HS256'.
            Supported algorithms: HS256, HS384, HS512, RS256, RS384, RS512,
            ES256, ES384, ES512
        headers (dict, optional): Additional headers to include in the JWT header.
            Will override default headers with the same keys
        access_token (str, optional): If present, the 'at_hash' claim will be
            calculated and added to the claims
    
    Returns:
        str: The JWT token string in the format header.payload.signature
    
    Raises:
        JWTError: If there is an error encoding the claims
    """

Usage Examples:

from jose import jwt
from jose.constants import ALGORITHMS

# Basic HMAC signing
token = jwt.encode({'user': 'john', 'role': 'admin'}, 'secret', algorithm=ALGORITHMS.HS256)

# With expiration time
import time
claims = {
    'user': 'jane', 
    'exp': int(time.time()) + 3600,  # Expires in 1 hour
    'iat': int(time.time()),         # Issued now
    'iss': 'my-app'                  # Issuer
}
token = jwt.encode(claims, 'secret')

# RSA signing with private key
rsa_private_key = """-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC...
-----END PRIVATE KEY-----"""

token = jwt.encode({'user': 'alice'}, rsa_private_key, algorithm=ALGORITHMS.RS256)

# With additional headers
headers = {'kid': 'key-1', 'typ': 'JWT'}
token = jwt.encode({'user': 'bob'}, 'secret', headers=headers)

# With access token hash for OpenID Connect
access_token = 'SlAV32hkKG'
token = jwt.encode({'user': 'charlie'}, 'secret', access_token=access_token)

Token Decoding and Verification

Decodes and verifies JWT tokens with comprehensive claim validation and flexible verification options.

def decode(token, key, algorithms=None, options=None, audience=None, issuer=None, subject=None, access_token=None):
    """
    Decodes and verifies a JWT token.
    
    Args:
        token (str): The JWT token to decode
        key (str or bytes or dict or list): The verification key(s). Supports:
            - String secrets for HMAC algorithms
            - RSA/EC public keys in PEM format
            - JWK dictionaries
            - List of keys to try multiple keys
        algorithms (str or list): Allowed algorithms for verification. If None,
            raises an error. Use specific algorithms like ['HS256'] for security
        options (dict, optional): Verification options controlling which claims
            to verify and validation behavior
        audience (str, optional): Expected audience claim ('aud'). Token must
            contain this exact audience value
        issuer (str or list or tuple, optional): Expected issuer claim(s) ('iss').
            Token issuer must match one of the provided values
        subject (str, optional): Expected subject claim ('sub'). Token must
            contain this exact subject value
        access_token (str, optional): Access token for 'at_hash' verification
            in OpenID Connect scenarios
    
    Returns:
        dict: The decoded payload claims
    
    Raises:
        JWTError: If the token is invalid or verification fails
        ExpiredSignatureError: If the token has expired
        JWTClaimsError: If claim validation fails
    """

Verification Options:

The options parameter accepts a dictionary with the following keys:

# Default options
options = {
    'verify_signature': True,    # Verify the token signature
    'verify_exp': True,         # Verify expiration time claim
    'verify_nbf': True,         # Verify not before time claim  
    'verify_iat': True,         # Verify issued at time claim
    'verify_aud': True,         # Verify audience claim
    'verify_iss': True,         # Verify issuer claim
    'verify_sub': True,         # Verify subject claim
    'verify_jti': True,         # Verify JWT ID claim
    'require_exp': False,       # Require exp claim to be present
    'require_iat': False,       # Require iat claim to be present
    'require_nbf': False,       # Require nbf claim to be present
    'require_aud': False,       # Require aud claim to be present
    'require_iss': False,       # Require iss claim to be present
    'require_sub': False,       # Require sub claim to be present
    'require_jti': False,       # Require jti claim to be present
    'leeway': 0                 # Leeway in seconds for time-based claims
}

Usage Examples:

from jose import jwt
from jose.exceptions import ExpiredSignatureError, JWTError
from datetime import timedelta

# Basic verification
try:
    claims = jwt.decode(token, 'secret', algorithms=['HS256'])
    print(f"User: {claims['user']}")
except JWTError as e:
    print(f"Token validation failed: {e}")

# Verification with audience and issuer
claims = jwt.decode(
    token, 
    'secret', 
    algorithms=['HS256'],
    audience='my-app',
    issuer='trusted-issuer'
)

# Verification with leeway for clock skew
options = {'leeway': 30}  # 30 seconds leeway
claims = jwt.decode(token, 'secret', algorithms=['HS256'], options=options)

# Skip signature verification (for debugging only)
options = {'verify_signature': False}
claims = jwt.decode(token, 'secret', algorithms=['HS256'], options=options)

# Require specific claims
options = {
    'require_exp': True,
    'require_iss': True,
    'require_aud': True
}
claims = jwt.decode(token, 'secret', algorithms=['HS256'], options=options)

# Multiple key verification (JWK set scenario)
keys = [
    {'kty': 'oct', 'k': 'key1'},
    {'kty': 'oct', 'k': 'key2'},
    'backup-secret'
]
claims = jwt.decode(token, keys, algorithms=['HS256'])

# RSA public key verification
rsa_public_key = """-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...
-----END PUBLIC KEY-----"""

claims = jwt.decode(token, rsa_public_key, algorithms=['RS256'])

Header and Claims Inspection

Retrieve JWT headers and claims without performing verification, useful for debugging and token inspection.

def get_unverified_header(token):
    """
    Get JWT header without verification.
    
    Args:
        token (str): The JWT token
    
    Returns:
        dict: The JWT header dictionary
    
    Raises:
        JWTError: If the token format is invalid
    """

def get_unverified_headers(token):
    """
    Get JWT header without verification (alias for get_unverified_header).
    
    Args:
        token (str): The JWT token
    
    Returns:
        dict: The JWT header dictionary
    
    Raises:
        JWTError: If the token format is invalid
    """

def get_unverified_claims(token):
    """
    Get JWT payload claims without verification.
    
    Args:
        token (str): The JWT token
    
    Returns:
        dict: The JWT payload claims dictionary
    
    Raises:
        JWTError: If the token format is invalid
    """

Usage Examples:

# Inspect token header (useful for getting 'kid' for key selection)
header = jwt.get_unverified_header(token)
print(f"Algorithm: {header['alg']}")
print(f"Key ID: {header.get('kid')}")

# Inspect token claims (useful for debugging expired tokens)
claims = jwt.get_unverified_claims(token)
print(f"Issuer: {claims.get('iss')}")
print(f"Subject: {claims.get('sub')}")
print(f"Expires: {claims.get('exp')}")

# Conditional verification based on header
header = jwt.get_unverified_header(token)
if header['alg'] == 'HS256':
    claims = jwt.decode(token, hmac_secret, algorithms=['HS256'])
elif header['alg'] == 'RS256':
    claims = jwt.decode(token, rsa_public_key, algorithms=['RS256'])

Standard JWT Claims

The JWT specification defines several standard claims:

# Standard claims supported by python-jose
claims = {
    'iss': 'issuer',           # Issuer - who issued the token
    'sub': 'subject',          # Subject - who the token is about
    'aud': 'audience',         # Audience - who the token is intended for
    'exp': 1234567890,         # Expiration time (Unix timestamp)
    'nbf': 1234567890,         # Not before time (Unix timestamp)
    'iat': 1234567890,         # Issued at time (Unix timestamp)
    'jti': 'unique-id',        # JWT ID - unique identifier for the token
    'at_hash': 'hash-value'    # Access token hash (OpenID Connect)
}

Error Handling

JWT operations can raise several specific exceptions:

class JWTError(JOSEError):
    """Base exception for JWT-related errors."""

class JWTClaimsError(JWTError):
    """JWT claims validation failed."""

class ExpiredSignatureError(JWTError):
    """JWT token has expired."""

Common Error Scenarios:

from jose import jwt
from jose.exceptions import JWTError, ExpiredSignatureError, JWTClaimsError

try:
    claims = jwt.decode(token, key, algorithms=['HS256'], audience='my-app')
except ExpiredSignatureError:
    # Token has expired (exp claim)
    print("Token has expired")
except JWTClaimsError as e:
    # Claims validation failed (aud, iss, sub, etc.)
    print(f"Claims validation failed: {e}")
except JWTError as e:
    # Other JWT errors (invalid format, signature, etc.)
    print(f"JWT error: {e}")

OpenID Connect Support

The library provides built-in support for OpenID Connect JWT features:

# Access token hash calculation (at_hash claim)
access_token = 'SlAV32hkKG'
id_token = jwt.encode(
    {'sub': '12345', 'aud': 'client-id'}, 
    key, 
    access_token=access_token
)

# Verification includes at_hash validation
claims = jwt.decode(
    id_token, 
    key, 
    algorithms=['HS256'],
    access_token=access_token
)

Best Practices

  1. Always specify algorithms: Never use algorithms=None in production
  2. Use appropriate algorithms: HS256 for symmetric keys, RS256/ES256 for asymmetric
  3. Validate claims: Always verify aud, iss, and other relevant claims
  4. Handle expiration: Use appropriate exp times and handle ExpiredSignatureError
  5. Clock skew: Use leeway option to handle small time differences between systems
  6. Key management: Rotate keys regularly and use kid header for key identification

Install with Tessl CLI

npx tessl i tessl/pypi-python-jose

docs

constants-algorithms.md

index.md

jwe-operations.md

jwk-management.md

jws-operations.md

jwt-operations.md

tile.json