Skip to main content

Jam

Jam

Python Version PyPI Version PyPI Downloads Tests License

Jam is a typed, modular authentication and authorization framework for Python. It brings tokens, delegated credentials, sessions, identity protocols, and policy enforcement behind one consistent API without forcing applications into a particular web framework.

Use the high-level Jam or AsyncJam facade for complete authentication flows, or use the JOSE, PASETO, Macaroon, SAML, OTP, session, and OAuth2 modules independently.

What Jam provides

Area Capabilities
Credentials JWT, JWS, JWE, PASETO v1-v4, Macaroons, and SAML 2.0
Stateful authentication Sessions and shared credential token lists
Identity and verification OAuth2 clients, HOTP, and TOTP
Authorization Typed principals, credential constraints, contextual policy rules, and deny-by-default evaluation
Key management In-memory and file-backed keychains, rotation, historical-key verification, and revocation
Integrations Django, Django REST Framework, Django Modern REST, FastAPI, Starlette, Litestar, and Flask
Configuration Python dictionaries, TOML, YAML, and JSON with environment-variable substitution
Runtime model Synchronous and asynchronous facades with native async I/O backends

Jam keeps optional features optional. The core package depends only on cryptography; integrations and storage clients are installed through extras when needed.

Installation

Jam requires Python 3.10 or newer.

pip install jamlib

Install only the optional dependencies your application uses:

pip install "jamlib[redis]"    # Redis sessions and token lists
pip install "jamlib[oauth2]"   # OAuth2 HTTP clients
pip install "jamlib[yaml]"     # YAML configuration
pip install "jamlib[fastapi]"  # FastAPI integration
pip install "jamlib[django]"   # Django integration
pip install "jamlib[drf]"      # Django REST Framework integration

Other extras include cli, json, toml, starlette, litestar, flask, and dmr.

Quickstart

Create a minimal config.toml:

[jam.jose.jwt]
alg = "HS256"
secret_key = "$JWT_SECRET_KEY"

[jam.authz.rules]
"profile:read" = ["*"]
"post:create" = ["is_authenticated"]

Set a sufficiently strong secret outside the configuration file:

export JWT_SECRET_KEY="replace-with-at-least-32-random-characters"

Define the application subject and use the issue-authenticate-authorize flow:

from dataclasses import dataclass

from jam import BaseSubject, Jam


@dataclass
class User(BaseSubject):
    id: str
    email: str
    is_authenticated: bool = True


jam = Jam(config="config.toml", subject=User)
user = User(id="1", email="user@example.com")

token = jam.issue(
    user,
    via="jwt",
    exp=3600,
    permissions=["profile:read", "post:create"],
)

principal = jam.authenticate(token, via="jwt")

assert principal.subject == user
assert jam.authorize(principal, "post:create")
assert not jam.authorize(principal, "post:delete")

Authentication returns a Principal: the verified subject, registered and application claims, permissions, credential type, and any constraints carried by the credential. Authorization evaluates credential constraints before server-side policy, so a policy cannot widen authority granted by a token or Macaroon.

One facade, multiple credential types

The facade selects a configured mechanism through via:

jwt = jam.issue(user, via="jwt", permissions=["profile:read"])
paseto = jam.issue(user, via="paseto", permissions=["profile:read"])
macaroon = jam.issue(user, via="macaroon", permissions=["profile:read"])
saml_response = jam.issue(user, via="saml")

principal = jam.authenticate(jwt, via="jwt")

Modules are also available directly when lower-level protocol control is needed:

decoded = jam.macaroon.decode(macaroon)
attenuated = decoded.add_caveat(b"permission = profile:read")

header_and_payload = jam.jwt.decode(jwt)

Only configured modules are available. Accessing a missing module fails with a JamConfigurationError instead of an untyped None attribute error.

Asynchronous applications

AsyncJam provides native async session, token-list, and OAuth2 operations. Cryptography, OTP, Macaroon processing, and authorization remain synchronous because they do not cross an I/O boundary.

from jam.aio import AsyncJam


jam = AsyncJam(config="config.toml", subject=User)

token = await jam.issue(user, via="jwt", exp=3600)
principal = await jam.authenticate(token, via="jwt")

allowed = jam.authorize(principal, "profile:read")

await jam.aclose()

AsyncJam can also be used as an async context manager when it owns I/O clients:

async with AsyncJam(config="config.toml", subject=User) as jam:
    token = await jam.issue(user, via="session")

Authorization that credentials cannot bypass

Jam separates identity, credential authority, and application policy:

  1. authenticate() verifies the credential and creates a Principal.
  2. Credential constraints are evaluated first.
  3. The configured server-side policy evaluates the requested permission and context.
  4. Any failed constraint or policy rule denies access.
from jam.authz import AuthorizationContext


context = AuthorizationContext(
    request=request,
    resource=article,
)

if not jam.authorize(principal, "article:update", context):
    raise PermissionError

Macaroon caveats, token permissions, time restrictions, and resource-aware policy checks can only reduce authority; they cannot silently grant permissions that the credential did not carry.

Framework integrations

Jam integrations are deliberately thin: they extract credentials, delegate to Jam or AsyncJam, and expose the resulting principal to the framework.

Standalone modules

The facade is optional. Protocol implementations can be constructed directly:

from jam.jose import JWT
from jam.paseto import PASETOv4


jwt = JWT(alg="HS256", secret_key="replace-with-a-strong-secret")
paseto = PASETOv4(purpose="local", secret_key=b"\x00" * 32)

See the documentation for:

Development

git clone https://github.com/mkrdnk/jam.git
cd jam
uv sync --group tests --all-extras
uv run pytest -x

Jam is licensed under the Apache License 2.0.

Metadata

Release files for jamlib 4.2.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for jamlib 4.2.1
File Size Uploaded
jamlib-4.2.1.tar.gz 154.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for jamlib 4.2.1
File Interpreter ABI Platform
jamlib-4.2.1-py3-none-any.whl Python 3 none any Details

Total release size: 367.3 kB

Release files / jamlib-4.2.1.tar.gz

Download URL jamlib-4.2.1.tar.gz
Size 154.3 kB
Tags Source
SHA-256 checksum
How to use checksums
ebe50650f109840d8609682c7b0b986b96ba5e33a98da729aadd310185f66649
BLAKE2b-256 checksum
How to use checksums
bc925484c200614ef4e104d12cf9a0a088649c472e227921890c3736607125bc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.17 {"installer":{"name":"uv","version":"0.12.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / jamlib-4.2.1-py3-none-any.whl

Download URL jamlib-4.2.1-py3-none-any.whl
Size 213.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5f909709a444064b7c402008fb2a3b4ed401fb82c1c6069995bb9df61ba399a4
BLAKE2b-256 checksum
How to use checksums
c22b9d76a13112825b0e99c4f4746aaef476812d3071334e3310eef457c85038
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.17 {"installer":{"name":"uv","version":"0.12.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

This release

4.2.1 This release

2 release files

4.2.0

2 release files

4.1.3

2 release files

4.1.2

2 release files

4.1.1

2 release files

4.0.0

2 release files

3.3.0

2 release files

3.2.0

2 release files

3.1.2

2 release files

3.1.1

2 release files

3.1.0

2 release files

3.0.0

2 release files

2.5.6

2 release files

2.5.5

2 release files

2.5.3

2 release files

2.5.2

2 release files

2.5.1

2 release files

2.5.0

2 release files

2.4.2

2 release files

2.4.1

2 release files

2.4.0

2 release files

2.3.3

2 release files

2.3.2

2 release files

2.3.1

2 release files

2.3.0

2 release files

2.2.5

2 release files

2.2.4

2 release files

2.2.3

2 release files

2.2.2

2 release files

2.2.1

2 release files

2.2.0

2 release files

2.1.4

2 release files

2.1.3

2 release files

2.1.2

2 release files

2.1.1

2 release files

2.1.0

2 release files

2.0.0

2 release files

1.1.4

2 release files

1.1.2

2 release files

1.1.1

2 release files

1.1.0

2 release files

1.0.5

2 release files

1.0.4

2 release files

1.0.3

2 release files

1.0.1

2 release files

1.0.0

2 release files

0.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page