Search code examples
androidgoogle-play-servicesgoogle-cloud-endpointsgooglesigninaccount

Use authorized Google Cloud Endpoints with Google Sign in


I have an app that uses Google Cloud Endpoints. Some methods need authorization so I followed this tutorial. This requires the GET_ACCOUNTS permissions.

I am updating the app to work with runtime permissions. I do not like to request permission to read contacts, but GET_ACCOUNTS is in the same group. Because of this I am looking to use authorization without GET_ACCOUNTS permission.

I think that Google Sign In could work but I am unable to find a way to use the result from Google Sign In.

This is the code used to create the object to make the calls to the endpoint:

Helloworld.Builder helloWorld = new Helloworld.Builder(AppConstants.HTTP_TRANSPORT, AppConstants.JSON_FACTORY,credential);

The credential object must be a HttpRequestInitializer but from the Google Sign In I get a GoogleSignInAccount.

So, is it possible to do this? How should this be done?


Solution

  • I finally found the solution. Using the tutorial found here.

    You must add the Client id in the GoogleSignInOptions:

     GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
                .requestIdToken(CLIENT_ID)
                .requestEmail()
                .build();
    

    Following the tutorial you will finaly get a GoogleSignInAccount. Set the token from the GoogleSignInAccount in a GoogleCredential object:

    GoogleCredential credential = new GoogleCredential.Builder().setTransport(new NetHttpTransport())
                .setJsonFactory(JacksonFactory.getDefaultInstance())
                .build();
    credential.setAccessToken(GoogleSignInAccount.getIdToken());
    

    This credential is ready to make authenticated calls to Google Cloud Enpoints.

    Note that you must remove "server:client_id:" part from the CLIENT_ID. So if you were using this:

    credential = GoogleAccountCredential.usingAudience(this,
        "server:client_id:1-web-app.apps.googleusercontent.com");
    

    Your CLIENT_ID would be:

    CLIENT_ID = "1-web-app.apps.googleusercontent.com"
    

    Also note that the token is valid for a limited amount of time (Aprox. 1 hour in my testing)

    To avoid the 1 hour token limitation, use GoogleSignInApi.silentSignIn() to get a new token before every call you make to your endpoint. For example if you are not in the UI thread:

    GoogleSignInOptions options = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN).requestEmail()
                    .requestIdToken(CLIENT_ID)
                    .build();
    GoogleSignInClient client = GoogleSignIn.getClient(context, options);
    GoogleSignInAccount user = Tasks.await(getGoogleSignInClient(context).silentSignIn());
    
    // Use the new user token as before 
    GoogleCredential credential = new GoogleCredential.Builder().setTransport(new NetHttpTransport())
            .setJsonFactory(JacksonFactory.getDefaultInstance())
            .build();
    credential.setAccessToken(user.getIdToken());