0

I am working on an android application for on online taxi service , in which it supports in app calling using sinch SDK. To authorize a client, we need to share our APP_KEY and SECRET_KEY and userId with the sinch server and that's cryptographically signed with the Application Secret. From their tutorial they have made a class to share these data as base 64 . But once I tried this I got a runtime exception as "bad base-64" like:

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.tukxi.ride, PID: 17870
    java.lang.RuntimeException: bad base-64
        at com.general.files.JWT.create(JWT.java:50)
        at com.general.files.SinchService$MySinchClientListener.onCredentialsRequired(SinchService.java:252)
        at com.sinch.android.rtc.internal.client.DefaultSinchClient$2.onCredentialsRequired(Unknown Source:22)

here is my code :

     public static  String create(String appKey, String appSecret, String userId) {
    JSONObject header = new JSONObject();
    JSONObject payload = new JSONObject();
    final long issuedAt = System.currentTimeMillis() / 1000;
    String kid = "hkdfv1-" + formatDate(issuedAt);
    try {
      header.put("alg", "HS256");
      header.put("typ", "JWT");
      header.put("kid", kid);
      payload.put("iss","//rtc.sinch.com/applications/" + appKey);
      payload.put("sub","//rtc.sinch.com/applications/" + appKey + "/users/" + userId);
      payload.put("iat",issuedAt);
      payload.put("exp",issuedAt + 600);
      payload.put("nonce", UUID.randomUUID());
    } catch (JSONException e) {
      throw new RuntimeException(e.getMessage(), e.getCause());
    }

    String headerStr = header.toString().trim().replace("\\/","/");
    String payloadStr = payload.toString().trim().replace("\\/","/");
    String headerBase64 = Base64.encodeToString(headerStr.getBytes(), Base64.NO_PADDING | Base64.NO_WRAP | Base64.DEFAULT);
    String payloadBase64 = Base64.encodeToString(payloadStr.getBytes(), Base64.NO_PADDING | Base64.NO_WRAP | Base64.DEFAULT);

    String jwtToSign = headerBase64 + "." + payloadBase64;

    String jwtSignature;
    try {
      byte[] origKey = Base64.decode(appSecret, Base64.DEFAULT);
      byte[] signingKey = deriveSigningKey(origKey, issuedAt);
      final byte[] macData = Hmac.hmacSha256(signingKey, jwtToSign);
      String signature = Base64.encodeToString(macData, Base64.NO_PADDING | Base64.NO_WRAP | Base64.DEFAULT);
      jwtSignature = jwtToSign + "." + signature;
    } catch (Exception e) {
      throw new RuntimeException(e.getMessage(), e.getCause());
    }
    return jwtSignature;
  }

  private static String formatDate(long time) {
    String format = "yyyyMMdd";
    SimpleDateFormat sdf = new SimpleDateFormat(format, Locale.getDefault());
    sdf.setTimeZone(TimeZone.getDefault());
    return sdf.format(new Date(time * 1000));
  }

  private static byte[] deriveSigningKey(byte[] key, long issuedAt) {
    return Hmac.hmacSha256(key, formatDate(issuedAt));
  }
Liya
  • 568
  • 7
  • 28
  • 1
    In this wood of variables, there is more info available, like line number. Stylistic I would use `headerStr.getBytes("UTF-8")` in case one developer tries this code on Windows, say for the other end. – Joop Eggen Oct 06 '21 at 09:14
  • @JoopEggen . thanks for your concern . can you figure out what is the issue with the base64 i've returned ? – Liya Oct 06 '21 at 10:59
  • Can you indicate line 50 from JWT.java? (`at com.general.files.JWT.create(JWT.java:50)`) – Joop Eggen Oct 06 '21 at 11:43
  • 1
    If `appSecret` fails as Base64, check it. It could have line breaks or whatever. Add it to the exception message - temporarily. – Joop Eggen Oct 06 '21 at 11:47
  • line #50 is the catch clause . #50 : } catch (Exception e) { throw new RuntimeException(e.getMessage(), e.getCause()); } – Liya Oct 06 '21 at 13:55
  • 1
    Ah, yes, and further in the stacktrace a "caused by" continues with the original exception. My guess is `byte[] origKey = Base64.decode(appSecret, Base64.DEFAULT);`; **appSecret**. Winston Churchill: _Als je door een hel gaat, blijf gaan._ – Joop Eggen Oct 06 '21 at 14:02
  • If you download the Java SDK (https://developers.sinch.com/docs/in-app-calling/sdk-downloads/) there are samples for general use-cases and in each one is a JWT.java which creates a JWT token for the sample application. Please use this as a reference. – Roland Oct 07 '21 at 07:02
  • @Roland I used the same JWT class from their sample project :| – Liya Oct 07 '21 at 07:39
  • 1
    https://developers.sinch.com/docs/in-app-calling/android/application-authentication/. Here there is a link to here: More detailed examples on how to implement this in various languages, including reference data for unit tests, is available at https://github.com/sinch/sinch-rtc-api-auth-examples. I have run the Android sample applications which uses JWT.java without issue. Can you test with the sample application before integrating into your project. – Roland Oct 07 '21 at 08:04
  • @Roland can you address this issue ? we are getting new this error message while trying to register , "Configuration refresh interval is not valid (500)" . – Liya Oct 14 '21 at 10:01
  • @Liya Can you open a support ticket and provide me the relevant details for your account. – Roland Oct 21 '21 at 08:04
  • @Roland . thanks Ronald . the issue got fixed – Liya Oct 22 '21 at 12:50

0 Answers0