Java 8 Base64 JWT token into JSON
Asked Answered
F

2

4

So, I have done some research on this on the Net and here on StackOverflow, and I have tried many, multiple suggestions that I have found. The problem is that I am logging into one of our Oauth2 services which is working well. I get an Oath2 JWT token. I know this is Base64 encoded, and I can drop the token into jwt.io and www.base64decode.org and both of these sites parse the token correctly.

I am using Java 8 Base64 tools, and the code looks as follows:

public String getTokenProperty(String token, String propertyName)
{
    byte[] bytes = Base64.getUrlDecoder().decode(token);
    String decodedString = new String(bytes, StandardCharsets.UTF_8);
    System.out.println("Decoded: " + decodedString);
    return (new JSONObject(decodedString)).getString(propertyName);
}

The error occurs on the decoder line as follows:

java.lang.IllegalArgumentException: Illegal base64 character 2e

I tried this with a token from my Oauth2 Service, I got a token from Syncope, and I got a token from Auth0 ... all return with JWT Base64 encoded tokens. With ALL these tokens from these different servers, I get the same error.

I would like to use the Java 8 Base64 which is standard, but I am thinking that I may need to use an external third-party Base64 decoder.

Any help would be great. Thanks!

The token is as follows:

eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ik1qSTRRVFEwT1VRNU9VSXlSVEV6TlRBd05UVXpSVVExTlVOR05FVkVORGRDTlRnM016VXdRZyJ9.eyJodHRwczovL2JpdG9vbXRyYWRlci5uZXQvYXV0aG9yaXphdGlvbiI6eyJncm91cHMiOlsiQ29uc3VtZXJzIl0sInJvbGVzIjpbIlVzZXIiXX0sImlzcyI6Imh0dHBzOi8vYml0em9vbS5hdXRoMC5jb20vIiwic3ViIjoiYXV0aDB8NWNhNTE5NzZjYzMzZjUxMTBhYWNkYmM0IiwiYXVkIjpbImh0dHBzOi8vYml0em9vbS5hdXRoMC5jb20vYXBpL3YyLyIsImh0dHBzOi8vYml0em9vbS5hdXRoMC5jb20vdXNlcmluZm8iXSwiaWF0IjoxNTU5MzIzNDI1LCJleHAiOjE1NTk0MDk4MjUsImF6cCI6IlliRGFSelRVQkFtZEFrSExqdjZ0bEI3U05xSTF1RlNtIiwic2NvcGUiOiJvcGVuaWQgcHJvZmlsZSBlbWFpbCBhZGRyZXNzIHBob25lIHJlYWQ6Y3VycmVudF91c2VyIHVwZGF0ZTpjdXJyZW50X3VzZXJfbWV0YWRhdGEgZGVsZXRlOmN1cnJlbnRfdXNlcl9tZXRhZGF0YSBjcmVhdGU6Y3VycmVudF91c2VyX21ldGFkYXRhIGNyZWF0ZTpjdXJyZW50X3VzZXJfZGV2aWNlX2NyZWRlbnRpYWxzIGRlbGV0ZTpjdXJyZW50X3VzZXJfZGV2aWNlX2NyZWRlbnRpYWxzIHVwZGF0ZTpjdXJyZW50X3VzZXJfaWRlbnRpdGllcyIsImd0eSI6InBhc3N3b3JkIn0.St7097L1ZAlBWcAPrie-8CGV2F3Fr8uNYpSDVKSPVPF4zBZrmm62_UAj7Ssux8AjUy0LhjiF3kLpNph2L7yrpUREw6TyGJwQasfdVtM5VzRYUcy-fOGyRSqPQorbzxJQZzs2pyDJm-2hMQ0McJ37ubKIWrHFD5McMedN6THK7g5TExX47XCRPcOuCEWm3bf3zdWF2LEGhCw_c-lcZDwlb4ePkO721XjSWtrXEBvxc8scFNaHDt7VOnrSze4XK_LO8eE8bHRq6qUrWf1csYucK--aHazBsvfdl-6QDRk-tOBM-LdXJMT7H8Ih6trxVmZofQjr2dQ4j_3DTVoU3eLdog

UPDATE:

I switched from java,util.Base64 to org.apache.commons.codec.binary.Base64 and this seems to work somewhat, I don't get an error now.

String decodedString = new String(bytes, StandardCharsets.UTF_8);

gives me back a string of the header, payload, and signature data. So, when I do:

JSONObject jsonObject = new JSONObject(decodedString);
    System.out.println("getTokenProperty: jsonObject = " + jsonObject.toString());

I am only getting back the header data, and what I really need is the payload.

For the record ... the code I inherited from a "proof of concept" project was:

public static String getTokenProperty(String token, String propertyName)
{
    return (new JSONObject(new String(Base64.getDecoder().decode(token)))).getString(propertyName);
}

and there was no unit testing at all. So, when I went to unit test it, of course it completely broke. So, now I have a better understanding of how to parse this token, and I will remember this lesson for a long time.

Thanks very much!

Furlong answered 31/5, 2019 at 17:48 Comment(5)
Ok, I added the token, which is generated from Auth0. I also switched from java.util.Base64 to org.apache.commons.codec.binary.Base64 which actually DOES work and I get JSON data for the header, payload, and signature, but I also get a lot of junk after it ... not sure what that is. When I get to the third line which gets me the JSONObject, I am only getting the header, and I really want the payload data.Furlong
@Brandon Where's that token from?Slovenia
@shmosel; I fixed the token.. ideone.com/IUfTYHJehial
The token I posted was from a test account with Auth0. That is a real token from them, and I get the same error parsing that. Yeah, I went to that page with the sample you provided and yeah, I agree that code works ... but the token is also hard-coded in that sample. That code, that standard java code with a token from Auth0 actually does NOT work!Furlong
I don't get an exception when I use Base64.getMimeDecoder() instead of Base64.getUrlDecoder(). I do get trailing binary data as well, though.Cavort
J
21

The reason it doesn't parse is because you are trying to Base64URLDecode the ENTIRE token.. But you have to decode PARTS of the token which is separated by a DOT "." character (0x2e in hex, 46 in dec, &#46 in html -- ASCII/UTF8) ..

Example:

public static void decodeTokenParts(String token)
{
    String[] parts = token.split("\\.", 0);

    for (String part : parts) {
        byte[] bytes = Base64.getUrlDecoder().decode(part);
        String decodedString = new String(bytes, StandardCharsets.UTF_8);

        System.out.println("Decoded: " + decodedString);
    }
}

This is because a JWT token is made up of parts:

Base64URLEncode({HeaderJSON}) + "." + Base64URLEncode({PayloadJSON}) + "." + Signature for example..

So to decode it.. you need to split it by "." and decode each part. Note: The signature will usually be binary that is encoded as base64 so once you decode it, don't try printing it.. it'll print bytes. You'd need to verify the signature.

For example, if you go to: https://jwt.io/#debugger-io?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

You will see how each "part" is encoded. It is colour coded.

Jehial answered 31/5, 2019 at 18:31 Comment(4)
Yes, I am very familiar with JWT.io and have used them before. I just hadn't parsed a JWT token in Java recently. The last time I used Base64 was encoding images. But this does solve my issue.Furlong
@tjholmes66; Nice :) I wasn't sure so I included the jwt.io link anyway so that others in the future will also understand easier.Jehial
Awesome! was a simple stupid problem on my part. But the important thing is that I learned, and I hope this will help others!!!Furlong
No such property: StandardCharsets for class: Script1??Chophouse
J
2

I used this library https://mvnrepository.com/artifact/com.auth0/java-jwt/3.12.0 for decoding to get the subject(userId) thus: JWT.decode(token).getSubject()

Jubbulpore answered 19/1, 2021 at 15:13 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.