You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
ConfigMeta metaclass (jam.utils.config_meta) — classes accept config / pointer kwargs; config values are injected into __init__ parameters by
signature, explicit kwargs always win
jam.lists module with BaseList, MemoryList, RedisList, JSONList
and the build_list(config) factory
jam.subject.BaseSubject — dataclass contract for auth subjects (mandatory id field) with generic to_dict() / from_dict() serialization
jam.authz — BasePolicy interface and declarative Policy built from
compact predicates or structured allow/deny rules; supports credential
permissions, permission wildcards, dynamic authorization context, all / any / not conditions and deny-by-default evaluation
Principal authentication result preserves the typed subject and verified
credential claims; AuthorizationContext supplies the current time,
resource, request and application attributes to authorization policies
Config-driven module init: JWT/JWS/JWE, PASETO (v1-v4), sessions
(redis/json), OAuth2 providers and authz are built directly from [jam] config sections
New Jam facade API:
issue(subject, via, exp/iss/aud/nbf/jti, permissions, **claims) —
issues a JWT, PASETO or session with per-credential permission grants; via is one of "jwt", "paseto" or "session"
authenticate(token, via) — verifies a JWT, JWE, PASETO or session and
returns a Principal; via is required
authorize(principal, permission, context=None) — checks credential
grants and the [jam.authz] policy
subject / config as class attributes overridable via __init__
Independent jam.aio.AsyncJam facade with awaitable issue() and authenticate(), native async Redis sessions/token lists and async OAuth2
HTTP; jam.aio.Jam remains an import-compatible alias
Async context management closes Redis and OAuth2 clients created by AsyncJam
Config caching — config files are parsed once and cached per
path + pointer (JAM_CONFIG_CACHING=true, default). Set JAM_CONFIG_CACHING=false to re-read config on every instance creation
for runtime config updates. Manual invalidation via jam.utils.config_maker.__config_cache_clear__
jam.utils.redaction.SensitiveDataFilter — attached to the "jam"
logger by default; redacts JWT/JWE/PASETO tokens, PEM private keys and key=value secrets from log records (disable with JAM_DEBUG=True)
NullHandler added to the "jam" logger so Jam emits no log output
unless the application configures logging
authz.Policy supports @-prefixed value references that resolve another
field path (e.g. subject.id == @context.resource.author_id) for
field-to-field comparisons
authz.Policy field resolution supports arbitrary objects (pydantic models,
ORM instances, plain classes) via public attributes, not just mappings and
dataclasses; methods, callables and private attributes are never evaluated.
Missing field values do not match; missing @ references raise a
configuration error (exists reports absence explicitly)
PASETO: BasePASETO.__init__(purpose, secret_key, list, config, pointer); .key() kept as an alias; white/black list handling moved into
the base (_list_add / _list_check)
Sessions: BaseSessionModule uses ConfigMeta with _SESSION_TYPE
validation (sessions_type kept as a deprecated alias)
OAuth2: create_instance replaced by build_clients(providers, serializer)
The module config schema moved from [jam.jwt] to [jam.jose.jwt]
PASETO v1–v4 refactored onto shared mixins in jam.paseto.__base__
(LegacyAEADMixin, XChaChaMixin, KeyLoadMixin); local encode/decode and
footer parsing are now defined once
JamConfigurationError raises in JWT/PASETO carry machine-readable error_code values (configuration.jwt.*, configuration.paseto.*)
Logging calls in hot paths (sign/verify/wrap/unwrap, sessions, lists) use
lazy %s formatting on module-level logging.getLogger(__name__) loggers
BaseJam.__init__ uses None defaults for config / plugins instead of
mutable class attributes
BaseSubject.from_dict ignores unknown keys; id is a plain field
annotation; dead __abstract_methods__ marker removed
authz.Policy._match compares field=value predicates literal-aware
(via ast.literal_eval) with a string fallback
Jam.issue(via="paseto") now forwards nbf to the PASETO payload
JamPASTOKeyVerificationError (typo) renamed to JamPASETOKeyVerificationError; JamPASETOInvalidPurpose now inherits from JamConfigurationError
Documentation refactoring. Migrate from mkdocs.
Deprecated
sessions_type parameter in session modules (use session_type)
Removed
jam.logger module with BaseLogger / JamLogger — all modules now use
the standard logging library with logging.getLogger(__name__) loggers
logger / log_level kwargs from Jam, BaseJam, JWT, JWS, JWE,
PASETO, session modules and lists; logging is configured through the
standard logging API instead
build_list(config, logger) — the logger argument is gone
Deprecated jam.jwt module and the [jam.jwt] → [jam.jose.jwt] config
migration
All deprecated Jam wrapper methods: jwt_make_payload, jwt_create, jwt_encode, jwt_decode, jws_sign, jws_verify, jwe_encrypt, jwe_decrypt, session_*, otp_*, oauth2_*, paseto_make_payload, paseto_create, paseto_decode — use the module attributes and the new issue / authenticate / authorize API
BaseJam old abstract interface and the MODULES factory map
Dead code: the jam.jose.lists package alias, MsgspecJsonEncoder, paseto.utils.__b64url_nopad__, and the never-raised exceptions JamJWTEmptySecretKey, JamJWTEmptyPrivateKey, JamJWTValidationError, JamJWKMissingParameterError
Fixed
KeyChain now generates the JOSE-mandated P-256, P-384 and P-521 curves for
ES256, ES384 and ES512, and rejects keys whose curve does not match alg
PASETO v1: dead length check on the local key no longer shadows key loading
JWT _detect_key_type tries PEM/DER public key loaders before falling back
to symmetric, so JWE with a public key is handled correctly
Jam.authenticate(via="jwe") routes JWE tokens to jwt.decrypt
JWS/JWE/JWT encode / decode raise JamConfigurationError with error_code when the module is not configured instead of a bare assert