使用超薄PHP和Android在Firebase中自定义令牌认证[错误无效令牌。 请查看文档]

A little background:

I have a project in Android that will do basic authentication. I did the backend in SLIM PHP framework and it works. But I want to integrate Firebase in the project so I can store some images for the user, and basic chat feature.

So, I use the mAuth.signInWithCustomToken() From what I understand a string token will be pass inside the function. I use firebase/php-jwt for the php part and added some lines on the backend. On the projectname/public/index.php I added this function:

function create_custom_token($uid) {
$service_account_email = "service account email here";
$private_key = "privatekey here";

$now_seconds = time();
$payload = array(
  "iss" => $service_account_email,
  "sub" => $service_account_email,
  "aud" => "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit",
  "iat" => $now_seconds,
  "exp" => $now_seconds+(60*60),  // Maximum expiration time is one hour
  "uid" => $uid
);
return JWT::encode($payload, $private_key, "HS256");
}

And to call that function I put the code below inside the login router:

if($result == USER_AUTHENTICATED){

        $user = $db->getUserByUsername($username);
        $response_data = array();

        $response_data['error']=false; 
        $response_data['message'] = 'Login Successful';
        $response_data['user']=$user; 

        $jwt = create_custom_token($username);

        $response_data['token']=$jwt;

        $response->write(json_encode($response_data));

        return $response
            ->withHeader('Content-type', 'application/json')
            ->withStatus(200);    

    }

So basically, I use the username as uid which makes since it is unique.

And on the android, In the LoginActivity.java

@Override
public void onValidationSucceeded() {
    String username = editTextUsername.getText().toString();
    String password = editTextPassword.getText().toString();

    ProgressDialog dialog = new ProgressDialog(this);
    dialog.setMessage("Logging in...");
    dialog.show();
    dialog.setCancelable(false);

    Call<LoginResponse> call = RetrofitClient
            .getInstance().getApi().userLogin(username, password);

    call.enqueue(new Callback<LoginResponse>() {
        @Override
        public void onResponse(Call<LoginResponse> call, Response<LoginResponse> response) {
            LoginResponse loginResponse = response.body();

            if (!loginResponse.isError()) {

                mAuth.signInWithCustomToken(loginResponse.getToken())
                        .addOnCompleteListener(LoginActivity.this, new OnCompleteListener<AuthResult>() {
                            @Override
                            public void onComplete(@NonNull Task<AuthResult> task) {
                                if (task.isSuccessful()) {
                                    SharedPrefManager.getInstance(LoginActivity.this)
                                            .saveUser(loginResponse.getUser());
                                    dialog.dismiss();
                                    Intent intent = new Intent(LoginActivity.this, MainActivity.class);
                                    startActivity(intent);
                                    finish();
                                } else {
                                    // If sign in fails, display a message to the user.
                                    dialog.dismiss();
                                    Toast.makeText(LoginActivity.this, loginResponse.getToken(),
                                            Toast.LENGTH_SHORT).show();
                                }
                            }
                        });

            } else {
                dialog.dismiss();
                Toast.makeText(LoginActivity.this, response.body().getMessage(), Toast.LENGTH_LONG).show();
            }
        }

        @Override
        public void onFailure(Call<LoginResponse> call, Throwable t) {
            Toast.makeText(LoginActivity.this, t.getMessage(), Toast.LENGTH_LONG).show();
            dialog.dismiss();
        }
    });
}

This is the LoginResponse Model

public class LoginResponse {

private boolean error;
private String message;
private User user;
private String token;

public LoginResponse(boolean error, String message, User user, String token) {
    this.error = error;
    this.message = message;
    this.user = user;
    this.token = token;
}

public boolean isError() {
    return error;
}

public String getMessage() {
    return message;
}

public User getUser() {
    return user;
}

public String getToken() {
    return token;
}
}

Using Postman to test the API, This is the result from POSTMAN So you can say, that it is working fine.

On Android however, When I try to login, by giving the same correct username and password,it throws an error `

The Custom token format is invalid. Please check the documentation. [SIGNATURE_INVALID]

Just in case you want to know, this the token from the result eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJmaXJlYmFzZS1hZG1pbnNkay1tY3l4MEBmbGl0dGVyLWMxNzU2LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic3ViIjoiZmlyZWJhc2UtYWRtaW5zZGstbWN5eDBAZmxpdHRlci1jMTc1Ni5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImF1ZCI6Imh0dHBzOlwvXC9pZGVudGl0eXRvb2xraXQuZ29vZ2xlYXBpcy5jb21cL2dvb2dsZS5pZGVudGl0eS5pZGVudGl0eXRvb2xraXQudjEuSWRlbnRpdHlUb29sa2l0IiwiaWF0IjoxNTM0MzQ4ODI5LCJleHAiOjE1MzQzNTI0MjksInVpZCI6Imp1c3Rpbi5sdWNhcyJ9.cQwNFWshi_0nMiZKpjXajJ4MnB9E7kGPlFB-kWZPmfo

Any idea guys? Maybe I have to do something on the client side?

To anyone who might see this one. The answer is: make sure to set your PC/Desktop/Laptop to the correct time/timezone. Got the answer the next day after posting the question.