Search code examples
javafirebasegoogle-app-enginefirebase-authenticationgoogle-cloud-endpoints

How to verify firebase token in google endpoints?


I have followed the docs for the firebase authentication and also a tutorial on this. Assuming the token will be coming in the client from the header, I have created a custom authenticator class and I get an error for Task stating The type TaskQueuePb.TaskQueueQueryAndOwnTasksResponse.Task is not generic; it cannot be parameterized with arguments <FirebaseToken> However, I don't see any other imports and the tutorial does not seem to be explaining more about it.

Please refer the code below:

package com.travelplannr.endpoint.firebase;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.servlet.http.HttpServletRequest;

import com.google.api.server.spi.ServiceException;
import com.google.api.server.spi.auth.common.User;
import com.google.api.server.spi.config.Authenticator;
import com.google.appengine.api.taskqueue.TaskQueuePb.TaskQueueQueryAndOwnTasksResponse.Task;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.firebase.FirebaseApp;
import com.google.firebase.FirebaseOptions;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseToken;

public class CustomAuthenticator implements Authenticator {

     private static final Logger logger = Logger.getLogger(CustomAuthenticator.class.getName());

        static {
            try {
                FileInputStream serviceAccount = new FileInputStream("path/to/serviceAccountKey.json");

                FirebaseOptions options = new FirebaseOptions.Builder()
                    .setCredentials(GoogleCredentials.fromStream(serviceAccount))
                    .setDatabaseUrl("https://<DATABASE_NAME>.firebaseio.com/")
                    .build();

                FirebaseApp.initializeApp(options);

            } catch (Exception e) {
                logger.log(Level.SEVERE, e.toString(), e);
            }
        }

        @Override
        public User authenticate(HttpServletRequest httpServletRequest) {

            //get token
            final String authorizationHeader = httpServletRequest.getHeader("Authorization");

            //verify
            if(authorizationHeader != null) {
                Task<FirebaseToken> task = FirebaseAuth.getInstance().verifyIdToken(authorizationHeader.replace("Bearer ", ""));

                //wait for the task
                try {
                    Tasks.await(task);
                } catch (ExecutionException e) {
                } catch (InterruptedException e) {
                }

                FirebaseToken firebaseToken = task.getResult();
                User user = new User(firebaseToken.getUid(), firebaseToken.getEmail());
                return user;
            }
        return null;
    }
}

Please help! Thanks in advance.


Solution

  • I think that there are two distinct problems here, in the same line of code. First, there seems to be a mismatch of the left-hand receiving type from the return type in your assignment. From what I can see from the FirebaseAuth Java API reference, the method signature is:

    FirebaseToken verifyIdToken(String token)
    

    So, verifyIdToken returns a FirebaseToken, but you're trying to assign it to a Task<FirebaseToken>, which is a different, incompatible type. Secondly, Task<FirebaseToken> is also an illegal type to try to use, because this Task class isn't generic, so it can't be parameterized at all. This is the error that you're seeing from the compiler, but that detail becomes irrelevant if you drop the use of Task altogether, because it's unnecessary:

    FirebaseToken firebaseToken = FirebaseAuth.getInstance().verifyIdToken(authorizationHeader.replace("Bearer ", ""));
    

    Just remove all of your other code around trying to use Task and Tasks.await().

    It seems like you might have been mixing and matching synchronous and asynchronous sources of information about how to make this call. Since the code you've written was going to immediately wait for the async task to be done anyway, you should probably just stick with the synchronous version of the API (verifyIdToken()) instead of trying to use the asynchronous variant (verifyIdTokenAsync()), which might have caused some confusion when trying to follow examples.