Unable to parse JWK in Java

Issue #441 invalid
Former user created an issue

I implemented a rest authorization server that returns the public-key for a given keyId in the JWK format using the com.nimbusds:nimbus-jose-jwt:9.13 package. The code looks something like this:

@RequestMapping(value = "/oauth2", produces = APPLICATION_JSON_VALUE)
public interface Rest {
...
    @GetMapping("/public-key/{keyId}")
    @Operation(summary = "Return the public key corresponding to the key id")
    JWK getPublicKey(@PathVariable String keyId);
}

public class RestController implements Rest {
.....
 public JWK getPublicKey(String keyId) {
         byte[] publicKeyBytes = ....
         RSAPublicKey publicKey = (RSAPublicKey) keyFactory.generatePublic(new X509EncodedKeySpec(publicKeyBytes));
         JWK jwk = new RSAKey.Builder(publicKey)
                .keyID(keyId)
                .algorithm(new Algorithm(publicKey.getAlgorithm()))
                .keyUse(KeyUse.SIGNATURE)
                .build();
         return jwk;
    }
}

This code returns a JWK key in the following format:

{
    "keyStore": null,
    "private": false,
    "publicExponent": {},
    "modulus": {},
    "firstPrimeFactor": null,
    "secondPrimeFactor": null,
    "firstFactorCRTExponent": null,
    "secondFactorCRTExponent": null,
    "firstCRTCoefficient": null,
    "otherPrimes": [],
    "requiredParams": {
        "e": "some-valid-exponent",
        "kty": "RSA",
        "n": "some-valid-modulus"
    },
    "privateExponent": null,
    "x509CertChain": null,
    "algorithm": {
        "name": "RSA",
        "requirement": null
    },
    "keyOperations": null,
    "keyID": "some-valid-key-id",
    "x509CertURL": null,
    "x509CertThumbprint": null,
    "x509CertSHA256Thumbprint": null,
    "parsedX509CertChain": null,
    "keyUse": {
        "value": "sig"
    },
    "keyType": {
        "value": "RSA",
        "requirement": "REQUIRED"
    }
}

On the client side (java), I try to parse the jwk with the following code:

public JWK getPublicKey(String keyId) {
 String json = restTemplate.getForObject(publicUrl + "/oauth2/public-key/" + keyId, String.class);
        try {
            return JWK.parse(json);
        } catch (ParseException e) {
            log.error("Unable to parse JWK", e);
            return null;
        }
}

However, the client is unable to parse the key since parse throws an exception (Missing parameter "kty"). I see that JWK.parse requires a kty key in main JWT json body, while the default serialization of JWK embeds the kty key within requiredParams key. When I try jwk.toString(), I do see the kty key in the main json body.

Why doesn't serialization/deserialization of the native JWK object work in a straight-forward manner? What would be the best way to fix this without implementing a custom jwt structure or a serializer/deserializer?

Comments (4)

  1. Vidyabhushan Mohan

    Thanks for responding. I really appreciate it. Yes, I already changed it to Map<String, Object> to make it work.

    However, I was wondering that since this package creates and provides the JWK object, it would also provide the correct serializer/deserializer along with it (not a String or Map, but JWK). If you don’t think so, please feel free to close this issue.

  2. Yavor Vasilev

    I’m not sure there is a reliable way to indicate to frameworks how the object should be serialised to produce a JWK compliant JSON object.

    What you did - toJSONObject was more likely to succeed.

    To the 100% sure the serialisation is JWK compliant the toJSONString is the method.

  3. Log in to comment