Save and restore token for Google Drive android - android

I tried this example from google to authenticate with Google Drive and it can work. But the problem is that I don't know how to restore the previous success login from users. For example, when users login success, the next time they go to my app, they don't need to login again. I look in the GoogleAccountCredential class, it only have getToken method and don't have 'setToken` so I don't know how to do. And the document doesn't say anything about it. Here is my try:
credential = GoogleAccountCredential.usingOAuth2(context, DriveScopes.DRIVE);
// try to add login account into credential
String accountName = SharePreferenceHelper.getDriveAccount(context);
if (accountName != null) {
credential.setSelectedAccountName(accountName);
service = getDriveService(credential);
}
// try to get token again
try {
String token = credential.getToken();
Log.d(TAG,"token = " + token);
} catch (UserRecoverableAuthException ex) {
startActivityForResult(ex.getIntent(), requestCode);
}
Does anybody know how to do it?

You need not do this manually. It is already taken care of by GoogleAccountCredential
This call
credential = GoogleAccountCredential.usingOAuth2(this, scopes);
will automatically restore the saved token if its previously saved.
You can check out a sample source code of my app here:
https://github.com/madhur/GAnalytics/blob/develop/src/in/co/madhur/ganalyticsdashclock/MainActivity.java
the difference it uses Google Analytics instead of Google Drive.

Related

How multiple users use google cloud speech at the same time

I'm building an app that uses Google Cloud Speech.
I have a Google Service account key in my app, and I use it to call the API.
It works well when used by one user, but does not work when multiple users use it at the same time.
For example, only one user is available or all are unavailable.
The rights of the service account key are project owner.
I think it's a service account key issue...
How do I fix it?
private class AccessTokenTask extends AsyncTask<Void, Void, AccessToken> {
#Override
protected AccessToken doInBackground(Void... voids) {
final SharedPreferences prefs = mContext.getSharedPreferences(PREFS, Context.MODE_PRIVATE);
String tokenValue = prefs.getString(PREF_ACCESS_TOKEN_VALUE, null);
long expirationTime = prefs.getLong(PREF_ACCESS_TOKEN_EXPIRATION_TIME, -1);
// Check if the current token is still valid for a while
if (tokenValue != null && expirationTime > 0) {
if (expirationTime > System.currentTimeMillis() + ACCESS_TOKEN_EXPIRATION_TOLERANCE) {
return new AccessToken(tokenValue, new Date(expirationTime));
}
}
final InputStream stream = mContext.getResources().openRawResource(R.raw.credential);
try {
final GoogleCredentials credentials = GoogleCredentials.fromStream(stream).createScoped(SCOPE);
final AccessToken token = credentials.refreshAccessToken();
prefs.edit()
.putString(PREF_ACCESS_TOKEN_VALUE, token.getTokenValue())
.putLong(PREF_ACCESS_TOKEN_EXPIRATION_TIME, token.getExpirationTime().getTime())
.apply();
return token;
} catch (IOException e) {
Log.e(TAG, "Failed to obtain access token.", e);
}
return null;
}
#Override
protected void onPostExecute(AccessToken accessToken) {
mAccessTokenTask = null;
final ManagedChannel channel = new OkHttpChannelProvider()
.builderForAddress(GOOGLE_API_HOSTNAME, GOOGLE_API_PORT)
.nameResolverFactory(new DnsNameResolverProvider())
.intercept(new GoogleCredentialsInterceptor(new GoogleCredentials(accessToken)
.createScoped(SCOPE)))
.build();
mApi = SpeechGrpc.newStub(channel);
// Schedule access token refresh before it expires
if (mHandler != null) {
mHandler.postDelayed(mFetchAccessTokenRunnable,
Math.max(accessToken.getExpirationTime().getTime() - System.currentTimeMillis() - ACCESS_TOKEN_FETCH_MARGIN, ACCESS_TOKEN_EXPIRATION_TOLERANCE));
}
}
}
This code is the code that calls 'credential.json' file on Android and gets 'Access token'.
The server for this app is python and communicates via http.
https://github.com/GoogleCloudPlatform/android-docs-samples/tree/master/speech/Speech
The description in the link above tells you to delegate the authentication to the server.
I want to write that part with python code.
What should I do?
In the link you provided in the description, they suggest you to read first the basic authentication concepts document. In your case, use a service account for the Android application.
I understand that you have already been able to provide end user credentials to a Google Cloud Platform API, as for example Cloud Speech API.
If you want to authenticate multiple users to your application you should use instead Firebase authentication. The link contains a brief explanation and a tutorial.
There are several Python client libraries for GCP that you can use, depending on what operations do you want to perform on the server. And regarding Python authentication on the server side, this documentation shows how the authentication for Google Cloud Storage works (have this example in mind as a reference).

How to access Google plus domains api using GoogleApiClient object?

The documentation here says the following
Warning: The Google+ Sign-In button and the plus.login scope used by
Google+ Sign-In, are not currently supported for use with the Google+
Domains API. Requests that are made to the Google+ Domains API using
an authentication token granted for the
https://www.googleapis.com/auth/plus.login scope, or generated by the
Google+ Sign-In button, will fail.
So if we need to access Google Plus Domains API how do we do it using GoogleApiClient object in android?
I want a list of a user's circles for which I need to use the Domains API.
Consider using GoogleAuthUtil for Google Plus Domain authentication.
And most importantly: "Domain API will work only with domain email id" (which is not the gmail id).
String scopes = "oauth2:" + "https://www.googleapis.com/auth/plus.me " +
"https://www.googleapis.com/auth/plus.circles.read";
String accountName = "domain_email_id_used_for_login";//fetch from AccountManager or ask the user to enter
String token = "";
try {
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(LoginActivity.this);
token = sharedPref.getString("token", "");
if (!token.equals("")) {
GoogleAuthUtil.clearToken(LoginActivity.this, token);
}
token = GoogleAuthUtil.getToken(LoginActivity.this,
accountName, scopes);
GoogleCredential googleCredential = new GoogleCredential().setAccessToken(token);
PlusDomains plusDomains = new PlusDomains.Builder(new NetHttpTransport(), new JacksonFactory(), googleCredential).setApplicationName("GPlusLab").build();
plusDomains.people().get("me").execute();
return token;
} catch (UserRecoverableAuthException e) {
startActivityForResult(e.getIntent(), REQUEST_AUTHORIZATION);
} catch (GoogleAuthException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
github link to complete example.

How to Access Google Plus API from Different Activity

I am having trouble with the Google Plus Android API. I have a new activity, and I want to access the User's name and other details. How do I do that? I understand how to do it in the Sign In activity, but how do I access user information in this new activity?
Thanks in advance.
From the documentation on signing in:
When the user has successfully signed in, your onConnected handler will be called. At this point, you are able to retrieve the user’s account name or make authenticated requests.
It looks like there's a specific method for retrieving the signed-in user's information once sign in has been completed: Plus.PeopleApi.getCurrentPerson
Use the Plus.PeopleApi.getCurrentPerson method to request profile information the currently signed in user.
You can call the getCurrentPerson method after the GoogleApiClient is connected:
#Override
public void onConnected() {
...
if (Plus.PeopleApi.getCurrentPerson(mGoogleApiClient) != null) {
Person currentPerson = Plus.PeopleApi.getCurrentPerson(mGoogleApiClient);
String personName = currentPerson.getDisplayName();
String personPhoto = currentPerson.getImage();
String personGooglePlusProfile = currentPerson.getUrl();
}
}

Restrict access to my API Endpoint to Android App

I want to restrict my API endpoints access only to my android app, but without google_account/password.
I've the choice of those methods : https://developers.google.com/accounts/docs/OAuth2
For test, I succeeded to authenticate my android app to my API with this method: https://cloud.google.com/appengine/docs/python/endpoints/consume_android
==> This method allow you to authenticate your app with combo:
Login/password (Google account)
SHA1 and package name of your android APP
So if someone get my code (Decompiling apk) and modify my android code, they can't access to my API because SHA1 fingerprint of my app will change. (I tested it, and it works =) )
This method works fine, but I don't want Google login/password for authentication..
So I tried this method: https://developers.google.com/accounts/docs/OAuth2ServiceAccount
I successfully authenticate my android app, BUT, if my android code is modified by someone else(So the SHA1 changed), my android app can still connect to my API !! So if someone get my package and decompile it, he'll changed freely code and successfully access to my API..
Here is my API Code:
#ApiMethod( name = "ListCampagnes", httpMethod = ApiMethod.HttpMethod.GET, path="list", clientIds = {CONSTANTES.ANDROID_CLIENT_ID, CONSTANTES.WEB_CLIENT_ID, CONSTANTES.SERVICE_CLIENT_ID, com.google.api.server.spi.Constant.API_EXPLORER_CLIENT_ID}, audiences = {CONSTANTES.ANDROID_AUDIENCE})
public Collection<Campagne> getCampagnes(#Named("NumPortable")String NumPortable, User user) throws UnauthorizedException {
if (user == null) throw new UnauthorizedException("User is Not Valid");
return CampagneCRUD.getInstance().findCampagne(NumPortable);
}
Here is my android code:
GoogleCredential credentialToAppengine;
try {
String p12Password = "notasecret";
KeyStore keystore = KeyStore.getInstance("PKCS12");
InputStream keyFileStream = getAssets().open("59ce5a08e110.p12");
keystore.load(keyFileStream, p12Password.toCharArray());
PrivateKey key = (PrivateKey)keystore.getKey("privatekey", p12Password.toCharArray());
credentialToAppengine = new GoogleCredential.Builder().setTransport(AndroidHttp.newCompatibleTransport()).setJsonFactory(new JacksonFactory()).setServiceAccountId("301991144702-3v9ikfp4lsmokee1utkucj35847eddvg#developer.gserviceaccount.com").setServiceAccountPrivateKey(key).setServiceAccountScopes(Collections.singleton("https://www.googleapis.com/auth/userinfo.email")).build();
} catch (GeneralSecurityException e) {
e.printStackTrace();
return null;
} catch (Exception e) {
e.printStackTrace();
return null;
}
Do I try an other method for authenticate my android App ? Or did I missing something in my API code ?
Thanks a looot in advance,
Authenticate Android End point without Google User Account is just impossible ! I tried every ways but still doesn't works !
So here is my way to resolv this problem, without any user interaction (Maybe not the right but that works, and you've got strong authentication (SHA1 + Google Account)):
HERE IS MY ANDROID CODE
Get and Build Valid Credential
//Get all accounts from my Android Phone
String validGoogleAccount = null;
Pattern emailPattern = Patterns.EMAIL_ADDRESS; // API level 8+
Account[] accounts = AccountManager.get(context).getAccounts();
for (Account account : accounts) {
if (emailPattern.matcher(account.name).matches()) {
//Just store mail if countain gmail.com
if (account.name.toString().contains("gmail.com")&&account.type.toString().contains("com.google")){
validGoogleAccount=account.name.toString();
}
}
}
//Build Credential with valid google account
GoogleAccountCredential credential = GoogleAccountCredential.usingAudience(this,"server:client_id:301991144702-5qkqclsogd0b4fnkhrja7hppshrvp4kh.apps.googleusercontent.com");
credential.setSelectedAccountName(validGoogleAccount);
Use this credential for secure calls
Campagneendpoint.Builder endpointBuilder = new Campagneendpoint.Builder(AndroidHttp.newCompatibleTransport(), new JacksonFactory(), credential);
HERE IS MY API BACKEND CODE:
API Annotation
#Api(
scopes=CONSTANTES.EMAIL_SCOPE,
clientIds = {CONSTANTES.ANDROID_CLIENT_ID,
CONSTANTES.WEB_CLIENT_ID,
com.google.api.server.spi.Constant.API_EXPLORER_CLIENT_ID},
audiences = {CONSTANTES.ANDROID_AUDIENCE},
name = "campagneendpoint",
version = "v1"
)
Method code:
public Collection<Campagne> getCampagnes(#Named("NumPortable")String NumPortable, User user) throws UnauthorizedException {
if (user == null) throw new UnauthorizedException("User is Not Valid");
return CampagneCRUD.getInstance().findCampagne(NumPortable);
}
For the moment, it only works on Android (I don't know how we gonna do on IOS..)..
Hope It will help you !

GoogleAccountCredential + Google Play Services + Refresh Token - how this works together?

I have published a pretty successful app about 2 weeks ago. But starting from yesterday, users keep sending me emails about Drive not being accessable anymore. After a quick debug, I found that requests to the Drive API now return "403 Forbidden" -> "Access Not Configured".
I think this might be an issue with the refresh token not being handled properly.
I'm using the following code (from the Android Drive SDK samples):
mCredentials = GoogleAccountCredential.usingOAuth2(this, DriveScopes.DRIVE);
String accountName = PreferenceManager.getDefaultSharedPreferences(this).getString(PREF_DRIVE_NAME, null);
if (accountName != null) {
setupDrive(accountName);
} else {
startActivityForResult(mCredentials.newChooseAccountIntent(), 0);
}
setupDrive(...) looks like this:
mCredentials.setSelectedAccountName(accountName);
try {
mCredentials.getToken();
} catch (Exception e) {
Log.w(AbstractDriveActivity.class.getSimpleName(), "Error getting auth token", e);
if (e instanceof UserRecoverableAuthException) {
Intent intent = ((UserRecoverableAuthException) e).getIntent();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK).addFlags(Intent.FLAG_FROM_BACKGROUND);
startActivity(intent);
} else {
Toast.makeText(AbstractDriveActivity.this, getString(R.string.toast_drive_setup_error),
Toast.LENGTH_SHORT).show();
finish();
}
}
drive = new Drive.Builder(AndroidHttp.newCompatibleTransport(), new GsonFactory(),
mCredentials).build();
Any idea what might be wrong here?
From my understanding, GoogleAccountCredential uses the Google Play Services to manage the OAuth2 flow and all you need to provide is the username. Am I wrong? Did I miss something?
Btw: After clearing app data, selecting the Google Account again, everything works fine. That's why I think that it has something to do with the refresh token.
Goddchen
No guaranty, but the problem might come from here:
mCredentials = GoogleAccountCredential.usingOAuth2(this, DriveScopes.DRIVE);
This method appears as deprecated to me. You should upgrade your SDK and environment and change it to:
mCredentials = GoogleAccountCredential.usingOAuth2(this, Arrays.asList(DriveScopes.DRIVE));

Categories

Resources