Repository navigation
v4.0.0rc0
Pre-release
Pre-release
Added
ConfigMetametaclass (jam.utils.config_meta) — classes acceptconfig/
pointerkwargs; config values are injected into__init__parameters by
signature, explicit kwargs always winjam.listsmodule withBaseList,MemoryList,RedisList,JSONList
and thebuild_list(config)factoryjam.subject.BaseSubject— dataclass contract for auth subjects (mandatory
idfield) with genericto_dict()/from_dict()serializationjam.authz—BasePolicyinterface and declarativePolicybuilt from
compact predicates or structured allow/deny rules; supports credential
permissions, permission wildcards, dynamic authorization context,
all/any/notconditions and deny-by-default evaluationPrincipalauthentication result preserves the typed subject and verified
credential claims;AuthorizationContextsupplies 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
Jamfacade API:issue(subject, via=None, exp/iss/aud/nbf/jti, permissions, **claims)—
issues a JWT, PASETO or session with per-credential permission grants
(auto-detects whenvia=None)authenticate(token, via=None)— verifies a token/session and returns a
Principalauthorize(principal, permission, context=None)— checks credential
grants and the[jam.authz]policysubject/configas class attributes overridable via__init__
- Independent
jam.aio.AsyncJamfacade with awaitableissue()and
authenticate(), native async Redis sessions/token lists and async OAuth2
HTTP;jam.aio.Jamremains 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=falseto 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=valuesecrets from log records (disable withJAM_DEBUG=True)NullHandleradded to the"jam"logger so Jam emits no log output
unless the application configures loggingauthz.Policysupports@-prefixedvaluereferences that resolve another
field path (e.g.subject.id == @context.resource.author_id) for
field-to-field comparisonsauthz.Policyfield 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.
Structured rules fail closed when a referencedfieldor@-value is
missing (existsstill reports absence explicitly)- Key rotation manager
jam.keychain.
Changed
- JWT:
__init__acceptsconfig/pointer;listparameter accepts
dict | BaseList | None;decode()gainedcheck_list: bool = True - JWS/JWE:
config/pointerkwargs added - 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:
BaseSessionModuleusesConfigMetawith_SESSION_TYPE
validation (sessions_typekept as a deprecated alias) - OAuth2:
create_instancereplaced bybuild_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 JamConfigurationErrorraises in JWT/PASETO carry machine-readable
error_codevalues (configuration.jwt.*,configuration.paseto.*)- Logging calls in hot paths (sign/verify/wrap/unwrap, sessions, lists) use
lazy%sformatting on module-levellogging.getLogger(__name__)loggers BaseJam.__init__usesNonedefaults forconfig/pluginsinstead of
mutable class attributesBaseSubject.from_dictignores unknown keys;idis a plain field
annotation; dead__abstract_methods__marker removedauthz.Policy._matchcomparesfield=valuepredicates literal-aware
(viaast.literal_eval) with a string fallbackJam.issue(via="paseto")now forwardsnbfto the PASETO payloadJamPASTOKeyVerificationError(typo) renamed to
JamPASETOKeyVerificationError;JamPASETOInvalidPurposenow inherits from
JamConfigurationError- Documentation refactoring. Migrate from mkdocs.
Deprecated
sessions_typeparameter in session modules (usesession_type)
Removed
jam.loggermodule withBaseLogger/JamLogger— all modules now use
the standardlogginglibrary withlogging.getLogger(__name__)loggerslogger/log_levelkwargs fromJam,BaseJam,JWT,JWS,JWE,
PASETO, session modules and lists; logging is configured through the
standardloggingAPI insteadbuild_list(config, logger)— theloggerargument is gonejam.jose.create_jwt_instance/create_jws_instance/create_jwe_instance
/create_instancefactories — constructJWT/JWS/JWEdirectly- Deprecated
jam.jwtmodule and the[jam.jwt]→[jam.jose.jwt]config
migration - All deprecated
Jamwrapper 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/authorizeAPI BaseJamold abstract interface and theMODULESfactory map- Dead code: the
jam.jose.listspackage alias,MsgspecJsonEncoder,
paseto.utils.__b64url_nopad__, and the never-raised exceptions
JamJWTEmptySecretKey,JamJWTEmptyPrivateKey,
JamJWTValidationError,JamJWKMissingParameterError
Fixed
- PASETO v1: dead length check on the local key no longer shadows key loading
- JWT
_detect_key_typetries PEM/DER public key loaders before falling back
to symmetric, so JWE with a public key is handled correctly Jam.authenticate/ token auto-detection now routes JWE tokens (4 segments)
tojwt.decryptinstead of failing as a session- JWS/JWE/JWT
encode/decoderaiseJamConfigurationErrorwith
error_codewhen the module is not configured instead of a bare assert