Repository navigation
First stable release. The API is settled, and the sharp edge from 0.2.0 — a
model built from a dict looking exactly like a verified one — now has a way to
turn it off.
Full documentation: [pydantic-jwt.dmi03.com](https://pydantic-jwt.dmi03.com)
Added
verified_only— a model withmodel_config = ConfigDict(verified_only=True)
accepts nothing but a token string whose signature was checked. A claims dict
arriving from a request body is rejected withjwt_unverified_payload, so a
JWTModelcan safely be a field type. Off by default; models that read
incoming tokens should set it.from_claims()— build a model from claim values on averified_only
model, where the plain constructor is refused. Claims are still validated, and
a validation context can be passed as the first argument.
Changed
str(token)no longer signs. A model now stringifies like any other
Pydantic model, showing its claims. Signing happens only where you ask for it:
token.generate()ortoken.jwt_str.
Breaking changes
str(token) and f"{token}" used to return a signed, replayable token. They
now return the claims. Nothing raises — the value is simply no longer a token —
so grep for it:
# before
headers = {"Authorization": f"Bearer {token}"}
response = TokenPair(access_token=str(token))
# after
headers = {"Authorization": f"Bearer {token.jwt_str}"}
response = TokenPair(access_token=token.generate())The reason for the change: logger.info("token=%s", token) used to write a live
credential into the logs, where anyone who can read them can replay it until it
expires.
Models that opt into verified_only=True also lose the plain constructor —
use from_claims() there. Existing models are unaffected.
Requirements
Python 3.10+, Pydantic 2.10+, PyJWT.
pip install pydantic-jwt