Search code examples
javajsonjwtjose4j

Parser exception in JWT when encryption and signing is enabled


I'm new to JWT, learning through standalone code to understand JWT API's. Below code sign and encrypt JWT token from sender's end and it get validated at receiver's end.

Library: JOSE 0.4.1

package com.one00bytes.jwt;

public class JWTSignEncryption {

public static void main(String[] args) throws Exception {

    /***************************SENDER'S END ***********************************/

    JwtClaims claims = new JwtClaims();
    claims.setAudience("Admins");
    claims.setIssuer("CA");
    claims.setSubject("users");
    claims.setClaim("email", "[email protected]");
    claims.setClaim("Country", "Antartica");
    System.out.println(claims.toJson());

    //SIGNING
    RsaJsonWebKey jsonSignKey = RsaJwkGenerator.generateJwk(2048);
    JsonWebSignature jws = new JsonWebSignature();
    jws.setKey(jsonSignKey.getPrivateKey());
    jws.setPayload(claims.toJson());
    jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA512);
    String signedJwt = jws.getCompactSerialization();
    System.out.println("Signed ::" + signedJwt);


    //ENCRYPTING
    RsaJsonWebKey keyEncrypt = RsaJwkGenerator.generateJwk(2048);
    KeyGenerator keyGen = KeyGenerator.getInstance("AES");
    keyGen.init(256);
    SecretKey contentEncryptKey = keyGen.generateKey();

    JsonWebEncryption jwe = new JsonWebEncryption();
    jwe.setKey(keyEncrypt.getPublicKey());
    jwe.setPayload(signedJwt);
    jwe.setAlgorithmHeaderValue(KeyManagementAlgorithmIdentifiers.RSA_OAEP_256);
    jwe.setContentEncryptionKey(contentEncryptKey.getEncoded());
    jwe.setEncryptionMethodHeaderParameter(ContentEncryptionAlgorithmIdentifiers.AES_256_GCM);
    SecureRandom iv = SecureRandom.getInstance("SHA1PRNG");
    jwe.setIv(iv.generateSeed(32));
    String encryptedJwt = jwe.getCompactSerialization();
    System.out.println("Encrypted ::" + encryptedJwt);


    /***************************RECEIVER'S END ***********************************/ 

    JwtConsumer consumer = new JwtConsumerBuilder()
                            .setExpectedAudience("Admins")
                            .setExpectedIssuer("CA")
                            .setRequireSubject()
                            .setDecryptionKey(keyEncrypt.getPrivateKey())
                            .setVerificationKey(jsonSignKey.getPublicKey())
                            .build();
    JwtClaims receivedClaims = consumer.processToClaims(encryptedJwt);
    System.out.println("SUCESS :: JWT Validation :: " + receivedClaims);

}

}

Observing below exception when running this program:

Exception in thread "main" org.jose4j.jwt.consumer.InvalidJwtException: Unable to parse JWT Claim Set JSON: eyJhbGciOiJSUzUxMiJ9.eyJhdWQiOiJBZG1pbnMiLCJpc3MiOiJDQSIsInN1YiI6InVzZXJzIiwiaWF0IjoxNDM0NTM0MDgxLCJleHAiOjE0MzQ1MzQ2ODEsImp0aSI6IjJxUUpuMDVGY3RrLWF1VG1vVktuWXciLCJuYmYiOjE0MzQ1MzM5NjEsImVtYWlsIjoidXNlcnNAMTAwYnl0ZXMuY29tIiwiQ291bnRyeSI6IkFudGFydGljYSIsImhvYmJpZXMiOlsiQmxvZ2dpbmciLCJQbGF5aW5nIGNhcmRzIiwiR2FtZXMiXX0.soY_5Hbam569I-CnUW1F4GWdaqprh-XAOtAMOcb7zZSiRcIhXYUdJjEslrDbwphAP135SvmoXO4nVaVmo-d8oWREFYUeXEDzHbrqHNp7pp5pH6hGTJ5C4uE1UVzZ4bis3g_KEgZvEn31NnV4RcU_oRn2Q4inkrTlYKY-juEtCmpPQ0sSP4GiDbwVIfCj-kxZsKh_i9n28SSK890K3DIGiFWOUDwrnY4Yfr1UffsUS9ovyhtqrOcN4YsJR4XzGPaLehlR-qD7eOdAdmVb8RDtGKufNuCd7Q9OFfeKzBmGITHsvd6IPVYLLCfSCzO6PqQSIzkupl5D6HqoOqID8JZLxA
    at org.jose4j.jwt.JwtClaims.<init>(JwtClaims.java:50)
    at org.jose4j.jwt.JwtClaims.parse(JwtClaims.java:56)
    at org.jose4j.jwt.consumer.JwtConsumer.process(JwtConsumer.java:267)
    at org.jose4j.jwt.consumer.JwtConsumer.processToClaims(JwtConsumer.java:115)
    at com.one00bytes.jwt.JWTSignEncryption.main(JWTSignEncryption.java:76)
Caused by: org.jose4j.lang.JoseException: Parsing error: org.jose4j.json.internal.json_simple.parser.ParseException: Unexpected character (e) at position 0.
    at org.jose4j.json.JsonUtil.parseJson(JsonUtil.java:66)
    at org.jose4j.jwt.JwtClaims.<init>(JwtClaims.java:45)
    ... 4 more
Caused by: org.jose4j.json.internal.json_simple.parser.ParseException: Unexpected character (e) at position 0.
    at org.jose4j.json.internal.json_simple.parser.Yylex.yylex(Yylex.java:612)
    at org.jose4j.json.internal.json_simple.parser.JSONParser.nextToken(JSONParser.java:269)
    at org.jose4j.json.internal.json_simple.parser.JSONParser.parse(JSONParser.java:118)
    at org.jose4j.json.internal.json_simple.parser.JSONParser.parse(JSONParser.java:81)
    at org.jose4j.json.JsonUtil.parseJson(JsonUtil.java:62)
    ... 5 more

Signed JWT

eyJhbGciOiJSUzUxMiJ9.eyJhdWQiOiJBZG1pbnMiLCJpc3MiOiJDQSIsInN1YiI6InVzZXJzIiwiZW1haWwiOiJ1c2Vyc0B0ZXN0LmNvbSIsIkNvdW50cnkiOiJBbnRhcnRpY2EifQ.5Xu7v2MosIQmtAOlqfM2PE9eJeT0iZzL9x6RIvqx_PAHKer0ylo-0wT9eON_qX1H_QZekTWMf8ok4fxdZNv2KP_AkNqSKLXYJ65TjPnfcX8-dooDJM9txfRWOFqJWx4yj4CTMPNR6rNhizkC9jUaLisPIjogc_a_61qTSnvHXFnuaYmkovN2Y3WfuXjhUZCH98hodRL_ATg1_SpO0bPb7_N1Z76yrcv0RYQan0Y5kICWYdhHlk8Dw6I2fLMVsl3HiYiRq4XBJE8AY_g742Uq5kTS62PKohg3IjfRa-g2rjgKo1XW2sRLVc7vnns2L3TqESo5vgvorTjKnCTQKuHpIg

Encrypted JWT

eyJhbGciOiJSU0EtT0FFUC0yNTYiLCJlbmMiOiJBMjU2R0NNIn0.lZ2nqCeiPzsPmJShsrDD3uA55-06A649CMtwOyuY9nNzMtUGyzV-G8qc4w4ui1uWrtzypBs5Eyq4GfjnTtVHbcDVkS1HVc3tfxNAPY8dfjVrWNz59HyKt4bCjBdqqhBOdZezLtWB9aoWIwZoHLf4D8aUcVUtDsFELVcScmiQNtzHwvpDHZb4oxRfPl-OuOTkKA23C8lnnDMO1KUy8ZXHD4p0jQKAcaV877gYm8NbHDwOBEf-ItWJOGx2jV60apWd0hKqwfFR2QKD9wmGgXpbFZ08ro7X2fj8rTgKWhDgoBT_JVZdVFhVI4T4RLRDrCJqkyeciXhLm7W_xNhWBXAMrA.94SuB596ZLuUtw53wrofwN5jZXfT5f-ZarJhQc9Mj0M.0Ow5DXfilYX3ty49H4lNMNPljlWAFASc49zljhRSIIUSlmUHLZo0SAezn-n_FdxexAIYLk_FtRgnkMHDEyxJ1V1yHhqa1Jvdb36lTYyptqCJhMkOV1XGn58L4Z9QQmdrIZnn5iHxZ9-N1Jfjs0eoKiLBgR9O7ZEcs7QrWZVT6n_HrGrIloYQu_lFgmk5O7k47_15CVXaFqIohpHXETejoHEwjQj-iTToNRaHWNFAKvlpUBz4mUgk9RSIQCxK1GxxS8wxP44w5G4HdOIjFNwTsRDXeSZy0mU9zTNUCmDEUT9MFESfmVU1nPurdT-VoiPvVklbJZW8Sas0hWgqQkdQdP35nFY1sjCgfMB9iYUeEU-TCE219wkm1XXrLJwLEYZclL_4ckl4zExo2wb3Czwd8f5iO9fBQQWZ4mdwThK4VtZaPs1JEkxwGLI0SHA8Jr-e2PsDrkGEnxs74FsJ5MKluU2ZKvKcGXyQPaaTRa0ecJLD5-YYBuTtxOnU3gM_5aZm97pd_wiPk_h81r5aiwjSfRF3Ihxp37KNPfNOMJoA9xe2F51m1AvmjrOUgSM156LwmFyJFebVfarb9NPtJ_q1wU891sCu2Vmv520BR4QfIc-ayIwTVxLgZSN-BP7PhEJb_x8.XhZpINBxRdFFEgwPTcAgJg

Same code runs seperately for signing and encryption, but didn't run, if I include both.

Please help me to understand what I'm doing wrong.

Thanks In Advance


Solution

  • A JWT has as its payload, or Message, the UTF-8 representation of the Claims Set. From RFC 7519:

    Let the Message be the octets of the UTF-8 representation of the JWT Claims Set.

    This is the case for both signed JWTs (which are JWS objects), and encrypted JWTs (using JWE):

    if the JWT is a JWE, create a JWE using the Message as the plaintext for the JWE; all steps specified in JWE for creating a JWE MUST be followed.

    Accordingly, for verification of an encrypted JWT, the payload is interpreted as a Claims Set:

    Else, if the JWT is a JWE, follow the steps specified in JWE for validating a JWE. Let the Message be the resulting plaintext.

    The mistake you have made in your program is using the serialization of the signed JWT as the payload of a JWE, but then attempting to process the resulting object as n encrypted JWE. Accordingly, the library attempts to interpret a serialized signed JWT (the JWS Flattened Serialization) as a serialized JWT Claims Set (a JSON object). This explains the exception you are getting:

    Caused by: org.jose4j.lang.JoseException: Parsing error:
        org.jose4j.json.internal.json_simple.parser.ParseException:
        Unexpected character (e) at position 0.
    

    It appears that you are attempting to produce a JWT that is both encrypted and authenticated. All JWE algorithms are authenticated encryption algorithms, so there is no need to do anything with JWS to achieve this - an encrypted JWT is sufficient.