Error message
It is required that you pass in a value for the "algorithms" argument when calling decode().
PyJWT (Python) — jwt.exceptions.DecodeError
What it means
Since PyJWT 2.0, jwt.decode() refuses to run without an explicit algorithms list. This is not pedantry: deriving the algorithm from the token's own header enables algorithm-confusion attacks (e.g. verifying an HS256 token with an RSA public key as the HMAC secret). The verifier — configured server-side, out of the attacker's reach — must state what it accepts, and PyJWT enforces that contract at the API level so the unsafe call shape is simply impossible to write.
Why it happens
Code written for PyJWT 1.x
commonPyJWT 1.x allowed jwt.decode(token, key) and guessed the algorithm. The 2.0 release (2020) made algorithms mandatory; any dependency bump across that boundary surfaces this error in previously working code.
Tutorial or LLM-generated snippet omitted it
commonMany older examples on the web still show two-argument decode() calls. The snippet runs fine on PyJWT 1.x pinned environments and fails on any modern install.
A shared auth helper hides the decode call
occasionalWhen a small internal utility wraps jwt.decode(), a PyJWT upgrade breaks every service importing the helper at once, and the traceback points at the wrapper rather than the calling code. Framework integrations (Flask-JWT-Extended, DRF SimpleJWT) pass algorithms internally — hand-rolled wrappers are the usual site of the omission.
How to fix it
- 1.
State the algorithm explicitly
Pass exactly the algorithm(s) your issuer uses — for ECDSA-signed tokens typically ES256. If several token types flow through one service, give each issuer its own allowlist rather than merging them all into one permissive list.
python import jwt payload = jwt.decode( token, public_key_pem, algorithms=["ES256"], # required — and a security control, not boilerplate audience="api://orders", ) - 2.
For inspection without verification, say so explicitly
If you only need to read claims (debugging, logging), disable verification deliberately — and never feed the result into authorization decisions.
python claims = jwt.decode(token, options={"verify_signature": False}) # or just the header: header = jwt.get_unverified_header(token)