Search code examples
androidfirebasetokenfirebase-authenticationjjwt

JJWT libary to generate token for authentication with Firebase on Android


I am trying to implement Linkedin Signin and then authenticate with Firebase. The only way to do so, since Linkedin is not in the current Firebase simple login providers is to:

  1. Login with Linkedin, grant the token as shown here.
  2. Get the Id of the Linkedin user.
  3. Make a token just like Firebase indicates.
  4. In order to signInWithCustomToken just like it indicates here, following then the procedure over here:

    Create custom tokens using a third-party JWT library

Now, I have done all these. Here is the generating token code with JJWT library:

long nowSeconds = System.currentTimeMillis()/1000;
        Date current_date = new Date(nowSeconds);
        KeyPair myKey = RsaProvider.generateKeyPair();
        long expMillis = nowSeconds + 3000;
        Date exp_time = new Date(expMillis);
        String compactJws = Jwts.builder()
                .setSubject(ACCOUNT_EMAIL)
                .setIssuer(ACCOUNT_EMAIL)
                .setAudience("https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit")
                .setIssuedAt(current_date)
                .setExpiration(exp_time)
                .setId(linkedinId)
                .signWith(SignatureAlgorithm.RS256, myKey.getPrivate())
                .compact();

but I have incorrect Token format because:

iat Issued-at time The current time, in seconds since the UNIX epoch

exp Expiration time The time, in seconds since the UNIX epoch, at which the token expires. It can be a maximum of 3600 seconds later than the iat. Note: this only controls the time when the custom token itself expires. But once you sign a user in using signInWithCustomToken(), they will remain signed in into the device until their session is invalidated or the user signs out.

Because Firebase wants seconds and not Date. I can't pass a long value on setIssuedAt or setExpiration, as a Date Object is needed as a parameter.

So, how can I put a long value (the seconds) there? UPDATE: I have found a way to pass the timestamp like this:

long nowSeconds = System.currentTimeMillis()/1000;
        Date current_date = new Date(nowSeconds);
        KeyPair myKey = RsaProvider.generateKeyPair();
        long expSeconds = nowSeconds + 3000;
        Date exp_time = new Date(expSeconds);
        String compactJws = Jwts.builder()
                .setSubject(ACCOUNT_EMAIL)
                .setIssuer(ACCOUNT_EMAIL)
                .setAudience("https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit")
                .claim("iat",current_date.getTime())
                .claim("exp",exp_time.getTime())
                .claim("uid",uid)
                .signWith(SignatureAlgorithm.RS256,myKey.getPrivate())
                .compact();

But still my Token format is incorrect:

 E/AndroidRuntime: FATAL EXCEPTION: main
                                                                          Process: com.example.qrcodereader, PID: 24239


com.google.android.gms.tasks.RuntimeExecutionException: com.google.firebase.auth.FirebaseAuthInvalidCredentialsException: The custom token format is incorrect. Please check the documentation.
                                                                          at com.google.android.gms.tasks.zzh.getResult(Unknown Source)
                                                                          at com.example.qrcodereader.LoginActivity$6.onComplete(LoginActivity.java:268)
                                                                          at com.google.android.gms.tasks.zzc$1.run(Unknown Source)
                                                                          at android.os.Handler.handleCallback(Handler.java:739)
                                                                          at android.os.Handler.dispatchMessage(Handler.java:95)
                                                                          at android.os.Looper.loop(Looper.java:148)
                                                                          at android.app.ActivityThread.main(ActivityThread.java:7325)
                                                                          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)
                                                                       Caused by: com.google.firebase.auth.FirebaseAuthInvalidCredentialsException: The custom token format is incorrect. Please check the documentation.
                                                                          at com.google.android.gms.internal.zzbix.zzcb(Unknown Source)
                                                                          at com.google.android.gms.internal.zzbiu$zzj.zza(Unknown Source)
                                                                          at com.google.android.gms.internal.zzbjf.zzcc(Unknown Source)
                                                                          at com.google.android.gms.internal.zzbjf$zza.onFailure(Unknown Source)
                                                                          at com.google.android.gms.internal.zzbja$zza.onTransact(Unknown Source)
                                                                          at android.os.Binder.execTransact(Binder.java:453)

Does anyone know what's the mistake here? I really can't figure it out.


Solution

  • A Date con not be built with seconds. It needs a milliseconds value. This code is incorrect.

    Date current_date = new Date(nowSeconds);
    

    Use the following code

    KeyPair myKey = RsaProvider.generateKeyPair();
    Date current_date = new Date();
    Calendar calendar = Calendar.getInstance(); 
    calendar.add(Calendar.SECOND, 3000);
    Date exp_time = calendar.getTime();
    String compactJws = Jwts.builder()
            .setSubject(ACCOUNT_EMAIL)
            .setIssuer(ACCOUNT_EMAIL)
            .setAudience("https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit")
            .setIssuedAt(current_date)
            .setExpiration(exp_time)
            .setId(linkedinId)
            .signWith(SignatureAlgorithm.RS256, myKey.getPrivate())
            .compact();
    

    If you want to use the second way .claim() the divide the values by 1000 to get seconds

    .claim("exp",exp_time.getTime()/1000)