I'm trying to develop an application that makes use of some basic Google+ Apis. The app request a token from Google that then upload on my server and my server check for its validation with Google. What I don't understand (I'm a bit confused) is what's the difference between Client ID for Web application and Client ID for Android application in Google Developers Console. I've tried both of them on the Android app and both work (successfully obtained a token). Obviously, when using the Web Client ID, my SCOPE that I pass using GoogleAuthUtil.getToken() is different from the one using Android Client ID. So, what's the difference between them? I think that I should go for the Android Client ID, but I'd like to know the really differences.
On client side I use:
final String token = GoogleAuthUtil.getToken(mContext, userEmail, G_PLUS_SCOPE);
Where G_PLUS_SCOPE = oauth2:https://www.googleapis.com/auth/plus.me
On server side, I check with Google with this code:
GoogleIdToken token = GoogleIdToken.parse(mJFactory, getRequest().getAuthToken());
if (mVerifier.verify(token)) {
GoogleIdToken.Payload tempPayload = token.getPayload();
if (!tempPayload.getAudience().equals(mAudience)) {
problem = "Audience mismatch";
errorMessage = new ErrorMessage(ErrorCodes.AUDIENCE_MISMATCH,problem,null);
mResponse = new ErrorResponse( errorMessage);
}
else if (!mClientIDs.contains(tempPayload.getAuthorizedParty())) {
problem = "Client ID mismatch";
errorMessage = new ErrorMessage(ErrorCodes.CLIENT_ID_MISMATCH,problem,null);
mResponse = new ErrorResponse(errorMessage);
}
I also don't understand what's the exact value of mAudience. Do I need to put the Client ID as mAudience? And, is the mClientIDs the array containing all the key (Including the Android client ID key)?
Thanks for your help
EDIT: Following http://android-developers.blogspot.it/2013/01/verifying-back-end-calls-from-android.html I've read that the Audience is the Client ID for Web Application and the mIds are all the ID for installed application (1 for me because I've only Android). But I'm not sure if this is the right way of thinking it for every case.
I don't have answer to your question but I found this blog which can help you out:
http://www.androidhive.info/2014/02/android-login-with-google-plus-account-1/
I hope this helps you.
Technically the audience is the client ID which the ID token is intended to authenticate the user to, where the authorized party is the client ID which the ID token was issued to:
http://openid.net/specs/openid-connect-core-1_0.html#IDToken
You should verify both when both are provided. When requesting an ID Token from your Android app, you should use the Client ID of your server to make the request. Your server should then verify that it is the audience for the token when it receives it from your Android client.
Related
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.
As the title says, I'm trying to use the Google Sign-In API with a Spring Boot backend server, as described here.
Just to describe the context, the Spring backend is basically a resource+authentication server, that is currently providing Oauth2 authentication to a second spring boot application containing the frontend website, via Google SSO or simple form login (similar to what's described here).
My original idea was to mimic the #EnableOauth2Sso annotation by simply providing an access token to the android app and attach it to every request as "Bearer ".
Using the user credentials for this was pretty straightforward: I simply make a request to the server at "/oauth/token", using those credentials inserted by the user as authentication and I correctly receive the access token.
Now, I have absolutely no idea on how to build a similar procedure with the Google API in Android. The tutorial page I linked before describes how to get a token ID and how the server should validate it, but after that I don't know what to do.
So far I've managed to add a filter to the security chain that simply checks the token like this:
private Authentication attemptOpenIDAuthentication(#NonNull String tokenString){
String clientId = authServices.getClientId();
GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(transport, factory)
.setAudience(Arrays.asList(clientId, androidClient))
.build();
try {
GoogleIdToken token = verifier.verify(tokenString);
if (token != null) {
return authServices.loadAuthentication(token.getPayload());
} else {
throw new InvalidTokenException("ID token is null");
}
} catch (GeneralSecurityException | IOException e) {
throw new BadCredentialsException("Could not validate ID token");
}
}
This manages indeed to create an Authentication object, but how can I generate an access token after the authentication filtering?
To recap, so far I've got:
The Android app successfully retrieves the Google token ID and sends it to the server
The server sucessfully intercepts the request and validates the token
I'm basically missing the third point where I return a proper access token to the Android client.
Here you are a simple scheme to better understand the situation:
Is there any other way to validate the token and get an access token from the server, or should I completely change the authentication procedure on Android?
As far as I can tell: Yes, you need an access token from the server. If I understand this correctly, a webapp is already authenticated via Oauth on your backend, so the procedure is similar here: Load the user with the google-ID and generate a token. In my application I used a JWT which is valid for 30 days. If the token expires, the Google authentication in the app is usually still valid, so the token can be renewed using the Google ID. With Oauth you can also send a refresh-token directly.
It is important that the app always checks the Google authentication first and only in a second step that of the backend.
For the Authentication process on the backend u may need to manually implement a dedicated securityConfiguration for this. Have a look at the jhipster project, they implemented a custom jwt-authentication which may give you an idea how it works.
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?
I've been having problems implementing Google Play Services login on my android app and passing the authorisation code to my backend server, so the server will exchange the code for access token and refresh token.
First let me write a few lines what has already been tried/read:
on code.google.com/apis/console I've created a new project, with two clients (WEB client and Android installed client)
read articles on https://developers.google.com/+/mobile/android/sign-in#cross-platform_single_sign_on and http://android-developers.blogspot.com/2013/01/verifying-back-end-calls-from-android.html
Next I wrote simple android app (based on Google Play Services sample auth app) and a simple python code using gdata (using web service client_id and secret).
On android app I first used four scopes delimited with space and got a token. If I use this token in my python code I always get {'error_message': 'unauthorized_client'}.
Then I tried to change the scope to this values and always got invalid scope error.
oauth2:server:client_id:server-client-id:api_scope:scope1 scope2
audience:server:client_id:server-client-id:api_scope:scope1 scope2
oauth2:audience:server:client_id:server-client-id:api_scope:scope1 scope2
For server-client-id I used the client_id of web server client, android client, other client
Please can anyone help me with this problem.
Thanx
Here is the code for python backend
import gdata
import gdata.gauth
CLIENT_ID = 'client_id'
CLIENT_SECRET = 'secret_id'
SCOPES = ["https://www.google.com/m8/feeds", "https://mail.google.com", "https://www.googleapis.com/auth/userinfo.profile", "https://www.googleapis.com/auth/userinfo.email"]
USER_AGENT = 'my-app'
token = gdata.gauth.OAuth2Token(client_id=CLIENT_ID, client_secret=CLIENT_SECRET, scope=' '.join(SCOPES), user_agent=USER_AGENT)
print "token ", token
print token.generate_authorize_url(redirect_url='urn:ietf:wg:oauth:2.0:oob')
try:
print token.get_access_token("token")
except Exception, e:
print e
print e.__dict__
You are retrieving an authorization code, not an access token. These are two different things.
Authorization codes can be used in your server side to get an access token. They are not access tokens and cannot be used as such.
Is it possible to authenticate the user on server side using auth token retrieved by Android applicaton from Facebook?
In other words Android application uses SSO and obtain auth token. Then sends this token to backend application deployed on Google App Engine. Then backend application verifies the user against Facebook using the token.
I guess it's not feasible because retrieved token can be used only by Android application, but who knows? Maybe it may be reused somehow?
The Token you get from Android API can be sent to your server, who can check the validity of the token by querying the graph ( using /me?auth_token=.... for example).
The problem is that the same token can be used by any third party - it's not client specific - and so if you base server identification based on that, you have a problem (since a third app could use its user token and get authenticated by you). I am trying to find a way to solve this issue, but I don't have good ideas yet...
Facebook actually has an Android SDK that lets you do this. Information can be found here.
Yes you can. A valid access token is a valid access token. The Graph API does from where the token came, but only that the token has the appropriate permissions to access that portion of the graph api. Keep in mind, though, that the token is only valid for 24 hours from the time of its issuance. (is that really a word?) From the time it is issued?
When using facebook android sdk with SingleSignOn (SSO), the access token format actually changed.
Instead of getting traditional auth token which contains userid & session key as a part of authToken
now we get a different format of authToken
As Facebook Devs are still in process to support there rest apis with newly formated access token
meanwhile we can disable the SSO on android facebook sdk by changing DEFAULT_AUTH_ACTIVITY_CODE to -1 from 32665 (in Facebook.java)
This will invoke Traditional dialouge for granting acess token and in return you'll get access token which will contain session key in it.
Those who are looking for generating secure session key you need to add your own method in Facebook.java like
public String getSessionSecret(String accessToken) throws MalformedURLException, IOException
{
Bundle b = new Bundle();
b.putString("method", "auth.promoteSession");
b.putString("access_token", accessToken);
b.putString("session_key_only", "true");
String response = request(b);
return response;
}