JSON Web Token (JWT) with ES256K (secp256k1) signature

Support for EC DSA signatures on the secp256k1 curve, which is used in Bitcoin and Ethereum, was added in version 5.9 of the Nimbus JOSE+JWT library.

  • JWS algorithm: ES256K
  • JWK curve name: secp256k1

The ES256K algorithm for JOSE is specified in COSE and JOSE Registrations for WebAuthn Algorithms.

How to generate an EC key pair on the secp256k1 curve?

import java.security.*;
import java.security.interfaces.*;
import com.nimbusds.jose.jwk.*;
import com.nimbusds.jose.jwk.gen.*;

// Generate EC key pair on the secp256k1 curve
ECKey ecJWK = new ECKeyGenerator(Curve.SECP256K1)
    .keyUse(KeyUSE.SIGNATURE)
    .keyID("123")
    .generate();

// Get the public EC key, for recipients to validate the signatures
ECKey ecPublicJWK = ecJWK.toPublicJWK();

To sign a JWT with ES256K on the secp256k1 curve:

import com.nimbusds.jose.*;
import com.nimbusds.jose.crypto.*;
import com.nimbusds.jwt.*;


// Sample JWT claims
JWTClaimsSet claimsSet = new JWTClaimsSet.Builder()
    .subject("alice")
    .build();

// Create JWT for ES256K alg
SignedJWT jwt = new SignedJWT(
    new JWSHeader.Builder(JWSAlgorithm.ES256K)
        .keyID(ecJWK.getKeyID())
        .build(),
    claimsSet);

// Sign with private EC key
jwt.sign(new ECDSASigner(ecJWK));

// Output the JWT
System.out.println(jwt.serialize());

// With line break for clarity:
// eyJraWQiOiIxMjMiLCJhbGciOiJFUzI1NksifQ.eyJzdWIiOiJhbGljZSJ9
// .zRQyjdmePW97V5JYbPxwOrrtL0MdDPuz7w9O0CWvF-U40g195qBuZ8fXH2
// XZi_-U4RdMr4JvbiTKXH1ClofZgw

To validate the ES256K signature:

import java.security.interfaces.*;
import com.nimbusds.jose.crypto.*;
import com.nimbusds.jwt.*;

// Parse the signed JWT
String jwtString =
"eyJraWQiOiIxMjMiLCJhbGciOiJFUzI1NksifQ.eyJzdWIiOiJhbGljZSJ9" +
".zRQyjdmePW97V5JYbPxwOrrtL0MdDPuz7w9O0CWvF-U40g195qBuZ8fXH2" +
"XZi_-U4RdMr4JvbiTKXH1ClofZgw";

SignedJWT jwt = SignedJWT.parse(jwtString);

// Verify the ES256K signature with the public EC key
assertTrue(jwt.verify(new ECDSAVerifier(ecPublicJWK)));

// Output the JWT claims: {"sub":"alice"}
System.out.println(jwt.getJWTClaimsSet().toJSONObject());