25

I'm currently new into the AppEngine world, and wanting to create a backend using Cloud Endpoints for a mobile application that I'm developing.

One of my problem right now is about the user's authentication. I've been following the Udacity's MOOC on App Engine, and they taught us how to authenticate the user for API request using a Google Accounts. On the backend side, we simply have to add a User parameter to our method, and check if the user is signed in. As far as I know, this user parameter is generated by App Engine, based on the Authorization header of our request. (might need some confirmation there)

Now, there's a bunch of stuff I'm not sure to understand and that weren't that well explained on this MOOC.

Now, I'd like to know if this is compatible with other OAuth schemes, beside Google? So, if I want to implement Facebook authentication, will I simply pass the facebook access token?

From what I searched, using the Facebook SDK on Android would lead me to be able to generate a User Access Token, which identifies my user to facebook. After sending it to my backend, I would want to check it's validity with Facebook, and if it's valid, create a new user to my application. Now, I'd also want to generate a new token that identify the user to my app. What would I need to do to do so?

MagicMicky
  • 3,819
  • 2
  • 37
  • 53

2 Answers2

53

You can supply your own authenticator to Endpoints and the injected User will be obtained with your authenticator https://developers.google.com/appengine/docs/java/endpoints/javadoc/com/google/api/server/spi/config/Authenticator.html.

The Facebook credentials can be sent via a header, e.g. Authorization header and it can be accessed from backend via HttpServletRequest, which you can handle inside Authenticator.authenticate method.

For example.

// Custom Authenticator class
public class MyAuthenticator implements Authenticator {
  @Override
  public User authenticate(HttpServletRequest request) {
    String token = request.getHeader("Authorization");
    if (token != null) {
      String user = authenticateFacebook(token);  // apply your Facebook auth.
      if (user != null) {
        return new User(user);
      }
    }
    return null;
  }
}

// Endpoints class.
@Api(name = "example", authenticators = {MyAuthenticator.class})
public class MyEndpoints {
  public Container getThing(User user) {
    Container c = new Container();
    if (user != null) {
      c.email = user.getEmail();
    }
    return c;
  }

  public class Container {
    public String email;
    public String extraData;
  }
}
Alex Lockwood
  • 83,063
  • 39
  • 206
  • 250
Min Wan
  • 556
  • 5
  • 3
  • Great, seems awesome! I'll try that out asap! – MagicMicky Aug 20 '14 at 13:51
  • 1
    I'm currently trying to implement this. Would you have an idea of what is the defautl Authenticator used by Cloud Endpoints? If I still want to be able to auth the user using his Google Account, how can I access the default Google Authenticator? – MagicMicky Aug 28 '14 at 13:31
  • 6
    The default authenticator is com.google.api.server.spi.auth.EndpointsAuthenticator. You can add it to the end of the @authenticators list to make it as a fallback when user provided authenticator fails. Endpoints will try all authenticators and return the first successful one. – Min Wan Sep 04 '14 at 23:07
  • 7
    Thanks a lot. Great functionality for Cloud Endpoints. Too bad there is not enough documentation about it right now! – MagicMicky Sep 07 '14 at 12:38
  • I am doing something similar, @MagicMicky, if you got this working do you have any tips or code you can share? – Chanakya Dec 30 '14 at 01:39
  • @MinWan where did you find this? If I google that class I barely get any results. – Pega88 Jan 19 '15 at 19:42
  • 2
    @MinWan I have asked a separate question regarding proper handling of the User parameter in the described scenario here: http://stackoverflow.com/questions/28445840/how-can-i-pass-custom-information-from-an-app-engine-authenticator-to-the-endpoi – Oliver Hausler Feb 11 '15 at 03:01
  • When I try your example I always get an: java.lang.NullPointerException: authDomain must be specified. But I cannot set an authDomain on the User object. Any ideas? – flosk8 Jun 30 '15 at 21:14
  • Is the User used as return type of authenticate(HttpServletRequest request) method the type: com.google.appengine.api.users.User ? I cannot get it from the official documentation https://cloud.google.com/appengine/docs/java/endpoints/javadoc/com/google/api/server/spi/config/Authenticator – FilipR Jul 08 '15 at 16:52
  • I understand how this example works and how the Google accounts system works, but my question is, since you specify the `clientIds = {Constants.WEB_CLIENT_ID, Constants.ANDROID_CLIENT_ID, Constants.IOS_CLIENT_ID, Constants.API_EXPLORER_CLIENT_ID}, audiences = {Constants.ANDROID_AUDIENCE},` in your `@api` notation, can you somehow just authenticate without having the end user log in to anything? Is there some special data you can get form the headers that just say "yes this is a specified client"? I want an app where there is no login for the user but with the cloud endpoints secure – Micro Aug 20 '15 at 15:54
  • @MinWan any idea how do I send this kind of header when using JS library in the client side ? – serj Dec 30 '15 at 19:50
  • thanks so much, i've been wondering about this.... it is crazy how little documentation there is on this stuff – Creos Feb 29 '16 at 23:53
  • How do you set the Facebook (or any custom auth) token in the header on the client side? – ashughes Mar 17 '16 at 00:54
1

When I try your example I always get an: java.lang.NullPointerException: authDomain must be specified. But I cannot set an authDomain on the User object. Any ideas?

UPDATE: This is connected to this Bug https://code.google.com/p/googleappengine/issues/detail?id=12060&q=endpoints&colspec=ID%20Type%20Component%20Status%20Stars%20Summary%20Language%20Priority%20Owner%20Log

in version 1.9.22

flosk8
  • 465
  • 1
  • 6
  • 17