JWT EdDSA (Ed25519)
JWT EdDSA (Ed25519) is the most modern signing algorithm: deterministic signing eliminates the ECDSA nonce risk, 64-byte signatures, fastest verification. Learn library support, sign/verify code, and tradeoffs.
EdDSA (Edwards-curve Digital Signature Algorithm) using Ed25519 is the most modern JWT signing algorithm. It produces 64-byte signatures (same as ES256) and signs deterministically: no random nonce: which eliminates the entire class of ECDSA nonce-reuse attacks (including the 2010 PS3 private-key extraction). It is also the fastest JWT signing algorithm. Defined in RFC 8037.
Key facts and signature size
| Property | EdDSA |
|---|---|
| Type | Asymmetric (Edwards-curve, Ed25519) |
| Key | 256-bit Ed25519 key |
| Signature size | 64 bytes (same as ES256) |
| Security | ~128-bit; deterministic signing (no nonce) |
| Compatibility | Growing: jose, PyJWT ≥2.x, jjwt, go-jose; not jsonwebtoken |
When to use
Use EdDSA for greenfield systems where your full library stack supports it: deterministic signing closes the ECDSA nonce risk, signatures are 64 bytes, and signing/verification are the fastest of any JWT algorithm. EdDSA is the strongest choice when you control the issuer and every verifier and can confirm support across the whole path.
When not to use
EdDSA support is not universal: jsonwebtoken (the most popular Node.js library) does not support it: use jose instead. Older deployments, FIPS-restricted environments, and some cloud-provider token-validation toolchains may not support EdDSA. If you integrate with third-party systems or identity providers that default to RS256, EdDSA may not be accepted. Always verify support across every library in your verification path before adopting it.
Code examples
Generate an Ed25519 key pair
# OpenSSL 1.1.1+
openssl genpkey -algorithm ed25519 -out ed25519-private.pem
openssl pkey -pubout -in ed25519-private.pem -out ed25519-public.pem
// Node.js
const { generateKeyPairSync } = require("crypto");
const { privateKey, publicKey } = generateKeyPairSync("ed25519", {
publicKeyEncoding: { type: "spki", format: "pem" },
privateKeyEncoding: { type: "pkcs8", format: "pem" },
});
Sign and verify (Node.js: jose, not jsonwebtoken)
import { SignJWT, jwtVerify, importPKCS8, importSPKI } from "jose";
const privateKey = await importPKCS8(edPrivateKeyPem, "EdDSA");
const publicKey = await importSPKI(edPublicKeyPem, "EdDSA");
const token = await new SignJWT({ sub: "user_123" })
.setProtectedHeader({ alg: "EdDSA", kid: "ed25519-key-v1" })
.setExpirationTime("15m")
.setIssuer("https://auth.example.com")
.setAudience("https://api.example.com")
.sign(privateKey);
const { payload } = await jwtVerify(token, publicKey, {
issuer: "https://auth.example.com",
audience: "https://api.example.com",
});
Frequently asked questions
-
What is EdDSA in JWT and why is it more secure than ECDSA?
EdDSA (Edwards-curve Digital Signature Algorithm) using Ed25519 is a JWT signing algorithm defined in RFC 8037. It is deterministic: no random nonce is generated during signing, so the signature for a given private key and message is always the same value. This eliminates the entire class of ECDSA nonce-reuse attacks: where a reused or weak nonce lets an attacker recover the private key (as happened with the PS3 in 2010). EdDSA also produces 64-byte signatures and is the fastest JWT signing algorithm.
-
Does jsonwebtoken support EdDSA?
No. The jsonwebtoken package does not support EdDSA. Use the jose library instead, which supports EdDSA natively via importPKCS8/importSPKI with the 'EdDSA' algorithm. PyJWT 2.x supports EdDSA (with the cryptography backend), jjwt supports it in recent versions (often requiring BouncyCastle), go-jose supports it, and Rust's jsonwebtoken crate has incomplete EdDSA support in some versions: check the release notes for your pinned version.
-
Is EdDSA or ES256 better for a new JWT system?
EdDSA is cryptographically stronger (deterministic signing eliminates the nonce risk) and equally fast with the same 64-byte signature size. ES256 has broader library and identity-provider support. If your full stack supports EdDSA, prefer it. If you integrate with third-party systems or libraries that do not support EdDSA, use ES256: the nonce risk is handled correctly by every modern library's CSPRNG, so ES256 is safe in practice.