4

I've just created my own custom authentication on my google app engine Java app. And it wasn't that much of a trouble as is the next thing I'm trying to do.

Authentication works fine but now I'm trying to add some additional fields to the default User object so that I wouldn't have to make so many calls to the server.

So what I've done so far is created a custom class that implements Authenticator. Based on whether the user is authenticated or not the authenticate method returns the User object or null. User object is then accessible to my API endpoints.

To extend my app functionality I've tried extending the default User object, making some new fields, and then passing it to endpoints. However, since the User object accessible by endpoints is not the same kind as the one I extended from I can't get the extra fields.

MyAuthenticator.java

import com.google.api.server.spi.auth.common.User;

public class MyAuthenticator implements Authenticator {

@Override
public User authenticate(HttpServletRequest request) {
    // some code
    return new AuthUser(...)
}

AuthUser.java

import com.google.api.server.spi.auth.common.User;

public class AuthUser extends User {
private String newToken;

public AuthUser(String email) {
    super(email);
}

public AuthUser(String id, String email) {
    super(id, email);
}

public AuthUser(String id, String email, String newToken) {
    super(id, email);
    this.newToken = newToken;
}

public String getNewToken() {
    return newToken;
}
}

UserEndpoint.java

import com.google.appengine.api.users.User;

@Api(authenticators = MyAuthenticator.class)
public class UserEndpoint {
@ApiMethod(httpMethod = "GET")
public final Response sth(User user)
        throws UnauthorizedException {
    EndpointUtil.throwIfNotAuthenticated(user);
    // ...
}

Notice different class imports.

I can't use AuthUser in UserEndpoint sth method because then API expects me to post that object with my call to server.

How can I pass extra data from authenticator to my endpoint method?

Zeehad
  • 1,012
  • 1
  • 9
  • 11
alesko007
  • 219
  • 1
  • 3
  • 12

1 Answers1

5

AppEngine docs say the injected types are the following:

  • com.google.appengine.api.users.User
  • javax.servlet.http.HttpServletRequest
  • javax.servlet.ServletContext

However, it doesn't mention com.google.api.server.spi.auth.common.User, but it works for sure. I just tried with AppEngine Java SDK 1.9.32. I don't know if it's a bug or feature.

So in UserEndpoint.java, you have to import com.google.api.server.spi.auth.common.User, then you can cast it to AuthUser.

import com.google.api.server.spi.auth.common.User;

@Api(authenticators = MyAuthenticator.class)
public class UserEndpoint {
@ApiMethod(httpMethod = "GET")
public final Response sth(User user)
        throws UnauthorizedException {
    EndpointUtil.throwIfNotAuthenticated(user);

    ((AuthUser)user).getNewToken();

    // ...
}
Zoltán Barics
  • 431
  • 6
  • 11
  • 1
    I can confirm that using com.google.api.server.spi.auth.common.User in the Endpoint method works. – DFB Mar 29 '16 at 16:48
  • 1
    So sad, but this only works as long as you have no body in the incoming request. As soon as the request has a body, you can't compile because the compiler thinks `com.google.api.server.spi.auth.common.User` is the body from the endpoint: "Multiple entity parameters. (...)" – Oliver Hausler Aug 06 '16 at 19:47
  • I was going nuts! this answer was of great help. – Germán Sep 19 '16 at 00:33
  • The link to the AppEngine docs does not work anymore. Now Google says [https://cloud.google.com/endpoints/docs/frameworks/java/authenticating-users] that the injected type is `com.google.api.server.spi.auth.common.User`. I still use `com.google.appengine.api.users.User`. Does anyone know the difference? – rakensi Sep 09 '20 at 07:54
  • The difference between the two `User` classes is explained in [https://stackoverflow.com/a/40227633/1021892]. It is best to use `com.google.appengine.api.users.User`. – rakensi Sep 09 '20 at 09:10