title: Authenticating your client to Cloud Endpoints without a Google Account login
body: <p>I have been doing extensive research on how to authenticate your client (Android, iOS, web-app) with Cloud Endpoints <em>without</em> requiring your user to use their Google account login the way the <a href="https://cloud.google.com/appengine/docs/java/endpoints/auth" rel="nofollow noreferrer">documentation</a> shows you.</p>
  
  <p>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.</p>
  
  <p>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 <a href="https://cloud.google.com/appengine/docs/java/endpoints/auth" rel="nofollow noreferrer">documentation</a>. After that I will show you my findings and a potential area for a solution which I need help with.</p>
  
  <p>(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.</p>
  
  <pre><code>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;
          }
  
      } 
  </code></pre>
  
  <p>(3) In Android call the API method in an Asynctask making sure to pass in the <code>credential</code> variable in the <code>Builder</code>:</p>
  
  <pre><code>class EndpointsAsyncTask extends AsyncTask&lt;Pair&lt;Context, String&gt;, Void, String&gt; {
          private static MyApi myApiService = null;
          private Context context;
  
          @Override
          protected String doInBackground(Pair&lt;Context, String&gt;... 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://&lt;your-app-engine-project-id-here&gt;/_ah/api/")
                      .setGoogleClientRequestInitializer(new GoogleClientRequestInitializer() {
                          @Override
                          public void initialize(AbstractGoogleClientRequest&lt;?&gt; 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();
          }
      }
  </code></pre>
  
  <p>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 <code>GoogleAccountCredential</code> object (more info on how to do that <a href="https://cloud.google.com/appengine/docs/java/endpoints/consume_android" rel="nofollow noreferrer">here</a>).</p>
  
  <p>The Google App Engine server receives your request and checks it. If the Android Client is one of the ones you specified in the <code>@Api</code> notation, then the server will inject the <code>com.google.api.server.spi.auth.common.User</code> object into your API method. It is now your responsibility to check if that <code>User</code> object is <code>null</code> or not inside your API method. If the <code>User</code> object is <code>null</code>, 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).</p>
  
  <p>You can get your <code>ANDROID_CLIENT_ID</code> 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 <code>@Api</code> annotation (or put it in a class <code>Constants</code> like specified above for usability).   </p>
  
  <p><strong>I have done some extensive testing with all of the above and here is what I found:</strong></p>
  
  <p>If you specify a bogus or invalid Android clientId in your <code>@Api</code> annotation, the <code>User</code> object will be <code>null</code> in your API method. If you are doing a check for <code>if (user == null) throw new UnauthorizedException("User is Not Valid");</code> then your API method will not run. </p>
  
  <p>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 <code>User</code> object - even if the end user logged in to their Google account and the <code>GoogleAccountCredential</code> was valid.</p>
  
  <p>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 <code>HttpHeader</code> for example?</p>
  
  <p>Another injected type in Cloud Endpoints is the <code>javax.servlet.http.HttpServletRequest</code>. You can get the request like this in your API method:</p>
  
  <pre><code>@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;
              }
  
          }  
  </code></pre>
  
  <p>But I am not sure if the necessary information is there or how to get it.</p>
  
  <p>Certainly <em>somewhere</em> there must be some data that tells us if the Client is an authorized and specified one in the <code>@Api</code> <code>clientIds</code>.</p>
  
  <p>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).</p>
  
  <p>For all of this to work though, you would have to pass in <code>null</code> in the third argument of your <code>Builder</code> like this:</p>
  
  <p>MyApi.Builder builder = new MyApi.Builder(AndroidHttp.newCompatibleTransport(),
                              new AndroidJsonFactory(), null)</p>
  
  <p>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. </p>
  
  <p>I know this is possible because when using a <code>GoogleAccountCredential</code> in the <code>Builder</code>, somehow Cloud Endpoints knows whether or not the call came from an authenticated client and then either injects its <code>User</code> object into the API method or not based on that. </p>
  
  <p>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?</p>
  
  <p>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.</p>
  
  <p><a href="https://stackoverflow.com/questions/16970327/custom-authentication-for-google-cloud-endpoints-instead-of-oauth2?rq=1">Custom Authentication for Google Cloud Endpoints (instead of OAuth2)</a></p>
  
  <p><a href="https://stackoverflow.com/questions/20396577/authenticate-my-app-to-google-cloud-endpoints-not-a-user">Authenticate my &quot;app&quot; to Google Cloud Endpoints not a &quot;user&quot;</a></p>
  
  <p><a href="https://stackoverflow.com/questions/19224728/google-cloud-endpoints-without-google-accounts">Google Cloud Endpoints without Google Accounts</a></p>
  
  <p><strong>EDIT:</strong> 
  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:</p>
  
  <blockquote>
    <p>"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.</p>
    
    <p>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."</p>
  </blockquote>
  
  <p>(frowny face) - however, maybe it is still possible? </p>