Google APIs - App-Level Authorization for Android BigQuery Client - android

I've set up a project in Google API's for use with BigQuery. I've generated Client ID credentials and am using the BigQuery client for Android.
GoogleAccountCredential credential = GoogleAccountCredential.usingOAuth2(getApplicationContext(), Collections.singleton(BigqueryScopes.BIGQUERY));
...Display User Picker...
credential.setSelectedAccountName("account.selected.by.user#gmail.com");
Bigquery bigQuery = new Bigquery.Builder(AndroidHttp.newCompatibleTransport(), GsonFactory.getDefaultInstance(), credential)
.setApplicationName("My-App/1.0").build()
...use bigQuery to run a job or do whatever...
We can successfully connect to BigQuery, but only for Project Member Accounts as seen at https://console.developers.google.com/project/apps~my-project-name/permissions. Use of other accounts results in 403 Access Denied JSON errors from the BigQuery Client.
The app is to be deployed to any number of users where we do not know their accounts ahead of time. This workflow doesn't support that, unless I'm missing some trick.
It's starting to smell like we need to set up an App Engine app, use GoogleAccountCredential.usingAudience, and set up web services as a pass-through to BigQuery.
Any ideas or thoughts will be appreciated with up votes.

This can be accomplished by using a Service Account, which is typically geared for server-to-server communication.
Follow the instructions at https://developers.google.com/bigquery/docs/authorization#service-accounts-server.
GoogleCredential credential = new GoogleCredential.Builder().setTransport(TRANSPORT)
.setJsonFactory(JSON_FACTORY)
.setServiceAccountId("XXXXXXX#developer.gserviceaccount.com")
.setServiceAccountScopes(SCOPE)
.setServiceAccountPrivateKeyFromP12File(new File("my_file.p12"))
.build();
bigquery = new Bigquery.Builder(TRANSPORT, JSON_FACTORY, credential)
.setApplicationName("BigQuery-Service-Accounts/0.1")
.setHttpRequestInitializer(credential).build();
Save the p12 file to your assets folder, and generate a physical File object out of the InputStream from the p12 file in assets.
In this way, you can have your Android application act as a non-user-centric client of BigQuery. Awesome!

Related

Getting a Google Speech API access token for a production Android app

I'm using the Google Speech API in an Android app. The README states:
In this sample, we load the credential from a JSON file stored in a raw resource folder of this client app. You should never do this in your app. Instead, store the file in your server and obtain an access token from there.
Are there any samples regarding how to properly obtain an access token for a production app?
From what I've gathered, it seems that I can use Application Default Credentials provided via Compute Engine or GAE, but I have no idea how to actually respond with an access token to my app.
I'm the author of the sample.
Here's the part that should be on the server side. Basically, you have to store the JSON file securely on your server side, and fetch a new access token when you get a request from your mobile app. Mobile app should always talk with your server to get an access token. This way, you don't need to put your service account key in the APK.
// In response to a request from a mobile client
// Open the JSON file stored on the server side.
final InputStream stream = ...;
try {
// Initialize the credentials
final GoogleCredentials credentials =
GoogleCredentials.fromStream(stream)
.createScoped(SCOPE);
// Fetch a new access token.
final AccessToken token = credentials.refreshAccessToken();
// Return the token to the mobile app.
} catch (IOException e) {
// Maybe report this as an HTTP error.
}
If you don't use Java on your server side, you can find a client library for the language you use at Google Cloud Client Libraries.
Refer to Google Cloud Platform Auth Guide for basics about how to send requests from your backend to the API.
For Android, you might instead want to use the Android sample for Google Cloud Speech as the Cloud client library does not currently focus on Android support.

How to add more scopes in GoogleCloud Endpoints

So, I want to use Plus.me or lets say userinfo.profile scope with Google Cloud Endpoints with python as a backend.
Server Configuration:
#endpoints.api( name='sidebar', version='v1',# auth=AUTH_CONFIG,
allowed_client_ids=[WEB_CLIENT_ID,
ANDROID_CLIENT_ID,
endpoints.API_EXPLORER_CLIENT_ID],
audiences=[ANDROID_AUDIENCE],
scopes=[endpoints.EMAIL_SCOPE, "https://www.googleapis.com/auth/plus.me"])
class Sidebar(remote.Service):
Does anybody have an idea how to send the appropriate scope from android client?
All I know about setting up the android client is:
Android Client Configuration:
String WEB_CLIENT_ID = "xxxxxxxxxx-bbbbbbbbbbbbbbbbbbbbbbbbb.apps.googleusercontent.com";
GoogleAccountCredential credential = GoogleAccountCredential.usingAudience(
mContext, AUDIENCE);
credential.setSelectedAccountName(accountName);
Sidebar.Builder api = new Sidebar.Builder(AndroidHttp.newCompatibleTransport(), new GsonFactory(), credential);
api.setRootUrl(mRootUrl);
So, using this configuration doesnt work. get_current_user() returns None and there is an error in the server logs:
"Oauth framework user didn't match oauth token user."
If I remove the "https://www.googleapis.com/auth/plus.me" scope then the get_current_user() returns the user.
This thing is expected as I am not supplying a token for this scope or the scope itself from android client. So, How can I get this working? What changes do I need to do in the android client?

Error 401 Google-api-php-client verifing by server Android inapppurchase

I need to verify on my server each Android purchase that was made before by user in my Android APP.
I though that working with google-api-php-client it would be easy the authentication and managing of the token in server. But there aren't any sample, and yesterday Google published new version 0.6.3 providing in-app-purchases service.
I followed -> *code.google.com/p/google-api-php-client/wiki/OAuth2#Service_Accounts*
On my code.google.com/apis/console/ I pushed on, "Google Play Android Developer API" and I configured the "service account" in API Access.
From Android client APP, server recives the PACKAGE_NAME, PRODUCT_ID and purchase TOKEN.
My server code is the following:
require_once '../../src/Google_Client.php';
require_once '../../src/contrib/Google_AndroidpublisherService.php';
// Set your client id, service account name, and the path to your private key.
// For more information about obtaining these keys, visit:
// https://developers.google.com/console/help/#service_accounts
const CLIENT_ID = 'asdf.apps.googleusercontent.com';
const SERVICE_ACCOUNT_NAME = 'asdf#developer.gserviceaccount.com';
// Make sure you keep your key.p12 file in a secure location, and isn't
// readable by others.
const KEY_FILE = '../../asdf/privatekey.p12';;
$client = new Google_Client();
$client->setApplicationName({APP_PACKAGE_NAME});
// Set your cached access token. Remember to replace $_SESSION with a
// real database or memcached.
session_start();
if (isset($_SESSION['token'])) {
$client->setAccessToken($_SESSION['token']);
}
// Load the key in PKCS 12 format (you need to download this from the
// Google API Console when the service account was created.
$key = file_get_contents(KEY_FILE);
$client->setAssertionCredentials(new Google_AssertionCredentials(
SERVICE_ACCOUNT_NAME,
array('https://www.googleapis.com/auth/androidpublisher'),
$key)
);
$client->setClientId(CLIENT_ID);
$service = new Google_AndroidPublisherService($client);
$res = $service->inapppurchases->get({APP_PACKAGE_NAME},{APP_PACKAGE_NAME.PRODUCT_ID}, {PURCHASE_TOKEN});
var_dump($res);
The error showed is:
Google_ServiceException: Error calling GET https://www.googleapis.com/androidpublisher
/v1.1/applications/{APP_PACKAGE_NAME}/inapp/{APP_PACKAGE_NAME.PRODUCT_ID}/purchases
/{PURCHASE_TOKEN}: (401) This developer account does not own the application. in
/.../google-api-php-client/src/io/Google_REST.php on line 66 Call Stack: 0.0201
266376 1. {main}() ............
Token is correct, and I'm working with the same account in Google API Console(https://code.google.com/apis/console) and Google Developer Console (https://play.google.com/apps/publish/). I'm only using Service account api, and don't working with Client ID for web applications, and Simple API Access. For security I changed here some code values.
Could somebody help me to know what's wrong on my purchase server verification using Google API please?How I know the owner of my app? Have something to do with Google Apis new project, project domain, project number, project ID, etc...?
I think my problem was because I was trying to use Service Accounts with a Google Apps Gmail own account ( non #gmail.com account ).
I had to delegate domain-wide authority to my service account.
And I had to instantiate a Android Publisher Service as follows: ( only founded in Google Api Drive documentation ).
I added "sub" parameter programmatically in Google_AssertionCredentials like follows:
$auth = new Google_AssertionCredentials(
SERVICE_ACCOUNT_NAME,
'https://www.googleapis.com/auth/androidpublisher',
$key);
$auth->sub = "myown#email.com";
$client->setAssertionCredentials($auth);
The documentation in Google Play Android Developer API is very poor, and Google Support doesn't help, they redirects you to documentation. Google PHP developers even don't know how Service Accounts works.
In spite of having found the answer by myself, Google needs to improve all new Google Play In-app Billing API version 3.

GoogleCredential won't build without GoogleCredential.Builder

In the Google documentation for OAuth2, building a GoogleCredential with an auth token is described here:
Credential and Credential Store
In particular this code snippet is offered:
GoogleCredential credential = new GoogleCredential().setAccessToken(accessToken);
Plus plus = Plus.builder(new NetHttpTransport(), new JacksonFactory())
.setApplicationName("Google-PlusSample/1.0")
.setHttpRequestInitializer(credential)
.build()
When I try to build a GoogleCredential in this way I am tersely informed:
Please use the Builder and call setJsonFactory, setTransport and setClientSecrets
in the message field of an exception. I downloaded the libraries for this last week so I am not sure what is happening. Is the documentation simply outdated, and if so, what method has replaced this one as best practice for building from an existing auth token and refresh token?
Incidentally, the reason using the Builder was not an option was that there WAS no client secret provided by the Google application console; it says that they are no longer provided for Android apps and the like. setClientSecrets(...), therefore, couldn't be called.
I met this problem recently and figured out the solution for my case.
Here is the running conditions: the program is running on Android 4.0 and does not use Google Drive SDK, because it could not allow our program to read the files on Google Drive which are not created by our program. I use the com.google.api.services.drive.* and com.google.api.client.googleapis.auth.oauth2.* Java libraries.
the code arose this problem is like below :
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
httpTransport, jsonFactory, CLIENT_ID, CLIENT_SECRET, Arrays.asList(DriveScopes.DRIVE))
.setAccessType("offline")
.setApprovalPrompt("auto").build();
GoogleTokenResponse response = null;
try {
response = flow.newTokenRequest(authorizationCode).setRedirectUri(REDIRECT_URI).execute();
} catch (IOException e) {
e.printStackTrace();
}
GoogleCredential credential = new GoogleCredential().setFromTokenResponse(response);
but above code worked well if the parameter to setAccessType("online");
and the resolution for this issue depends on what kind of accessType you want.
if you want "onLine" as the accessType, then use setFromTokenResponse()should be ok.
if you want "offline" as the accessType, then you need to use blow code :
GoogleCredential credential = new GoogleCredential.Builder().setTransport(httpTransport)
.setJsonFactory(jsonFactory)
.setClientSecrets(CLIENT_ID, CLIENT_SECRET)
.build()
.setFromTokenResponse(response);
One thing need to be mentioned is that you need to keep the accessType setting to be consistent for GoogleTokenResponse and GoogleAuthorizationCodeFlow creation.
You need to set up your Android app key in Google Dev Console.
Choose your project, select API & Auth, then click Credentials
Create new client id (though it has other client ids)
Select installed app -> android
Fill in your package name and SHA1 correctly
Create new Key (though it has other client keys)
Select Android key
Fill in the SHA1;packageName like this: 45:B5:E4:6F:36:AD:0A:98:94:B4:02:66:2B:12:17:F2:56:26:A0:E0;com.example
Your problem will be automatically solved. Be sure to create client id and key with both your debug keystore and release keystore.
Check the Android quickstart sample in the Google Drive SDK documentation for step-by-step instructions to correctly setup GoogleCredential:
https://developers.google.com/drive/quickstart-android

How do I build a GoogleCredential without a client secret?

I'm creating an Android app that uses a regular Google Drive account as an application-owned account as described, with incredible brevity, here:
Use regular Google accounts as application-owned accounts
Unfortunately all the descriptions of how to do anything on Drive refer to a client secret, and as described here:
Google APIs Console - missing client secret
that doesn't really exist any more for installed apps. I managed to get an OAuth2 token, at incredible pains, by building an actual web page. From this I obtained an access token and a refresh token, as described in the first link. I want to make a GoogleCredential object with these, and as far as I can see this should work like this:
HttpTransport httpTransport = new NetHttpTransport();
JsonFactory jsonFactory = new JacksonFactory();
GoogleCredential credential = new GoogleCredential.Builder()
.setTransport(httpTransport)
.setJsonFactory(jsonFactory)
.setClientSecrets(
new GoogleClientSecrets().setInstalled(
new Details()
.setAuthUri(AUTH_URI)
.setClientId(CLIENT_ID)
//.setClientSecret("but I haven't got one!")
.setRedirectUris(REDIRECT_URIS)
)
)
.build()
.setAccessToken(ACCESS_TOKEN) //defined above
.setRefreshToken(REFRESH_TOKEN); //defined above
Drive.Builder driveBuilder = new Drive.Builder(httpTransport, jsonFactory, null);
driveBuilder.setHttpRequestInitializer(credential);
I've put in the setClientSecret(...) call as commented out, because I don't have a client secret for the installed application.
Basically, I can't make this credential, and every suggestion about making credentials I have seen falls into one of these three categories:
designed for users to log into their own account. Not acceptable; I want one Drive account for all users BUT a regular account, not a service account (the client specified).
based on AccountManager or some other system of authentication. Not acceptable for the same reason.
throws up its hands in horror at the egregiousness of the Google API. Suggests making the request the old-fashioned way.
By the way, without the client secret set, I get a NullPointerException in Preconditions.class. It doesn't tell me a lot about this. I also tried to make a GoogleCredential directly by subclassing it, and it instructed me to use a GoogleCredential.Builder, which is why I find myself here.
What do I do to get round this client secret problem?
The answer seems to be to uncomment the line. The GoogleCredential.Builder succeeds in constructing a credential object as long as something is in the client secret field. But does it actually get the drive? Stick around.
EDIT: no, I'm getting an "invalid_client" error. This is intensely frustrating.
Here's a link to a question that provides its own answer in an edit, using the help of the accepted answer:
How setup Google Drive Credentials within Android App?
In short, the main thing is that you need to get a simple api access key from the developer api console. If you can't find it, then drive api access probably needs to be set.

Categories

Resources