Skip to content
ecdsa.com

Sign an ES256 JWT · Python

How to sign a JWT with ES256 in Python

To sign a JWT with ES256 in Python, PyJWT's jwt.encode takes the claims, a PEM private key and algorithm="ES256"; the cryptography package does the ECDSA work and PyJWT converts the signature into the 64-byte JWS form. The run checks the token with OpenSSL against the public key, independently of PyJWT.

Tested with PyJWT 2.15.1 (Python 3.14.8, cryptography 50.0.2).

sign.py — ES256 with PyJWT and a PEM key
import time
import jwt # PyJWT; ES256 needs the cryptography package: pip install "pyjwt[crypto]==2.15.1"
with open("key.pem") as f:
private_key = f.read() # PEM text; PyJWT loads it with cryptography
now = int(time.time()) # whole seconds, as NumericDate expects
token = jwt.encode(
{
"iss": "https://issuer.example.com",
"sub": "user-42",
"aud": "api://orders",
"iat": now,
"exp": now + 15 * 60,
},
private_key,
algorithm="ES256",
headers={"kid": "2026-10"},
)
print(token)

How it works

  1. jwt.encode accepts the PEM text directly (PKCS#8 or EC PRIVATE KEY) and loads it with cryptography.
  2. headers={"kid": "2026-10"} adds the key id; PyJWT always writes alg and typ itself.
  3. iat and exp are integers here; a datetime also works and is converted to whole seconds.
  4. PyJWT 2.x returns the token as str (1.x returned bytes), so it can be printed or put in a header as is.

Gotchas

  • Plain pip install pyjwt cannot sign ES256: NotImplementedError: Algorithm 'ES256' could not be found. Do you have cryptography installed?. Install pyjwt[crypto].
  • The key must match the algorithm: a P-384 key with algorithm="ES256" raises InvalidKeyError: The key's curve 'secp384r1' does not match the expected curve 'secp256r1' for this algorithm.
  • Passing the public key, or the PEM as a secret for HS256, is a different mistake with a different error — see the related error pages; ES256 always signs with the private key.
  • jwt.encode does not add exp or iat on its own. A token without exp never expires, and most verifiers accept it unless told to require the claim.

Related recipes