java-jwt: java.lang.NoSuchMethodError for Base64.decodeBase64(String)
Hi, while using your library I encountered the following runtime exception, which crashes my app:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.xxxx.yyyy, PID: 17510
java.lang.NoSuchMethodError: No static method decodeBase64(Ljava/lang/String;)[B in class Lorg/apache/commons/codec/binary/Base64; or its super classes (declaration of 'org.apache.commons.codec.binary.Base64' appears in /system/framework/org.apache.http.legacy.boot.jar)
at com.xxxx.yyyy.network.RealNetworkController$2.onResponse(RealNetworkController.java:172)
at retrofit2.ExecutorCallAdapterFactory$ExecutorCallbackCall$1$1.run(ExecutorCallAdapterFactory.java:68)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:158)
at android.app.ActivityThread.main(ActivityThread.java:7224)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
This is caused by your use of the Apache Commons Codec library, in JWTDecoder.java:38:
headerJson = StringUtils.newStringUtf8(Base64.decodeBase64(parts[0]));
payloadJson = StringUtils.newStringUtf8(Base64.decodeBase64(parts[1]));
I have investigated the issue, and I believe it’s down to an obscure problem with Android.
The Problem
Until recently, Android was bundled with Apache’s HttpClient, which depended on Commons Codec.
However, the version originally bundled with Android (1.3) does not contain the static decodeBase64(String)
method. Furthermore, this ancient version overrides the version you specify in your lib’s build.gradle
.
For a better explanation, see this blog post, and these stack overflow posts:
- http://stackoverflow.com/a/34473643
- http://stackoverflow.com/a/5902269
- http://stackoverflow.com/questions/24306695/base64-dependencies-issue-in-android-studio
The reason you (the developers of java-jwt) may not have been experiencing this error and I have, is because this ancient dependency has been removed from android entirely, after SDK 23 (version 6.0), removing the problem.
Unfortunately for me, my app’s minimum version is 4.4 (SDK 19), so I suspect that the legacy code is still in my classpath (this is corroborated by the exception message I pasted above:
declaration of 'org.apache.commons.codec.binary.Base64' appears in /system/framework/org.apache.http.legacy.boot.jar
This effectively gives your library an undocumented requirement for Android SDK 23 and above!
The Solution
Some people have been using a workaround, but I would recommend that you simply replace your Commons Codec call with the android-internal Base64 implementation. I will be submitting a pull request to this effect, if/when I have time.
TL;DR
You have an obscure bug to do with historical dependencies in Android on Apache Commons Codec.
I’ll submit a PR when I can.
About this issue
- Original URL
- State: closed
- Created 7 years ago
- Reactions: 3
- Comments: 23 (9 by maintainers)
Commits related to this issue
- Create a wrapper to access Base64 encode/decode to fix bug #131 on Android platform — committed to laurentyhuel/java-jwt by deleted user 7 years ago
- On device machine learning word to vector training assets/ vector_data1.txt vector_data2.txt vector_data3.txt vector_data4.txt raw/ stopwords.txt extended_stopwords.txt layout/ activity_... — committed to vijay033/Deeplearning4j by vijay033 5 years ago
@DuncanTyrell what do you need to do with the JWT? if it’s only decode we already have a lib https://github.com/auth0/JWTDecode.Android to do that. It’s unusual for an Android app to verify or even sign a token
Yep that seems to do everything I need for now anyway @hzalaz - thanks again for your help and super-responsive turnaround.