John
John

Reputation: 3996

How to Get JSON String for header/payload from JWT token using java-jwt

Is there a method in java-jwt that will return the token as a single JSON string (or at least the header and payload as two JSON strings)? Does JJWT support this?

Looking at the tutorial at https://github.com/auth0/java-jwt I'm not seeing this method (there are individual getters for individual pieces of the message but I'm not seeing anything that returns the complete message as a JSON string).

The getHeader() and getHeader() methods return the encoded strings. I'm trying to get the headers and payload as JSON (similar to what is shown at https://jwt.io/). How do I do this?

Here's the code so far:

import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;

public class CreateTokenExampleIntegrationTest {

    private static final Logger logger = LoggerFactory.getLogger(CreateTokenExampleIntegrationTest.class);

    @Test
    public void shouldCreateToken() {
        logger.info("Starting test...");
        // create the token
        String key = "foobarkey";
        Algorithm alg = Algorithm.HMAC256(key);
        String issuer = "me";
        JWTCreator.Builder jwt = JWT.create();
        jwt.withIssuer(issuer);
        jwt.withClaim("createdBy", "CreateTokenExampleIntegrationTest");
        jwt.withClaim("purpose", "test");
        jwt.withClaim("msg", "Hello World.");
        String token = jwt.sign(alg);
        logger.info("Created token: \n" + token);
        // read the token
        JWTVerifier verifier = JWT.require(alg)
                .withIssuer(issuer)
                .build();
        DecodedJWT decoded = verifier.verify(token);
        logger.info("Header: \n" + decoded.getHeader());
        logger.info("Payload: \n" + decoded.getPayload());
        logger.info("Done.");
    }

}

And here's the output:

2020-05-19 08:23:31,387 08:23:31.387 [main] INFO  (CreateTokenExampleIntegrationTest.java:19) - Starting test...
2020-05-19 08:23:32,226 08:23:32.226 [main] INFO  (CreateTokenExampleIntegrationTest.java:30) - Created token: 
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJtc2ciOiJIZWxsbyBXb3JsZC4iLCJjcmVhdGVkQnkiOiJDcmVhdGVUb2tlbkV4YW1wbGVJbnRlZ3JhdGlvblRlc3QiLCJwdXJwb3NlIjoidGVzdCIsImlzcyI6Im1lIn0.VmYsToj1PKBzJKQuXEyiKuJA-GkNVit0Ylh44dVF2UI
2020-05-19 08:23:32,273 08:23:32.273 [main] INFO  (CreateTokenExampleIntegrationTest.java:36) - Header: 
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
2020-05-19 08:23:32,273 08:23:32.273 [main] INFO  (CreateTokenExampleIntegrationTest.java:37) - Payload: 
eyJtc2ciOiJIZWxsbyBXb3JsZC4iLCJjcmVhdGVkQnkiOiJDcmVhdGVUb2tlbkV4YW1wbGVJbnRlZ3JhdGlvblRlc3QiLCJwdXJwb3NlIjoidGVzdCIsImlzcyI6Im1lIn0
2020-05-19 08:23:32,273 08:23:32.273 [main] INFO  (CreateTokenExampleIntegrationTest.java:38) - Done.

EDIT: This is a complete solution based on the accepted answer:

Code:

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.StringUtils;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;

public class CreateTokenExampleIntegrationTest {

    private static final Logger logger = LoggerFactory.getLogger(CreateTokenExampleIntegrationTest.class);

    @Test
    public void shouldCreateToken() {
        logger.info("Starting test...");
        // create the token
        String key = "foobarkey";
        Algorithm alg = Algorithm.HMAC256(key);
        String issuer = "me";
        JWTCreator.Builder jwt = JWT.create();
        jwt.withIssuer(issuer);
        jwt.withClaim("createdBy", "CreateTokenExampleIntegrationTest");
        jwt.withClaim("purpose", "test");
        jwt.withClaim("msg", "Hello World.");
        String token = jwt.sign(alg);
        logger.info("Created token: \n" + token);
        // read the token
        JWTVerifier verifier = JWT.require(alg)
                .withIssuer(issuer)
                .build();
        DecodedJWT decoded = verifier.verify(token);
        // header
        String encHeader = decoded.getHeader();
        String header = decode(encHeader);
        logger.info("Header: \n" + encHeader + "\n" + header);
        // payload
        String encPayload = decoded.getPayload();
        String payload = decode(encPayload);
        logger.info("Payload: \n" + encPayload + "\n" + payload);
        // done
        logger.info("Done.");
    }

    public String decode(final String base64) {
        return StringUtils.newStringUtf8(Base64.decodeBase64(base64));
    }

}

Output:

2020-05-19 10:13:29,146 10:13:29.146 [main] INFO  (CreateTokenExampleIntegrationTest.java:21) - Starting test...
2020-05-19 10:13:30,031 10:13:30.031 [main] INFO  (CreateTokenExampleIntegrationTest.java:32) - Created token: 
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJtc2ciOiJIZWxsbyBXb3JsZC4iLCJjcmVhdGVkQnkiOiJDcmVhdGVUb2tlbkV4YW1wbGVJbnRlZ3JhdGlvblRlc3QiLCJwdXJwb3NlIjoidGVzdCIsImlzcyI6Im1lIn0.VmYsToj1PKBzJKQuXEyiKuJA-GkNVit0Ylh44dVF2UI
2020-05-19 10:13:30,102 10:13:30.102 [main] INFO  (CreateTokenExampleIntegrationTest.java:41) - Header: 
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
{"typ":"JWT","alg":"HS256"}
2020-05-19 10:13:30,103 10:13:30.103 [main] INFO  (CreateTokenExampleIntegrationTest.java:45) - Payload: 
eyJtc2ciOiJIZWxsbyBXb3JsZC4iLCJjcmVhdGVkQnkiOiJDcmVhdGVUb2tlbkV4YW1wbGVJbnRlZ3JhdGlvblRlc3QiLCJwdXJwb3NlIjoidGVzdCIsImlzcyI6Im1lIn0
{"msg":"Hello World.","createdBy":"CreateTokenExampleIntegrationTest","purpose":"test","iss":"me"}
2020-05-19 10:13:30,103 10:13:30.103 [main] INFO  (CreateTokenExampleIntegrationTest.java:47) - Done.

Upvotes: 1

Views: 10396

Answers (1)

sapisch
sapisch

Reputation: 555

I looked through java-jwt and I don't think that it outputs the payload and header JSON Strings other than base64-encoded. Also, the "normal" JSON strings are just temporary local Strings in the cunstructor of JWTDecoder (see here) and private inaccessible fields of JWTCreator (see here) which never get "exposed to the public".

So you either have to decode the base64 Strings yourself or access the private Fields of JWTCreator via Reflections. But I'd definitely choose decoding the String manually in this case. That could look like this (equal with how JWTDecoder does it):

public String decodeToJson(final String base64){
        return StringUtils.newStringUtf8(Base64.decodeBase64(base64));
}
DecodedJWT decoded = verifier.verify(token); // in your Test-Class

final String headerJson = decodeToJson(decoded.getHeader());
final String payloadJson = decodeToJson(decoded.getPayload());

Upvotes: 4

Related Questions