Java – How do I add Facebook login and email sign-up to my Google Cloud Endpoints application (Java)?

How do I add Facebook login and email sign-up to my Google Cloud Endpoints application (Java)?… here is a solution to the problem.

How do I add Facebook login and email sign-up to my Google Cloud Endpoints application (Java)?

So I have an application that uses Google App Engine and Google Cloud Endpoints as Java backends. I’m currently working on user authentication, which is what I’m trying to do :

When users open the app for the first time, they can choose to “sign in via Facebook” or sign up with their email address. This data is then stored in user objects, which will be directed to the application home page after registration. It will be saved in their preferences so that they don’t need to log in every time they open the app, if any.

Now I’ve heard that you can use a custom identity validator for Facebook, but there isn’t much documentation about that. How do I use Google Cloud Endpoint’s identity validator for email sign-up and Facebook sign-in options? Or should I take a different approach?

Thank you.

Solution

My method is to use the Facebook login method (Facebook SDK for Android). The Facebook authentication process (on success) returns an object from which I can get the user’s email and then save it in my Endpoints class using the Datastore API. To check if the user is logged in, I chose the SharedPreferences method and the GSON library to parse objects into JSON strings and save them in preferences.

The link below and my sample code:

Regarding the Authenticator I found this SO answer

More info about Facebook login method

Saving custom objects in SharedPreferences

Get a user’s email through Facebook authentication

 private void onSessionStateChange(Session session, SessionState state, Exception exception) {
        if (state.isOpened()) {
            if (isSessionCalled == false) {
                Log.i(TAG, "Logged in...");
                System.out.println("Token=" + session.getAccessToken());

new Request(
                        session,
                        "/me",
                        null,
                        HttpMethod.GET,
                        new Request.Callback() {
                            public void onCompleted(Response response) {
                                if (response != null) {
                                    GraphObject object = response.getGraphObject();
                                    String email = (String) object.getProperty("email");
                                    Log.i(TAG, "user email : " + email);
                                    String firstName = (String) object.getProperty("first_name");
                                    String lastName = (String) object.getProperty("last_name");
                                    mUserTask = new UserAsyncTask();
                                    mUserTask.execute(email);
                                }

}

}
                ).executeAsync();

isSessionCalled = true;
            }
            else {
                Log.w(TAG, "session called twice");
            }

}

else if (state.isClosed()) {
            Log.i(TAG, "Logged out...");
        }
    }

Store users on my backend:

@ApiMethod(name = "storeUserModel")
    public UserModel storeUserModel(UserModel userModel) throws UserAlreadyExistsException, UserNotFoundException {
        logger.info("inside storeUser");
        String email = userModel.getEmail();
        UserModel checkUser = getUserModel(email);
        logger.info("after getUserModel with email " + email);

if (checkUser == null) {
            logger.info("inside checkUser is NULL");
            DatastoreService datastoreService = DatastoreServiceFactory.getDatastoreService();
            Transaction txn = datastoreService.beginTransaction();
            try {
                Entity userEntity = new Entity(UserModel.class.getSimpleName(), email);
                userEntity.setProperty("nickname", userModel.getNickname());

 TODO save the pheromones with the key of userEntity
                datastoreService.put(userEntity);
                txn.commit();
                storePheromoneList(userModel.getPheromoneList(), userEntity.getKey(), datastoreService);
            } finally {
                if (txn.isActive()) {
                    logger.severe("rolled back with email : " +  email);
                    txn.rollback();
                }
            }
        }
        else {
            throw new UserAlreadyExistsException();
        }
        return userModel;

}

Trigger the class that calls my backend

public class EndpointsServer implements Server {

private static final String TAG = "EndpointsServer";

final UserModelApi userEndpointsApi;

public EndpointsServer() {
        UserModelApi.Builder builder = new UserModelApi.Builder(AndroidHttp.newCompatibleTransport(), new AndroidJsonFactory(), null)
                .setRootUrl("http://10.0.2.2:8080/_ah/api/")
                .setGoogleClientRequestInitializer(new GoogleClientRequestInitializer() {
                    @Override
                    public void initialize(AbstractGoogleClientRequest<?> abstractGoogleClientRequest) throws IOException {
                        abstractGoogleClientRequest.setDisableGZipContent(true);
                    }
                });

userEndpointsApi = builder.build();

}

@Override
    public User getUser(String email)  {
        User  user = null;
        try {
            Log.d(TAG, "in getUser with email " +email);
             get user from db
            UserModel userModel = userEndpointsApi.getUserModel(email).execute();

if (userModel != null) {
                Log.d(TAG, "user != null with email " + email);
                user = new User(userModel);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return user;
    } 
}

Store user on successful login:

String userString = gson.toJson(user, User.class);
SharedPreferences.Editor editor = preferences.edit();
editor.putString(USER_KEY, userString);
editor.commit();

It has more features, such as another client class for building API calls to the backend and many other details. I can post it if you want.

Related Problems and Solutions