getting Google oauth authorization token from Android- return with invalid_scope/ Unknown error - android

I try to use Google oauth to authenticate users on my android app.
Then I would like to send it to my app server so it can connect at any time with Google calendar.
I tried to use
GoogleAuthUtil.getToken(getApplicationContext(), mAccountName, mScope);
Following this article:
https://developers.google.com/accounts/docs/CrossClientAuth
When I use it with scope
mScope = "oauth2:https://www.googleapis.com/auth/calendar https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile";
I get a token, which is valid for an hour
But when I try to get an authorization code (so I can get a refresh token that is valid for longer time, using
mScope2 ="oauth2:server:client_id:{CLIENT_ID}.apps.googleusercontent.com"+ ":api_scope:https://www.googleapis.com/auth/calendar https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile";
I receive either "invalid_scope" or "Unknown" exceptions.
What am I doing wrong?
EDIT:
OK, After creating a new app on google API console and adding plus.login to the scope I get a code, but for some reason my server can't resolve this token. When tying to resolve server gets an error about the redirection URL.
BTW, When I do the web flow with same parameters it works.

OK, found the solution, I expected Google to have a lot better documentation about working with Google Oauth and Android. A few things you have to know to work with Android and offline token
When you create google Client ID Don't create a service application before you create a web application
Must include https://www.googleapis.com/auth/plus.login in your scope
The weirdest, to resolve the one time authorization code on my server, I had to use the redirection URL from the Android client ID details (which doesn't even look like a url) and not from the Web client details on Google API console.

That scope string is only documented to work when passed to GoogleAuthUtil(), see http://developer.android.com/reference/com/google/android/gms/auth/GoogleAuthUtil.html, on Android. But it would be cool if it worked on iOS too; our infrastructure there is a little behind where we’re at on Android.

I have had the same issue then i realised that my app is not published and is in debug mode, so i had to add test users to the Google project -> Consent Screen, then i was able to fetch the token for the added test user.

You just need to follow the correct steps/format for specifying the scopes. Find them here https://developers.google.com/android/guides/http-auth#SpecifyingScopes

Related

Azure mobileserviceclient login returns authentication error(401)

I currently have a login flow with facebook that is working 100% and I just added Google into the equation. I wrote the code so that my google provider tokens are formatted and cached in the same way as my facebook tokens. My code gets the facebook and google tokens and does the folling: (the following example is for the google login):
USER_GOOGLE_TOKEN = new JsonObject();
USER_GOOGLE_TOKEN.addProperty("access_token", accessToken);
cacheProviderToken(USER_GOOGLE_TOKEN.toString());
setCurrentProvider("google");
Then, in my authentication method in the activity, here is how I mobileserviceclient.login:
MobileServiceAuthenticationProvider provider = null;
if (getCurrentProvider().equals("facebook")){
provider = MobileServiceAuthenticationProvider.Facebook;
} else if (getCurrentProvider().equals("google")) {
provider = MobileServiceAuthenticationProvider.Google;
}
token.addProperty("access_token", googleToken);
ListenableFuture<MobileServiceUser> mLogin = mClient.login(MobileServiceAuthenticationProvider.Google, getProviderToken());
The problem is that Facebook works and Google produces a 401 unauthorized.
The specific error I get (before the future returns failed), is: W/DefaultRequestDirector: `Authentication error: Unable to respond to any of these challenges: {}. Azure logs show that it is a 401 unauthorized.
I am successfully printing the Google-Sign-In token and formatting it in the same way as my facebook tokens before trying to use them. Are my google keys wrong? I regenerated them once already and I tried setting origions to https, I tried different key combos, and I even got rid of my google-services.json(apparently its not needed). I did not use the client key that was generated on this google doc.
Another question here is how does the authentication settings of my Azure Mobile App come into play? I had originally configured my facebook before migrating from a MobileService to MobileApp, and now I do not need to use the "turnkey authentication" feature for it to work. I went ahead and entered my app key and secret for facebook, but it definitely works regardless of whether or not this is enabled. Is this a necessary feature for oauth?
Also, Depending on the token format on Login and the On/Off status of the AUthentication feature, the errror: W/DefaultRequestDirector: Authentication error: Unable to respond to any of these challenges: {}
, will have some text in the curly brackets about the azure endpoint.
Thank you so much if you can help. Such a picky issue here.
The App Service Authentication / Authorization is incompatible with a migrated Mobile Service and must remain off.
To update Authentication settings with a migrated Mobile Service, you set the app settings. For facebook, that's MS_FacebookAppID and MS_FacebookAppSecret. For Google, that's MS_GoogleClientID and MS_GoogleClientSecret.
For reference, check out https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/#authentication

Protecting my Google App Engine API Endpoints

I have been doing a lot of research recently on securing my app engine. Currently, I've been reading through the question below and the links in that question:
How do I restrict Google App Engine Endpoints API access to only my Android applications?
However, it doesn't answer my problem. My question is similar to the question above, restricting access to my endpoint API to only my app. The guy seemed to have got it working when he inputs a correct email into the credentials.
My question is if I can achieve the same results without having to input any credentials. I want it so that only my app can use my endpoint API so to prevent other apps from abusing it and using up my quota. I already got a client id for my android application, and have placed it within my #API annotation. To test if it worked, I made a random value for the client id in the #API notation of another api class. However, my app was still able to use methods from both class. Any help?
-Edit-
From reading from the docs and researching further, the endpoint way of authorizing apps is by authenticating the user and for my API to check if user is null. My question is that in the process of authenticating the user, is Google somehow able to read my app's SHA1 fingerprint and authorize it to its list of client ids? If so, how can I replicate this process in my endpoint so that I check the SHA1 fingerprint of the app making the request and compare it to a set value? I don't understand the mechanics behind the endpoints very well, so correct me if I am understanding this wrong.
If the android app has access, then the user has access. A motivated party has many options for inspecting your protocol, including putting the device behind transparent proxy or simply running the app through a debugger. I do suggest running your app through ProGuard before publishing, as this will make the process [a bit] more difficult.
Ultimately, you'll need to make your appengine API robust against untrusted parties. This is simply the state of the web.
How you can protect your endpoint API is described here: http://android-developers.blogspot.com/2013/01/verifying-back-end-calls-from-android.html
The secret is that you request a token from Google Play using the following scope: audience:server:client_id:9414861317621.apps.googleusercontent.com where 9414861317621.apps.googleusercontent.com is your ClientId.
Google Play will look up the id at your endpoints app and return a Google-signed JSON Web Token if it finds the id. Then you pass that id in with your request. Above article says you should pass it in with the body. I would possibly rather add another parameter for that because otherwise you can't pass your own entities anymore. Anyway, your server backend receives the token, and you ask Google as described if it is authentic, before you process the API request.
If you pass in the token using an extra parameter, you can catch it on the server side by adding HttpServletRequest to your endpoint signature and then using request.getHeader("Yourname") to read it out. Make sure you never add the parameter as a URL parameter as it may be logged somewhere.
public void endpointmethod(
// ... your own parameters here
final HttpServletRequest request
) throws ServiceException, OAuthRequestException {
request.getHeader("YourHeaderName") // read your header here, authenticate it with Google and raise OAuthRequestException if it can't be validated
On the Android side you can pass in your token when you build the endpoint api, like this, so you don't have to do it with each and every request:
Yourapiname.Builder builder = new Yourapiname.Builder(AndroidHttp.newCompatibleTransport(), getJsonFactory(), new HttpRequestInitializer() {
public void initialize(HttpRequest httpRequest) {
httpRequest.setHeader(...);
}})
Hope this helps you make your endpoints API secure. It should.

How do I restrict Google App Engine Endpoints API access to only my Android applications?

I am an Android developer building my first Google App Engine (java) back-end for my apps. I don't want anybody else to access this API other than my app. (I plan to use App engine for verifying InApp purchases in my Android app). My data is not relevant to users so,
I don't want users to be able to access my API even if they are logged in with their Google accounts (on web or Android devices).
I followed the steps mentioned in - "Specifying authorized clients in the API backend"
(https://developers.google.com/appengine/docs/java/endpoints/auth)
like generating client IDs and add them in #Api (clientIds and audiences)
except "Add a User parameter" - since I don't need user authentication.
Then I deployed App engine and I am still able to access the API through API explorer (https://your_app_id.appspot.com/_ah/api/explorer)
(I haven't added API_EXPLORER client ID)
I tested with the APK that was built with the endpoint libs before adding client IDs and can still access the API.
Is adding a "User parameter" to all endpoint APIs a must? to achieve my purpose (restrict API to only my Android apps).
Can I pass null as userAccount name from Android client and ignore user parameter value on server (since it will be null)? Will this ensure that the API is accessible only from my android apps (since the client ID is generated for my package name and SHA1 of the APK?)
Should I use something like a service account for this purpose?
The documentation says for Android, both Android and Web client IDs must be added and audience must be the same as web client ID. Does this open access to any other web client? can I skip mentioning web client ID and still achieve my purpose?
Appreciate your time and help.
...... updating with my further investigation ...
I did the following:
Added User parameter to APIs on backend - but did not check for null value. API can still be accessed without passing any credentials (from Android debug APK and API explorer)
Then, I tried
mCredential = GoogleAccountCredential.usingAudience(this, "server:client_id:" + WEB_CLIENT_ID);
mCredential.setSelectedAccountName(null);
and passed this credential to API builder (as suggested in some other posts)
Caused FATAL EXCEPTION. So, we can't pass null account name.
I could call the API using API explorer without OAuth. But when I enabled OAuth, it gave error saying this client ID is not allowed! ( I haven't yet added com.google.api.server.spi.Constant.API_EXPLORER_CLIENT_ID in client_ids{})
Then I added code to throw OAuthRequestException on the backend if the user is null. This resulted in API explorer getting errors without OAuth. It works with OAuth enabled after adding API_EXPLORER_CLIENT_ID to client_ids)
Added code to pass valid user account name(email) from my Android app. Then, I am able to access API only with my release APK. Even the debug APK gets exceptions! - which is what I expected..So, I assume no other Android apps will be able to access this API.
So, not checking for null user on back-end API is a bad idea (as suggested in other posts). It is as good as not mentioning any client_ids and not having User param.
Only question I have at this moment is: If some one can figure out the WEB_CLIENT_ID from the APK, will they be able to use it to build a web client to access my API (I haven't mentioned client secret anywhere in the code. So I am thinking this is not possible).
I did search Google groups and Stackoverflow, but still it is not clear.
(Authenticate my “app” to Google cloud endpoints not a “user”)
Authenticate my "app" to Google Cloud Endpoints not a "user"
(How do I protect my API that was built using Google Cloud Endpoints?)
How do I protect my API that was built using Google Cloud Endpoints?
(Restrict access to google cloud endpoints to Android app)
Restrict access to google cloud endpoints to Android app
I had a similar issue, not between Android and App Engine, but between a separate server and App Engine. The way I handled it was to add a signature hash field as a parameter to each API call. If the request had an improper signature, it would be denied.
For example, suppose your API end-point is example.com/api/do_thing?param1=foo. I would hash the entire url, along with a secret key, and then append the result of the hash to the request: example.com/api/do_thing?param1=foo&hash=[some long hex value].
Then, on the server side, I would first remove the hash from the url request, then run the hash on everything that was remaining. Finally, you check whether the calculated hash matches the one that was sent with the request and if they don't, you can deny the request.
It is very important however that your secret key remain secret. You have to be careful with this on Android because someone could attempt to decompile your APK.
Facing the same problem than you ! Authenticate Android End point without Google User Account is just impossible !
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 !
Google provides ways to do this for Android, web and iOS
The steps involves:
Specifying a client Id for apps you want to allow to make requests to your API
Adding a User parameter to all exposed methods to be protected by authorization.
Generating the client library again for any Android clients
Redeploying your backend API.
Updating the regenerated jar file to your Android project for your Android client.
These steps are laid out in clear detail on Google's Using Auth with Endpoints and also on this blog
Facing the same problem, here are the result of my research :
Added Android cliend id with SHA1 fingerprint in Google console
Use of it in the API annotation
BUT :
If i dont add user parameter to methods : the check about android app client id does not work
If I add the USER parameter but do not ask the user to choose its google account to create the credential ... also it does not work ...
Conclusion : It seems to be mandatory to connect a user account for the check about the app client id to be executed ... I really do not understand why because no link exist between the 2 processes
Access this site
Choose your project, go to credentials section
Create a new api key
Create a new android key
Click on "Edit allowed android applications" and enter your SHA1 key; your android package name
Let me know if this solves the issues.

Google+ login redirect_uri_mismatch error

I'm trying to implement one-time code sign in flow in my system.
Application contains of two parts:
1)Android application which requests Google+ for one-time authorization code
2)Rails server that receives one-time code from android application in request header and tries to exchange code for access_token and id_token from Google+
The problem is that everything works well if I get one-time code using JavaScript sign-in button in browser, but doesn't work when one-time code is obtained by Android application and then sent to my server.
I'm getting always
"error" : "redirect_uri_mismatch"
My server settings are following:
{ "web":
{ "client_id": "MY_REGISTERED_WEB_APP_CLIENT_ID",
"client_secret": "MY_CLIENT_SECRET",
"redirect_uris": ["postmessage"],
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://accounts.google.com/o/oauth2/token"
}
}
Now, how I'm requesting one-time code from Android app:
I use the same MY_REGISTERED_WEB_APP_CLIENT_ID as on my server for requesting one-time code. I don't know, maybe I have to use on Android another client id, that corresponds to my Android application? But all found documentation and articles are pointing to registered
Web app client_id.
Or maybe my rails server should be configured not for web, but for installed type of registered in Google Console apps?
Now regarding redirect_uris.
I've tried to set several redirect_uris in Google Console:
empty field
http://localhost:5000
https://localhost:5000
http://my.deployment.url/auth2callback
Web origins in Google console are set to
- http://my.deployment.url
- http://localhost:5000
Can't figure out what I'm doing wrong.
Actually I don't understand why I need to set this redirect_uris values, since I don't want to have callbacks from Google, I just want to get access_token and use it for accessing Google+.
This is happening because the redirect_uri your android app is using to create the initial login flow is different from the redirect_uri the server is using when it tries to excange the code for an access_token. The redirect_uri the user returns to and the redirect_uri used in the token exchange must match.
The proper redirect_uri in this case is "urn:ietf:wg:oauth:2.0:oob"

What is the proper way to validate google granted OAuth tokens in a node.js server?

I'm trying to authenticate a mobile application for the Android platform to a custom node.js server api. I would like to use Google OAuth2 tokens for this rather than roll my own authentication, since Android devices with Google Play installed make this available to app developers. I'm using the GoogleAuthUtil.getToken call from the Google Play Services library, documented here. I'm trying to follow the advice outlinedin this android developers blogpost
The getToken method is returning in my case a long 857 byte string. If I try to pass this token to Google's TokenInfo endpoint, it returns:
{'error': 'invalid_token', 'error_description': 'Invalid Value'}
What am I doing wrong here? In the 'scope' of the getToken call, I am sending:
audience:server:client_id:**i_put_my_clientid_here**. I have a clientid generated for "installed applications". Using this client id, the call to getToken doesn't work at all. When I generated a client id for a "service account", the call succeeds, but I get an 857 byte token that fails when passed to the TokenInfo endpoint as described above.
EDIT:
I also created a client id for "web applications", as it appears that is the right client id to use when calling getToken. But the behavior is the same, I get back an 857 byte token that doesn't validate when calling Google's endpoint.
How can I properly get a valid auth token using Google Play services on Android? Once I have the right token, what is the right node.js library to validate it server side? Can I use passport-google-oauth ?
Hm, this is really a comment rather than an answer, but I can’t put newlines in those:
it has to be the web-side Clent ID that goes in the put_my_clientid_here spot
if GoogleAuthUtil.getToken() gives you a String withou throwing an Exception, it really ought to be valid. When you hit tokeninfo, did you use ...tokeninfo?id_token=<857-byte-value-here>
if you’re a rubyist, grab the google-id-token gem and see if it can validate your 857-byte token.
If you just want to read the contents of the data returned by GoogleAuthUtil.getToken then the process is very simple. The returned data is simply a JWT. So all you'd have to do is split the data by the . character, and then base64 (url) decode each piece.
It gets slightly more complicated if you want you want to verify the message's authenticity. Simply use your favorite crypto library to do the verification. The 3rd component of the JWT is the signature of the data and the Google certs are publicly available; that's all you need to verify the message.
For a week I have been looking into how to validate GoogleAuthUtil tokens received in Android Client application at Node.js server using passport.js
Finally I came across passport-google-token passport strategy which perfectly performs the task.
https://www.npmjs.com/package/passport-google-token
More details are present in the above link.
The official node SDK lets you do that now.
Here's the link: https://github.com/google/google-auth-library-nodejs/blob/master/lib/auth/oauth2client.js#L384
I'm not too familiar with the details of how Android works with respect to handing a token from the device to the server. My general impression, however, is that you don't go through the typical web-based OAuth dance. Instead, you directly call the "user info" endpoint, which will return the info corresponding to the user who holds the token, or reject the request if the token is invalid. There's some discussion on this related question:
validating Android's authToken on third party server
In effect, the token becomes a secret that is shared between both the device and your server, so its important to protect it.
There are a couple strategies for Facebook and Twitter that were developed to do similar things using tokens from iOS devices:
https://github.com/drudge/passport-twitter-token
https://github.com/drudge/passport-facebook-token
You can take some inspiration from them and tweak it to talk to Google's endpoints. Let me know how this turns out. I'd love to see a similar "passport-google-token" strategy, so if you implement one, let me know and I'll link to it!

Categories

Resources