Blog · Security

EdDSA vs RS256 for signing JWTs

EdDSA JWT signing with Ed25519 vs RS256: key and signature sizes, speed, safety, library support, and how to verify EdDSA tokens in Node.js with jose.

For signing JWTs, EdDSA with Ed25519 gives you much smaller keys and signatures than RS256, fast signing, deterministic signatures that don’t depend on a random number generator at signing time, and fewer parameters to get wrong. RS256 (RSA with SHA-256) has the advantage of near-universal library support and very cheap verification. If your verifiers use a modern JOSE library, EdDSA is the better default for new systems. If you must support old or constrained libraries that only know RS256, RS256 is still a safe choice with a 2048-bit or larger key.

Here’s how the two compare in detail, and how to verify an EdDSA JWT in Node.js.

What the algorithm names mean

A JWT’s header says how it was signed:

{ "alg": "EdDSA", "kid": "2026-10-a", "typ": "JWT" }
algAlgorithmKey type in JWKS
RS256RSASSA-PKCS1-v1_5 with SHA-256"kty": "RSA"
EdDSAEdwards-curve signature, here with the Ed25519 curve (RFC 8037)"kty": "OKP", "crv": "Ed25519"

Both are asymmetric. The issuer signs with a private key and publishes the public key in a JWKS, so any service can verify tokens without being able to mint them. That’s the property you want for ID and access tokens consumed by multiple apps and APIs. (HS256, a shared-secret HMAC, doesn’t have it: anyone who can verify can also sign.)

Size

Ed25519RSA-2048
Public key32 bytes256-byte modulus plus exponent
Signature64 bytes256 bytes
Signature in a JWT (base64url)86 characters342 characters

Signature size matters more than it sounds. JWTs travel in Authorization headers and cookies on every request, and cookies have size limits. Moving to RSA-3072 or RSA-4096 for a longer security margin makes signatures larger still, while Ed25519 stays at 64 bytes.

Here’s what an Ed25519 key looks like in a JWKS:

{
  "keys": [
    {
      "kty": "OKP",
      "crv": "Ed25519",
      "kid": "2026-10-a",
      "alg": "EdDSA",
      "use": "sig",
      "x": "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo"
    }
  ]
}

That x value is the entire public key.

Speed

The two algorithms have opposite performance profiles:

  • Signing: Ed25519 signing is much faster than RSA signing, which needs a private-key operation with a large modulus.
  • Verification: RSA verification with the standard public exponent is very cheap, and is typically faster than Ed25519 verification.

For most systems neither number is a bottleneck. An identity provider signs a handful of tokens per sign-in, and your API verifies one per request. Both are fast enough that network and database time dominate. Don’t choose on speed alone.

Safety and implementation pitfalls

This is where EdDSA earns its reputation.

Deterministic signatures. Ed25519 derives its per-signature nonce from the private key and the message. There’s no random value to generate at signing time, so a bad or repeated RNG output can’t leak the key. ECDSA (ES256) is the cautionary tale here: reusing or biasing its random nonce has exposed private keys in real systems.

Fewer knobs. Ed25519 has one curve, one hash and one encoding. RSA has key sizes, padding schemes (PKCS#1 v1.5 vs PSS) and exponent choices, and historically more room for subtle implementation flaws.

Key generation. An Ed25519 private key is 32 random bytes. RSA key generation involves finding large primes, which is slower and has had its own implementation bugs.

Neither algorithm protects you from the most common JWT mistakes, which happen in the verifier:

  • Accepting "alg": "none".
  • Letting the token header choose the algorithm, which enables algorithm-confusion attacks (for example, treating an RSA public key as an HMAC secret).
  • Skipping issuer, audience or expiry checks.

The fix is the same for both: pin the expected algorithm in your verification code and check every registered claim.

Library support

RS256 is supported by effectively every JWT library. EdDSA support is widespread in modern libraries, including jose for Node.js and browsers, and Ed25519 is available in Node’s built-in crypto module, Go’s standard library, and common Python, Java and .NET crypto libraries. Some older or minimal JWT libraries still only implement RSA and HMAC, so check yours before you commit. The verify tokens docs show how to check tokens from your API.

Verifying an EdDSA JWT in Node.js with jose

The jose library fetches and caches the JWKS, selects the key by kid, and verifies the signature and claims:

import { createRemoteJWKSet, jwtVerify } from "jose";

const issuer = "https://acme.gatekeepauth.com";
const JWKS = createRemoteJWKSet(new URL(`${issuer}/jwks.json`));

export async function verifyToken(token) {
  const { payload } = await jwtVerify(token, JWKS, {
    issuer,
    audience: "acme-notes",      // your client ID
    algorithms: ["EdDSA"],       // pin the algorithm
  });
  return payload; // sub, email, email_verified, exp, iat, ...
}

algorithms: ["EdDSA"] is the important line. Without it, the library would accept any algorithm the key type allows. With it, a token claiming a different algorithm is rejected before any signature check.

Create the JWKS object once at startup and reuse it. jose caches keys and only refetches when it sees a kid it doesn’t know, which is exactly what you want during key rotation.

Key rotation

Whichever algorithm you use, plan for rotation:

  1. Publish the new public key in the JWKS before signing with it.
  2. Start signing with the new key, identified by a new kid.
  3. Keep the old public key in the JWKS until every token signed with it has expired, plus a safety margin.
  4. Remove the old key.

Verifiers that look up keys by kid from a cached remote JWKS handle this with no deploys. Hard-coding a public key in your app does not.

When to pick which

Choose EdDSA whenChoose RS256 when
Your verifiers use modern JOSE librariesA verifier only supports RSA
Token size matters (cookies, headers, mobile)You need compatibility with older enterprise tooling
You want deterministic signing and fewer parametersYour HSM or KMS setup only offers RSA keys

How Gatekeep signs tokens

Gatekeep signs every ID and access token with Ed25519 (alg: EdDSA). Signing keys are encrypted at rest with AES-GCM and rotate over time; retiring keys stay in /jwks.json for 35 days so verifiers with cached keys keep working. Access and ID tokens last 15 minutes, which keeps the cost of a leaked token low.

Any JOSE library with EdDSA support can verify them using the snippet above. See verify tokens, the endpoints reference and the security model. For the flow that produces these tokens, read OAuth PKCE explained. Gatekeep is in early access: request access.

Delete the password field.

Passkey sign-in for every app you ship. Free up to 5,000 monthly active users.