ES384 JWT Algorithm
ES384 uses the P-384 (secp384r1) elliptic curve with SHA-384. It provides a higher security margin than ES256 — approximately equivalent to RSA-7680 — while remaining far more efficient than RSA at that security level. P-384 is included in NIST's recommended curves and NSA Suite B.
Key Requirements
EC key pair on the P-384 (secp384r1) curve. Generate: openssl ecparam -name secp384r1 -genkey -noout -out ec-private.pem
JWT Header
Every JWT using ES384 has this header (base64url-encoded as the first segment):
{
"alg": "ES384",
"typ": "JWT"
}Code Examples
Node.js — Sign (jose library)
import { SignJWT, importPKCS8 } from 'jose'
const privateKey = await importPKCS8(process.env.EC_PRIVATE_KEY!, 'ES384')
export async function signToken(payload: Record<string, unknown>) {
return new SignJWT(payload)
.setProtectedHeader({ alg: 'ES384' })
.setIssuedAt()
.setExpirationTime('1h')
.sign(privateKey)
}Node.js — Verify (jose library)
import { jwtVerify, importSPKI } from 'jose'
const publicKey = await importSPKI(process.env.EC_PUBLIC_KEY!, 'ES384')
export async function verifyToken(token: string) {
const { payload } = await jwtVerify(token, publicKey, { algorithms: ['ES384'] })
return payload
}Python — PyJWT
import jwt
from cryptography.hazmat.primitives import serialization
with open("ec-private.pem", "rb") as f:
private_key = serialization.load_pem_private_key(f.read(), password=None)
with open("ec-public.pem", "rb") as f:
public_key = serialization.load_pem_public_key(f.read())
token = jwt.encode({"sub": "1234"}, private_key, algorithm="ES384")
payload = jwt.decode(token, public_key, algorithms=["ES384"])When to Use ES384
Systems requiring the NSA Suite B 192-bit security level (SECRET classification). Financial services, healthcare data, and government applications that must meet NIST SP 800-57 requirements for long-term data protection.
Security Considerations
P-384 is a NIST-standardised curve with extensive cryptographic review. Slightly slower than ES256 but still faster than RSA equivalents. The ECDSA nonce-reuse vulnerability (see ES256 notes) applies equally here.
Related Algorithms
Standardised in RFC 7518 §3.4 — JSON Web Algorithms (JWA).
Decode a real JWT
Paste any JWT into the debugger to inspect the header, payload, and verify an ES384 signature.
Open JWT DebuggerFrequently Asked Questions
How does ECDSA compare to RSA for JWT signing?
ECDSA provides equivalent security to RSA with much smaller keys: ES256 (P-256, 256-bit key) ≈ RSA-3072. This means smaller JWT signatures, faster verification, and shorter key material. ES256 is the preferred modern choice when asymmetric signing is needed.
What elliptic curve does ES256 use?
ES256 uses the P-256 curve (also known as secp256r1 or prime256v1). ES384 uses P-384 (secp384r1), and ES512 uses P-521 (secp521r1 — note: P-521, not P-512). The curve is specified in the 'crv' field of the JWK.
Is ECDSA safe from the nonce-reuse attack?
Modern ECDSA implementations in JavaScript (Node.js crypto, WebCrypto) and reputable libraries use the OS CSPRNG for nonce generation — making nonce reuse extremely unlikely. The infamous PS3 ECDSA attack happened because Sony used a constant nonce, not a random one. Using the jose or jsonwebtoken library protects you from this.
