Skip to content

MCP OAuth: optional additional signing algorithms (ES256 no-dep; EdDSA on demand) #127

Description

@heskew

Optional additional MCP signing algorithms (ES256 now-capable; EdDSA on demand)

Stage 4 (#94 / PR #126) ships MCP access-token signing as RS256 only — the universally-interoperable default. This tracks adding algorithm choice if a deployment ever needs it. Low priority: no spec or known MCP client requires anything beyond RS256.

ES256 — cheap, no new dependency

jsonwebtoken@9 already supports ES256/384/512 (confirmed: it's in the @types/jsonwebtoken Algorithm union and the jwa README). Adding it is a small, dependency-free change:

  • Generate an EC P-256 keypair (generateKeyPair('ec', { namedCurve: 'P-256' })) when mcp.signingAlgorithm === 'ES256'.
  • Pass algorithm: 'ES256' to jwt.sign (the issuer is otherwise unchanged).
  • JWK serialization already works — node:crypto createPublicKey(pem).export({ format: 'jwk' }) emits EC JWKs (kty: "EC", crv, x, y); generalize publicKeyToJwk beyond the current RSA-only n/e.
  • Re-advertise ES256 in id_token_signing_alg_values_supported (wellKnown.ts) conditioned on what's configured.

ES256 is the conventional "modern" upgrade (smaller keys/signatures than RSA, broad client support) and is the one to add first if asked.

EdDSA — on demand only

jsonwebtoken cannot emit EdDSA. Two options, neither blocking:

  • node:crypto directly — sign(null, data, ed25519PrivateKey) works (verified, 64-byte sig); the JWT (base64url(header).base64url(payload).base64url(sig)) would be assembled by hand. Zero new deps but more code.
  • jose — clean JOSE implementation that handles EdDSA (and everything else) without hand-rolling. A new dependency; only worth it if EdDSA is actually required (or if we choose to standardize the whole issuer on jose).

EdDSA has the weakest client/library ecosystem support of the three; implement only when a specific client needs it.

Non-breaking

Tokens carry kid and clients verify via JWKS, so a new algorithm is additive: publish a second JWK, sign new tokens with the new alg, old RS256 tokens keep verifying. No migration.

Related


🤖 Generated with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions