im working on an android app with some server-side business logic. Im using android studio and im creating that kind of app for a first time.
I am trying to use server-side application to login to a different system and return me a cookie, so my android application can tell, whether the set credentials are correct.
Here's my endpoint provided method.
/** Returns user with cookie set either to null or actual cookie from AIS */
#ApiMethod(name = "login")
public User login(#Named("loginName") String name, #Named("password") String password) {
AISCommunicator aisCommunicator = new AISCommunicator();
String cookieVal = aisCommunicator.login(password,name);
User user = new User();
user.setCookie(cookieVal);
//user.setCookie("asdasdasd");
return user;
}
AISCommunicator is a serverside bean. At the moment it's part of a code
CookieManager manager = new CookieManager();
manager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
CookieHandler.setDefault(manager);
is marked as incorrect by Android studio, which tells me, that to use it, i need to declare minSdk level 9, while currently i have 1. How can i do that? I have set minSdk in my client's app, but it seems like it does not influence the serverside bean.
Anyway, the code is still runnable for some reason and the endpoint Bean returns 404 not found error at the moment.
Ignore Android Studio's error. This is one of its known and unfixed bugs.
Related
Making app in Unity.
App works perfectly in Unity editor:
can access firebase for user login - this isnt the issue
can read and write from/to google sheet located in google drive using service account
When I build to android (apk file), and install on physical andoid device (Samsung S20 phone):
can access firebase for user login - so it is not an network/internet problem
CANT read/write from google sheet.
A portion of my code is here:
Authorisation - i am not sure if this bit works on the phone, or how to check.
public void Auth() // authorise access to the googlesheet online
{
//jsonKey = File.ReadAllText("Assets/Resources/Creds/beerhats-db-3***.json"); // location of key - read it - save to string
TextAsset txtAsset = (TextAsset)Resources.Load("beerhats-db-3***", typeof(TextAsset)); //i changed the file name here on stackoverflow just in case its a security thing
string jsonKey = txtAsset.text;
ServiceAccountCredential.Initializer initializer = new ServiceAccountCredential.Initializer(Secrets.serviceAccountID);
var jsonData = (JObject)JsonConvert.DeserializeObject(jsonKey);
if (jsonData != null) // the json file isnt moving or changing - so probably dont need an if statemet - remove later
{
string privateKey = jsonData["private_key"].Value<string>(); // specifically get the private key from all the data in the json file
ServiceAccountCredential credential = new ServiceAccountCredential(initializer.FromPrivateKey(privateKey));
service = new SheetsService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
});
}
}
Part of my ReadFile code:
public async Task<string> ReadFile(string sheetName, string cellLocation) // for reading data only
{
// creates a string of location to write to
string whereToRead = sheetName + "!" + cellLocation;
SpreadsheetsResource.ValuesResource.GetRequest request = service.Spreadsheets.Values.Get(Secrets.spreadsheetID, whereToRead);
StringBuilder sb = new StringBuilder();
ValueRange response = await request.ExecuteAsync(); // run this on a separate thread as it takes long?
IList<IList<object>> values = response.Values;
On the phone, it executes the stringbuilder line, but not the executeasync() line.
Tried:
upgrade Unity version
change the min and target API levels
introduced keystore and project keys
introduced async incase it was a loading issue
change custom gradle template checkboxes
change read access on android sdk
update nuget installs of google apis
asking chatgpt for help
looking at various forums for similar issues
I am not running on an emulator, so no help with errors during run time. No errors in editor when built.
Expecting:
when installed on android device, the app to read/write from google sheet located in google drive
Requesting:
ideas to try to get this working! Thankyou :)
I have an Android application in which I'm using Azure AD B2C to authenticate users. Users login and logout of the application as needed. I would like to give the user the option to delete their own account.
I understand that I need to use the Azure AD Graph API to delete the user. This is what I have so far:
According to this link, it looks like deleting a user from a personal account (which is what the B2C users are using) is not possible. Is that correct?
Here's my code snippet for the Graph API call. Feel free to ignore it if I'm off track and there is a better way to solve this.
I believe I need a separate access token than what my app currently has (as the graph API requires other API consent). So, I'm getting the access token as follows:
AcquireTokenParameters parameters = new AcquireTokenParameters.Builder()
.startAuthorizationFromActivity(getActivity())
.fromAuthority(B2CConfiguration.getAuthorityFromPolicyName(B2CConfiguration.Policies.get("SignUpSignIn")))
.withScopes(B2CConfiguration.getGraphAPIScopes())
.withPrompt(Prompt.CONSENT)
.withCallback(getGraphAPIAuthCallback())
.build();
taxApp.acquireToken(parameters);
In the getGraphAPIAuthCallback() method, I'm calling the Graph API using a separate thread (in the background):
boolean resp = new DeleteUser().execute(authenticationResult.getAccessToken()).get();
Finally, in my DeleterUser() AsyncTask, I'm doing the following:
#Override
protected Boolean doInBackground(String... aToken) {
final String asToken = aToken[0];
//this method will be running on background thread so don't update UI from here
//do your long running http tasks here,you dont want to pass argument and u can access the parent class' variable url over here
IAuthenticationProvider mAuthenticationProvider = new IAuthenticationProvider() {
#Override
public void authenticateRequest(final IHttpRequest request) {
request.addHeader("Authorization",
"Bearer " + asToken);
}
};
final IClientConfig mClientConfig = DefaultClientConfig
.createWithAuthenticationProvider(mAuthenticationProvider);
final IGraphServiceClient graphClient = new GraphServiceClient.Builder()
.fromConfig(mClientConfig)
.buildClient();
try {
graphClient.getMe().buildRequest().delete();
} catch (Exception e) {
Log.d(AccountSettingFragment.class.toString(), "Error deleting user. Error Details: " + e.getStackTrace());
}
return true;
}
Currently, my app fails when trying to get an access token with a null pointer exception:
com.microsoft.identity.client.exception.MsalClientException: Attempt to invoke virtual method 'long java.lang.Long.longValue()' on a null object reference
Any idea what I need to do to provide the user the option to users to delete their own account? Thank you!
Thanks for the help, #allen-wu. Due to his help, this azure feedback request and this azure doc, I was able to figure out how to get and delete users silently (without needing intervention).
As #allen-wu stated, you cannot have a user delete itself. So, I decided to have the mobile app call my server-side NodeJS API when the user clicks the 'Delete Account' button (as I do not want to store the client secret in the android app) and have the NodeJS API call the Azure AD endpoint to delete the user silently. The one caveat is that admin consent is needed the first time you try to auth. Also, I have only tested this for Graph API. I'm not a 100% sure if it works for other APIs as well.
Here are the steps:
Create your application in your AAD B2C tenant. Create a client secret and give it the following API permissions: Directory.ReadWrite.All ;
AuditLog.Read.All (I'm not a 100% sure if we need the AuditLog permission. I haven't tested without it yet).
In a browser, paste the following link:
GET https://login.microsoftonline.com/{tenant}/adminconsent?
client_id=6731de76-14a6-49ae-97bc-6eba6914391e
&state=12345
&redirect_uri=http://localhost/myapp/permissions
Login using an existing admin account and provide the consent to the app.
Once you've given admin consent, you do not have to repeat steps 1-3 again. Next, make the following call to get an access token:
POST https://login.microsoftonline.com/{B2c_tenant_name}.onmicrosoft.com/oauth2/v2.0/token
In the body, include your client_id, client_secret, grant_type (the value for which should be client_credentials) and scope (value should be 'https://graph.microsoft.com/.default')
Finally, you can call the Graph API to manage your users, including deleting them:
DELETE https://graph.microsoft.com/v1.0/users/{upn}
Don't forget to include the access token in the header. I noticed that in Postman, the graph api had a bug and returned an error if I include the word 'Bearer' at the start of the Authorization header. Try without it and it works. I haven't tried it in my NodeJS API yet, so, can't comment on it so far.
#allen-wu also suggested using the ROPC flow, which I have not tried yet, so, cannot compare the two approaches.
I hope this helps!
There is a line of code: graphClient.getUsers("").buildRequest().delete();
It seems that you didn't put the user object id in it.
However, we can ignore this problem because Microsoft Graph doesn't allow a user to delete itself.
Here is the error when I try to do it.
{
"error": {
"code": "Request_BadRequest",
"message": "The principal performing this request cannot delete itself.",
"innerError": {
"request-id": "8f44118f-0e49-431f-a0a0-80bdd954a7f0",
"date": "2020-06-04T06:41:14"
}
}
}
I'm trying to authenticate an end-user in an android app written in C# (Xamarin.Android).
I decided to try and use NuGet package Google.Apis.Oauth.v2 which seems to expose an easy to use Oauth client.
LocalServerCodeReceiver.ReceiveCodeAsync throws the following:
I get System.NotSupportedException:"Failed to launch browser with https://XXX.auth.XXX.amazoncognito.com/login?response_type=token&client_id=XXX&redirect_uri=https%3A%2F%2Fwww.google.com&scope=profile%20openid%20email for authorization. See inner exception for details."
and it has an inner exception of System.ComponentModel.Win32Exception:"Cannot find the specified file"
Code:
var clientSecret = new Google.Apis.Auth.OAuth2.ClientSecrets();
clientSecret.ClientId = ...
clientSecret.ClientSecret = ...
var initializer = new Google.Apis.Auth.OAuth2.Flows.AuthorizationCodeFlow.Initializer(
"https://XXX.auth.XXX.amazoncognito.com/login",
"https://XXX.auth.XXX.amazoncognito.com/login");
initializer.Scopes = new List<string> {"profile", "openid", "email"};
initializer.ClientSecrets = clientSecret;
var flow = new Google.Apis.Auth.OAuth2.Flows.AuthorizationCodeFlow(initializer);
var authCodeRequestURL = flow.CreateAuthorizationCodeRequest("https://www.google.com");
authCodeRequestURL.ResponseType = "token";
var uri = authCodeRequestURL.Build();
var cancellationTokenSource = new System.Threading.CancellationTokenSource();
var codeReceiver = new Google.Apis.Auth.OAuth2.LocalServerCodeReceiver();
var task = codeReceiver.ReceiveCodeAsync(authCodeRequestURL, cancellationTokenSource.Token);
Do I need to ask for a specific permission in the application manifest?
Instead of redirecting to www.google.com, I've heard you can redirect to an app, I'm not really sure how to do that, is it http://my_app_package_name or http://my_app_title, something else?
Is it possible not to rely on that library for launching the browser and instead get the RequestUri and start an Activity, if so how will the app become aware the end-user completed the SignIn process and how will the app retrieve the token?
Sorry, but Google.Apis.Oauth.v2 does not support Xamarin, and there's no simple way to get it working.
Unfortunately no Google.Apis.* packages currently support Xamarin.
You might find the Xamarin.Auth package does what you want?
I've figured out how to redirect to an app after authentication in the browser completes.
It's called a "Deep Link" and it's documented at enter link description here, essentially you need to declare an IntentFilter on your Activity, which registers with the Android OS that if someone clicks or an page redirects to a specific URI, your app gets called. The token that's appended to the URI can then be read inside your app.
I have been doing extensive research on how to authenticate your client (Android, iOS, web-app) with Cloud Endpoints without requiring your user to use their Google account login the way the documentation shows you.
The reason for this is that I want to secure my API or "lock it down" to only my specified clients. Sometimes I will have an app that does not have a user login. I would hate to pester my user to now sign in just so my API is secure. Or other times, I just want to manage my own users like on a website and not use Google+, Facebook, or whatever else login authentication.
To start, let me first show the way you can authenticate your Android app with your Cloud Endpoints API using the Google Accounts login as specified in the documentation. After that I will show you my findings and a potential area for a solution which I need help with.
(1) Specify the client IDs (clientIds) of apps authorized to make requests to your API backend and (2) add a User parameter to all exposed methods to be protected by authorization.
public class Constants {
public static final String WEB_CLIENT_ID = "1-web-apps.apps.googleusercontent.com";
public static final String ANDROID_CLIENT_ID = "2-android-apps.googleusercontent.com";
public static final String IOS_CLIENT_ID = "3-ios-apps.googleusercontent.com";
public static final String ANDROID_AUDIENCE = WEB_CLIENT_ID;
public static final String EMAIL_SCOPE = "https://www.googleapis.com/auth/userinfo.email";
}
import com.google.api.server.spi.auth.common.User; //import for the User object
#Api(name = "myApi", version = "v1",
namespace = #ApiNamespace(ownerDomain = "${endpointOwnerDomain}",
ownerName = "${endpointOwnerDomain}",
packagePath="${endpointPackagePath}"),
scopes = {Constants.EMAIL_SCOPE},
clientIds = {Constants.WEB_CLIENT_ID, Constants.ANDROID_CLIENT_ID,
Constants.IOS_CLIENT_ID,
Constants.API_EXPLORER_CLIENT_ID},
audiences = {Constants.ANDROID_AUDIENCE})
public class MyEndpoint {
/** A simple endpoint method that takes a name and says Hi back */
#ApiMethod(name = "sayHi")
public MyBean sayHi(#Named("name") String name, User user) throws UnauthorizedException {
if (user == null) throw new UnauthorizedException("User is Not Valid");
MyBean response = new MyBean();
response.setData("Hi, " + name);
return response;
}
}
(3) In Android call the API method in an Asynctask making sure to pass in the credential variable in the Builder:
class EndpointsAsyncTask extends AsyncTask<Pair<Context, String>, Void, String> {
private static MyApi myApiService = null;
private Context context;
#Override
protected String doInBackground(Pair<Context, String>... params) {
credential = GoogleAccountCredential.usingAudience(this,
"server:client_id:1-web-app.apps.googleusercontent.com");
credential.setSelectedAccountName(settings.getString(PREF_ACCOUNT_NAME, null));
if(myApiService == null) { // Only do this once
MyApi.Builder builder = new MyApi.Builder(AndroidHttp.newCompatibleTransport(),
new AndroidJsonFactory(), credential)
// options for running against local devappserver
// - 10.0.2.2 is localhost's IP address in Android emulator
// - turn off compression when running against local devappserver
.setRootUrl("http://<your-app-engine-project-id-here>/_ah/api/")
.setGoogleClientRequestInitializer(new GoogleClientRequestInitializer() {
#Override
public void initialize(AbstractGoogleClientRequest<?> abstractGoogleClientRequest) throws IOException {
abstractGoogleClientRequest.setDisableGZipContent(true);
}
});
// end options for devappserver
myApiService = builder.build();
}
context = params[0].first;
String name = params[0].second;
try {
return myApiService.sayHi(name).execute().getData();
} catch (IOException e) {
return e.getMessage();
}
}
#Override
protected void onPostExecute(String result) {
Toast.makeText(context, result, Toast.LENGTH_LONG).show();
}
}
What is happening is that in your Android app you are showing the Google account picker first, storing that Google account email in you shared preferences, and then later setting it as part of the GoogleAccountCredential object (more info on how to do that here).
The Google App Engine server receives your request and checks it. If the Android Client is one of the ones you specified in the #Api notation, then the server will inject the com.google.api.server.spi.auth.common.User object into your API method. It is now your responsibility to check if that User object is null or not inside your API method. If the User object is null, you should throw an exception in your method to prevent it from running. If you do not do this check, your API method will execute (a no-no if you are trying to restrict access to it).
You can get your ANDROID_CLIENT_ID by going to your Google Developers Console. There, you provide the package name of your Android App and the SHA1 which generates for you an android client id for you to use in your #Api annotation (or put it in a class Constants like specified above for usability).
I have done some extensive testing with all of the above and here is what I found:
If you specify a bogus or invalid Android clientId in your #Api annotation, the User object will be null in your API method. If you are doing a check for if (user == null) throw new UnauthorizedException("User is Not Valid"); then your API method will not run.
This is surprising because it appears there is some behind the scenes validation going on in Cloud Endpoints that check whether the Android ClientId is valid or not. If it is invalid, it won't return the User object - even if the end user logged in to their Google account and the GoogleAccountCredential was valid.
My question is, does anyone know how I can check for that type of ClientId validation on my own in my Cloud Endpoints methods? Could that information be passed around in an HttpHeader for example?
Another injected type in Cloud Endpoints is the javax.servlet.http.HttpServletRequest. You can get the request like this in your API method:
#ApiMethod(name = "sayHi")
public MyBean sayHi(#Named("name") String name, HttpServletRequest req) throws UnauthorizedException {
String Auth = req.getHeader("Authorization");//always null based on my tests
MyBean response = new MyBean();
response.setData("Hi, " + name);
return response;
}
}
But I am not sure if the necessary information is there or how to get it.
Certainly somewhere there must be some data that tells us if the Client is an authorized and specified one in the #Api clientIds.
This way, you could lock-down your API to your Android app (and potentially other clients) without ever having to pester your end users to log in (or just create your own simple username + password login).
For all of this to work though, you would have to pass in null in the third argument of your Builder like this:
MyApi.Builder builder = new MyApi.Builder(AndroidHttp.newCompatibleTransport(),
new AndroidJsonFactory(), null)
Then in your API method extract whether or not the call came from an authenticated client, and either throw an exception or run whatever code you wanted to.
I know this is possible because when using a GoogleAccountCredential in the Builder, somehow Cloud Endpoints knows whether or not the call came from an authenticated client and then either injects its User object into the API method or not based on that.
Could that information be in the header or body somehow? If so, how can I get it out to later check if it is there or not in my API method?
Note: I read the other posts on this topic. They offer ways to pass in your own authentication token - which is fine - but your .apk will still not be secure if someone decompiles it. I think if my hypothesis works, you will be able to lock-down your Cloud Endpoints API to a client without any logins.
Custom Authentication for Google Cloud Endpoints (instead of OAuth2)
Authenticate my "app" to Google Cloud Endpoints not a "user"
Google Cloud Endpoints without Google Accounts
EDIT:
We used Gold Support for the Google Cloud Platform and have been talking back and forth with their support team for weeks. This is their final answer for us:
"Unfortunately, I haven't had any luck on this. I've asked around my
team, and checked all of the documentation. It looks like using OAuth2
is your only option. The reason is because the endpoint servers handle
the authentication before it reaches your app. This means you wouldn't
be able to develop your own authentication flow, and would get results
much like what you were seeing with the tokens.
I would be happy to submit a feature request for you. If you could
provide a little more information about why the OAuth2 flow doesn't
work for your customers, I can put the rest of the information
together and submit it to the product manager."
(frowny face) - however, maybe it is still possible?
I have implemented Endpoint Auth using a custom header "Authorization" and it works just fine. In my case this token is set after login but should work all the same with your app. Check your tests because the value should be there.
The way to retrieve that header is indeed:
String Auth = req.getHeader("Authorization");
You could take it a step further and define your own implementations of an Authenticator and apply it to your secure API calls.
So you don't have any user specific info, but just want to ensure that only your app is able to communicate with your backend...
This is what i think,
change
#Api(name = "myApi", version = "v1",
namespace = #ApiNamespace(ownerDomain = "${endpointOwnerDomain}",
ownerName = "${endpointOwnerDomain}",
packagePath="${endpointPackagePath}"),
scopes = {Constants.EMAIL_SCOPE},
clientIds = {Constants.WEB_CLIENT_ID, Constants.ANDROID_CLIENT_ID,
Constants.IOS_CLIENT_ID,
Constants.API_EXPLORER_CLIENT_ID},
audiences = {Constants.ANDROID_AUDIENCE})
{
...
}
to
#Api(name = "myApi", version = "v1",
namespace = #ApiNamespace(ownerDomain = "${endpointOwnerDomain}",
ownerName = "${endpointOwnerDomain}",
packagePath="${endpointPackagePath}"),
scopes = {Constants.EMAIL_SCOPE},
clientIds = {Constants.ANDROID_CLIENT_ID},
audiences = {Constants.ANDROID_AUDIENCE})
{
...
}
The Client ID is generated from the signature of your app. It can't be replicated. If you only allow your endpoints to accept requests from the Android App, your problem would be solved.
Tell me if this works.
Faced the same problem to find a solution to call my API safely from my endpoints, without using Google Account. We can't decompile an IOS App (Bundle), but decompile an Android App is so simple..
The solution I found is not perfect but do the job pretty good:
On android APP, I just create an constant String variable, named APIKey, with simply content (For example "helloworld145698")
Then I encrypt it with sha1, next md5, and finally sha1 (Order and frequency of encryption up to you) and store the variable on SharedPref (For Android) in private mode (Do this action on an random class in your App) It's this result encrypted I authorize on my Backend !
On my backend, I just add a parameter (named token for exemple) on every request
Example:
#ApiMethod(name = "sayHi")
public void sayHi(#Named("name") String name, #Named("Token") String token) {
if (token == tokenStoreOnAPIServer) {
//Allow it
} else {
//Refuse it and print error
}
}
On android, active ProGuard for obfuscated your code. It will be really unreadable for anyone who tried to decompile your app (Reverse engineering is really hardcore)
Not THE perfect secure solution, but it works, and it will be really really (really) difficult to find the real API key for anyone who try to read your code after decompilation.
Authentication and app engine, there is a lot to be read about it, but a lot seems to be outdated!
Even the google pages https://developers.google.com/appengine/docs/java/endpoints/consume_android#making-authenticated-calls
Here, they talk about 'GoogleAccountCredential.usingAudience', but nowadays, you should use GoogleAuthUtil (as far as I know, please correct me if I'm wrong).
I am trying to set up an app engine as a backend to my Android app (and in future, my iOS app).
I am using Android Studio, used the 'new module' and chose app engine with cloud messaging there.
I created a simple endpoint, and have a function there, here is some code:
public class ReviewEndpoint {
// Make sure to add this endpoint to your web.xml file if this is a web application.
private static final Logger LOG = Logger.getLogger(ReviewEndpoint.class.getName());
/**
* This method gets the <code>Review</code> object associated with the specified <code>id</code>.
* #param id The id of the object to be returned.
* #return The <code>Review</code> associated with <code>id</code>.
*/
#ApiMethod(name = "getReview")
public Review getReview(#Named("id") Long id) {
// Implement this function
Review r = new Review();
r.setData("test!");
As you can see, this is nicely generated by Android Studio. I implemented some stuf like creating the 'review' object and return it at the end.
On the Android side, I can do this:
ReviewEndpoint.Builder b = new ReviewEndpoint.Builder(AndroidHttp.newCompatibleTransport(), new AndroidJsonFactory(), null);
ReviewEndpoint ep = b.build();
Review review = ep.getReview(1L).execute();
data = review.getData();
and yes, I get 'test!' :)
Now, I want to have this authenticated. I want to know which user wrote what, so I thought I am going to use GMail account and Facebook later.
Here I'm stuck. I am able to get a token from the user on Android:
token = GoogleAuthUtil.getToken(MainScreenActivity.this, mAccount.name, "oauth2:https://www.googleapis.com/auth/plus.me https://www.googleapis.com/auth/userinfo.profile");
then you are able to add this token as credential to the request:
Credential cr = new Credential(BearerToken.authorizationHeaderAccessMethod()).setAccessToken(token);
ReviewEndpoint.Builder b = new ReviewEndpoint.Builder(AndroidHttp.newCompatibleTransport(), new AndroidJsonFactory(), cr);
Then in the app engine I tried to get the user info, but how?
Will it be supplied as 'bearer'? How do I get this bearer token? Should I then do API request to get the data on the server?
this does not work:
OAuthService service = OAuthServiceFactory.getOAuthService();
try {
User user = service.getCurrentUser();
can anyone give me a heads up?
So finally, today, I found out how to do it! I had questions on Stackoverflow on this before and never had an answer, but these to sites gave me the answer:
https://developers.google.com/appengine/docs/java/endpoints/auth
https://developers.google.com/appengine/docs/java/endpoints/consume_android
The first shows what needs to be done on the app engine side. The second page will tell you how to get the credentials. I was quite close. I am not sure if the adjusting of the build.gradle file mentioned in the second link is necessary. What I added to the App Engine:
#Api(name = "reviewEndpoint", version = "v1", ...<<some more stuff here >>
scopes = {Constants.EMAIL_SCOPE},
clientIds = {Constants.WEB_CLIENT_ID, Constants.ANDROID_CLIENT_ID},
audiences = {Constants.ANDROID_AUDIENCE})
and then get the credentials:
// Initialize the scope using the client ID you got from the Console.
final String scope = "server:client_id:" + Constants.WEB_CLIENT_ID;
credential = GoogleAccountCredential.usingAudience(activity,scope);
You have to add the e-mail address of the user:
credential.setSelectedAccountName("some-mail-address#gmail.com");
you can get the e-mail address using the account picker (also example shown when you follow the link)
and next. you do a call to the endpoint, using the credential, I think Play Services will validate the user, because if I use an e-mail that is not logged in on the device, it will not work. The following code will throw an GoogleAuthIOException :
ReviewEndpoint.Builder b = new ReviewEndpoint.Builder(
AndroidHttp.newCompatibleTransport(),
new AndroidJsonFactory(), id_token);
ReviewEndpoint ep = b.build();
Review review;
review = ep.getReview(1L).execute();
for testing, I've put the e-mail address I get at the server side as a string in the review object, and there it gave me the e-mail address instead of the user object being null. Ow! I forgot to tell you, you need a user argument on the app engine side. Even though you do not see the 'user' argument in the 'getReview' call above, it will be added by App Engine.
So this is how my getReview looks now:
#ApiMethod(name = "getReview")
public Review getReview(#Named("id") Long id, User user) {
// Implement this function
Review r = new Review();
r.setData("user == " + (user == null ? "NULL " : user.toString()));
Hope this will help someone