What exactly is the client secret for Google OAuth2? - android

In Google's OIDC guide, section Exchange code for access token and ID token states that I must provide a client_secret.
If I select the relevant client ID from the API console, I do indeed get a JSON file named client_secret_.... However, none of the fields of the JSON object are named secret or anything similar. (The fields are named client_id, project_id, auth_uri, token_uri, auth_provider_x509_cert_url, and redirect_uris.)
So, where do I get this client_secret?

I think the secrete used to be in the file but alternatively you can also find it by looking at the page were you downloaded your json file and you can also click the button to reset said secret.
I would make sure that the credentials are looking at are under OAuth 2.0 client IDs and not Service account keys or API keys only the first one needs a secret I believe.
Update from comments: Creating Oauth Client Id for android will not give you a secret because its not needed in android application should should probably be following Add google sign-in to your android App

Related

Google Sign-in in Android with django-rest-auth

I've been trying to add Google Sign-In in Android but have a couple of doubts.
From the Android documentation Integrate google sign in android
In the server side authentication part Client Id is required which is OAuth 2.0 web application client ID for your backend server.
From android's documentation:
Get your backend server's OAuth 2.0 client ID
If your app authenticates with a backend server or accesses Google APIs from your backend server, you must get the OAuth 2.0 client ID that was created for your server. To find the OAuth 2.0 client ID
From my understanding the flow would be:
Android app will get the auth code from google which will be passed to the backend.
The backend will get the access token with the auth code from the android app and the client secret.
With the acess token we get the user's information and the access token is saved in the database.
My doubts are:
I read somewhere on StackOverflow that we need to create two OAuth client one for Android and one for Web Application. Is this True?
Django Rest Auth Login View need to have one redirect_url defined but I don't understand what would be the redirect_uri in case of Android device or we need to pass this URL while getting the auth code from Google.
On OAuth Playground I put my backend's client id and client secret and got the auth code and when I passed this auth code to my login view I was getting the redirect_uri_mismatch but If I put redirect_url = 'developer.google.com' It works, I guess the auth code contains host information from where it is generated that's why this should be the same as redirect_url in my rest-auth view but then for android what it should be?
Here is my Google Login View.
class GoogleLogin(SocialLoginView):
adapter_class = GoogleOAuth2Adapter
client_class = OAuth2Client
callback_url = 'localhost:8000' # What this should be?
Please ask for more information If I forgot to put any.
I am using this
django-rest-auth
Some helpful link -
https://github.com/Tivix/django-rest-auth/issues/262#issuecomment-256562095 # It says callback URL could be a fake one but I get redirect_uri_mismatch
So Finally, I figured it out, Answering my own question so someone might find this helpful.
Yes, you need two client id one for your Android device and one for your web application.
Just add http://localhost:8000/accounts/google/login/callback/ as callback_url in the GoogleLoginView and put the same in your Google developer console.
I don't know exactly if the auth code generated by the Android contains any host information or not but it seems as long as the callback URL you added in the login view class and in google developer console is the same it will work.
Your Google sign in view should look like this.
class GoogleLogin(SocialLoginView):
authentication_classes = (JSONWebTokenAuthentication,)
adapter_class = GoogleOAuth2Adapter
callback_url = 'http://localhost:8000/accounts/google/login/callback/'
client_class = OAuth2Client
Note: You only need callback_url and client_class in case where you are passing the auth code to this view but if in you are passing the access_token then callback_url and client_class is not necessary.

Misunderstanding Oauth2 and twitter4j

There is somthing that i can't understood. I'm trying to writte a simple app in android to post twitt's into my account. I registered my app in dev.twitter. There i got an api(consumer) key/secret, and access token/access secret pairs. BUT, as in the example, i must use setOauthConsumer(cons key, cons secret) then, after that in the app I must use get getOAuthAccessToken to get oauth access token. But i'm alredy have this(!), so i can use acces token and secret directly, or what?
p. s. i know twitter4j.org examples, and i can use other resources, but i cant find the answer, so i'm posting here
i must use setOauthConsumer(cons key, cons secret) then, after that in
the app I must use get getOAuthAccessToken to get oauth access token.
But i'm alredy have this(!), so i can use acces token and secret
directly, or what?
We need the following 4 values for every request to twitter API:
Consumer key
Consumer Secret
Access Token
Access Token Secret
You already have the following values:
Consumer key
Consumer Secret
Access Token & Access Token Secret are fetched in following two ways:
Case 1: Configuration required for app-only auth, to fetch the twitter feeds even
without Logging in to twitter account.
As you have not logged in, the twitter4j gives the OAuth2Token (access token and token secret) using getOAuth2Token();
Then you use these values in your configuration of Twitter instance. No need to store these values. You can get them using getOAuth2Token() for every request.
Case 2: When you login using your credentials.
In this case, the request is sent to Twitter API to get access token and access token secret (values are generated at the time of registering your application on Twitter).
Once you get these values, store it in SharedPrefernces and use them in subsequent requests. No need to request them again and again.
I hope this helps you.

Implement OAuth2 with resource owner password credentials on Android

I need to make calls to services which are secured by OAuth2 resource owner password credentials. I tried all the libraries on oauth.net/code, but with no success. All of them seem not to provide this kind of authentication, but seem to be great with 3 legged authentication.
My user should login with username and password, but I do not want to store username and password. I want to get an access token and refresh this token from time to time.
My network communication is currently based on spring 4 android and the resttemplate you can find there.
Any suggestions, which library I could use? I think this is a common problem.
I couldn't find anything either, so I've put together a library myself, and I am releasing it to the public.
Usage:
import org.sdf.danielsz.OAuth2Client;
import org.sdf.danielsz.Token;
OAuth2Client client = new OAuth2Client(username, password, app-id, app-secret, site);
Token token = client.getAccessToken();
token.getResource(client, token, "/path/to/resource?name=value");
With this grant type, the client application doesn't need to store the username/password of the user. Those credentials are asked once and exchanged for an access token. This token can then be used to access protected resources.
To check if a token has expired:
token.isExpired();
To manually refresh a token:
Token newToken = token.refresh(client);
A more involved example can be found in the README on github.
Check out this url : https://temboo.com/library/Library/Fitbit/OAuth/ and https://temboo.com/library/Library/Fitbit/OAuth/InitializeOAuth/
In order to run java code to generate OAuth url, you will need temboo.jar file which you can download by clicking on java icon on right hand side link.
cheers.

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.

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