简体   繁体   中英

How can I decode JWT token in android?

I have a jwt token like this

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

How can I decode this so that I can get the payload like this

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
}

I have used this library, but can't find a way to do what I want

you should split string: If you pass the first two sections through a base 64 decoder, you'll get the following (formatting added for clarity):

header

{
  "alg": "HS256",
  "typ": "JWT"
}

body

    {
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
}

Code example:

public class JWTUtils {

    public static void decoded(String JWTEncoded) throws Exception {
        try {
            String[] split = JWTEncoded.split("\\.");
            Log.d("JWT_DECODED", "Header: " + getJson(split[0]));
            Log.d("JWT_DECODED", "Body: " + getJson(split[1]));
        } catch (UnsupportedEncodingException e) {
            //Error
        }
    }

    private static String getJson(String strEncoded) throws UnsupportedEncodingException{
        byte[] decodedBytes = Base64.decode(strEncoded, Base64.URL_SAFE);
        return new String(decodedBytes, "UTF-8");
    }
}

Call method for example

JWTUtils.decoded("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ");

library reference: https://github.com/jwtk/jjwt

jwt test: https://jwt.io/

I used a third-party library named JWTDecode.Android https://github.com/auth0/JWTDecode.Android . The documentation is reasonably good. From your question, The sub, name, etc are a part of the body and are called Claims. You could get them like this using the above library:

JWT parsedJWT = new JWT(jwtToken);
Claim subscriptionMetaData = parsedJWT.getClaim("name");
String parsedValue = subscriptionMetaData.asString();

This works using Java 8's Base64 class:

public String getDecodedJwt(String jwt)
{
  String result = "";

  String[] parts = jwt.split("[.]");
  try
  {
    int index = 0;
    for(String part: parts)
    {
      if (index >= 2)
        break;

      index++;
      byte[] partAsBytes = part.getBytes("UTF-8");
      String decodedPart = new String(java.util.Base64.getUrlDecoder().decode(partAsBytes), "UTF-8");

      result += decodedPart;
    }
  }
  catch(Exception e)
  {
    throw new RuntimeException("Couldnt decode jwt", e);
  }

  return result;
}

If the project is already using AWSCognito SDK then CognitoJWTParser class can be used. It has static methods getHeader() , getPayload() , getSignature() .

https://github.com/aws-amplify/aws-sdk-android/blob/master/aws-android-sdk-cognitoidentityprovider/src/main/java/com/amazonaws/mobileconnectors/cognitoidentityprovider/util/CognitoJWTParser.java

I've used it in a Java web application and the code will look something like the below:-

Jwts.parser().setSigningKey('secret-key').parseClaimsJws(token).getBody()

It will return claims which contain the required values.

Based partially on the code provided by Brad Parks , adapted for use with lower versions of Android by using Apache Commons and converted to Kotlin:

In build.gradle :

implementation 'apache-codec:commons-codec:1.2'

In a Kotlin class:

fun decodeToken(token: String): String{
    val tokenParts: Array<String> = token.split(".").toTypedArray()
    if(tokenParts.isEmpty()) return token
    var decodedString = ""
    for(part: String in tokenParts){
        val partByteArray: ByteArray =
            stringToFullBase64EncodedLength(part).toByteArray(Charsets.US_ASCII)
        val decodedPart = String(Base64.decodeBase64(partByteArray))
        decodedString+=decodedPart
        // There are a maximum of two parts in an OAuth token,
        // and arrays are 0-indexed, so if the index is 1
        // we have processed the second part and should break.
        if(tokenParts.indexOf(part) == 1) break
    }
    return decodedString
}

private fun stringToFullBase64EncodedLength(string: String): String{

    // A properly base64 encoded string must be divisible by 4
    // We'll pad it to the nearest multiple of 4 without losing data:
    val targetLength: Int = ( 4 * ceil( string.length.toDouble()/4 ) ).toInt()

    // Now, we get the difference, and add it with a reserved character (`=`)
    // to the end of the string. It will get removed later.
    val requiredPadding: Int =  targetLength-string.length
    return string+"=".repeat(requiredPadding)

}

A no dependency version in Kotlin with Android SDK 26+ (Oreo):

fun extractJwt(jwt: String): String {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return "Requires SDK 26"
    val parts = jwt.split(".")
    return try {
        val charset = charset("UTF-8")
        val header = String(Base64.getUrlDecoder().decode(parts[0].toByteArray(charset)), charset)
        val payload = String(Base64.getUrlDecoder().decode(parts[1].toByteArray(charset)), charset)
        "$header\n$payload"
    } catch (e: Exception) {
        "Error parsing JWT: $e"
    }
}

If you are using the library io.jsonwebtoken.Jwts , then use the following snippet. It works for me.

try {
        val claims: Claims =
            Jwts.parser().setSigningKey(secretKey.toByteArray()).parseClaimsJws(token).body
        return ConnectionClaim(claims["uid"].toString(), claims["key"].toString())

 } catch (e: JwtException) {
        e.printStackTrace()
 }

this code convert JWT to String and work on any API

 public static String getDecodedJwt(String jwt)
   {
      StringBuilder result = new StringBuilder();

      String[] parts = jwt.split("[.]");
      try
      {
         int index = 0;
         for(String part: parts)
         {
            if (index >= 2)
               break;
            index++;
             byte[] decodedBytes = Base64.decode(part.getBytes("UTF-8"), Base64.URL_SAFE);
            result.append(new String(decodedBytes, "UTF-8"));
         }
      }
      catch(Exception e)
      {
         throw new RuntimeException("Couldnt decode jwt", e);
      }

      return result.toString();
   }

Example :

JWTUtils.getDecodedJwt("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c")

And finally the resulting conversion

{"alg":"HS256","typ":"JWT"}{"sub":"1234567890","name":"John Doe","iat":1516239022}

Almost all forgot to add imports and select android.util.Base64 !

import android.util.Base64
import org.json.JSONException

// Json data class
data class Data(
    val name: String?,
    val nonce: String?,
    // Other access_token fields
)

fun parseAccessToken(token: String): Data? {
    return try {
        val part = token.split(".")[1]
        val s = decodeJwt(part)
        // obj is an object of Gson or Moshi library
        obj.fromJson(s)
    } catch (e: Exception) {
        null
    }
}

@Throws(JSONException::class)
private fun decodeJwt(text: String): String {
    val s = Base64.decode(text, Base64.URL_SAFE)
    return String(s)
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM