How can my server authenticate Android users with their Google accounts? - android

I'm building an Android app as part of a client/server architecture, where my server will provide a service to the Android client. The server will not communicate with any Google server, but will need to authenticate the user via their gmail account. That is, the server needs to be sure that the http(s) requests coming from the phone are indeed from the person with that specific gmail account.
I was looking into Android's C2DM framework, which I can certainly use for passing service-related data back and forth, but how can I use Google account authentication between an Android phone and a third-party (non-Google) server?
Will Oath2.0 work for this, or is Oath2.0 only used for direct authentication between the phone and Google's services?

You didn't mention which language code you're going to use in your server.
The easier way to use C2DM is inside Google App Engine which comes with native support for Android integrations with C2DM.
If that's not the case ( EX: youre using php in your own server ) I would take a look to AccountManager which can provides you the auth token ( the app-user must allow it ).
When registering a new device to your C2DM server you'll need the device to communicate also the token so you'll be able to know if the user is really owner of that gmail account through a connection between your server and Google Servers.
:)

I think you must have got the answer to your query by now. But I still would to answer this question to assist other users who are interested in achieving something like this.
So to use google account access token to authenticate and authorize your app user against your own services you have to follow following steps.
Create a project in Google Cloud Console with two components (Create components by clicking on "APIs $ Auth >Credetials" option on left pane ). First component will be your web component (e.g. web-services) and second component is your android application.
Try to get access token by querying account manager in android app by executing GoogleAuthUtil.getToken() method by passing the current context, email id(queried using account manager) and scope as ("audience:server:client_id:").
Where is the "Client ID" parameter of the web component available under the project created on Google Cloud Console.
The method will return you the ID token encoded as JSON web token or JWT.
This ID token everything that a app would require to authenticate user on server.
The ID token consists of following parameters
iss: always accounts.google.com
aud: the client ID of the web component of the project
azp: the client ID of the Android app component of project
email: the email which identifies the user requesting the token, along with some other fields.
Pass this token to your web component (e.g. web services) over https(mandatory) where the web component and Android component client id's are already stored.
After decoding the received JWT ID token on server, check if "aud" parameter of the token and stored web component client id are equal and hence authenticate the user.
User identity can be fetched by reading the email parameter of JWT ID token which specifies the email id provided to access the Id token in android application while executing GoogleAuthUtil.getToken() method.
Note : The ID token on android can only be fetched by executing GoogleAuthUtil.getToken() if it is the same application singed by same certificate specified while creating android component under the project on Google Cloud Console.
More information can be found on "https://developers.google.com/accounts/docs/CrossClientAuth"

Related

Google OAuth2: perform token refreshing server-side while refresh token or authorization code acquired via mobile app

TL;DR - How can I refresh tokens backend-side if the oauth2 authorization happens in native android/ios app?
I am working on oauth2 integration with google calendar. My stack is react SPA app as web client and we have a backend API (in elixir). We are also using hybrid native apps, so our JS code is transformed into corresponding iOS/Android apps (using capacitor).
The flow is as follows:
user authorizes us to modify their calendars using oauth2, we ask for offline access
we acquire client-side authorization code from google
we send it to our backend and it uses the auth code to acquire access token and refresh token, the tokens are then persisted in our DB
we use the access token to perform updates to google calendar. When token expires we refresh it backend-side
This is the flow that is working on the web client, but with native apps (android/ios) I am stuck. When I use corresponding to ios/android apps clientIds from google console project credentials, my backend cannot successfully use it to acquire refresh and access tokens, I get the following response from https://oauth2.googleapis.com/token:
%{"error" => "invalid_client", "error_description" => "Unauthorized"}
I am considering moving the process of exchanging authorization code to refresh token and access token to the native apps, but how can the backend then have access to new access tokens? I can't refresh the tokens backend side if they were generated in the native app, I will again have clientId mismatch (also backend uses clientSecret, while native apps are exempt from using clientSecret).
You cant. The refresh token is client id based. You need the client id and client secret that were used to create it in order to refresh it.
The client used for Ios and android apps doesn't have a client id and secret that you could use backend.
You can do it the other way around though. If you created the refresh token in your backend app. The ios and android apps could refresh it as long as the client id is part of the same project.
I suspect there is something internal in the android and ios sdk's that allow for this. It just doesn't work with any other type of client due to the lack of client secret.
take a look at this documentation, it works form me in the same problem.
https://developers.google.com/identity/sign-in/ios/offline-access
"On your app's backend server, exchange the auth code for access and refresh tokens. Use the access token to call Google APIs on behalf of the user and, optionally, store the refresh token to acquire a new access token when the access token expires."
serverAuthCode is used on this api https://developers.google.com/identity/protocols/oauth2/native-app#exchange-authorization-code to generate a new refresh_token
I had the same issue and finally ended up.
In order to design user authentication from the mobile/front-end side and send the authorization code to the server-side to exchange it for access_token and referesh_token you have not to follow the Mobile or Installed App flow:
In this way, you've created Android app OAuth2 credentials in the google developer console and used its client_id for google oauth2 page preparation so at the end you will have access_token which works only on the mobile side and does not work on the backend as it doesn't have client_secret.
Therefore, if you want to have access to the google APIs on your server-side and just perform the google authentication on the mobile side you can choose one of the following flows:
As you can see from the above flows, there are three parts namely client-side (mobile), google, and server-side (backend) rather than communication just between mobile and google which is useful for installed applications, not web applications. To me, between these two flows, I prefer the last one as it has fewer requests to create access_token and refresh_token on the server-side.
Here's the whole procedure:
create a web application oauth2 credentials on the google developer console and use all sections in the backend and the client_id on the mobile side as well. Don't forget to enable the API you want to use.
create a /callback endpoint in the backend which is the same as redirect_uri that you will need on the mobile side. In this endpoint, you will get the authorization code from the google request and then exchange it to the access_token and referesh_token and persist that on the DB.
create an endpoint in order to call google API such as google calendar.
Bring up the google authorization page on the mobile using SDKs, web view, or browser with the following content: existing client_it (which is the same with server-side), redirect_uri (callback), response_type="code", scope="https://www.googleapis.com/auth/calendar", access_type="offline", include_granted_scopes=true, and state to put some string if you want, for example I sent user's uuid.
You can obtain access_token using refresh token by sending
POST https://oauth2.googleapis.com/token
x-www-form-urlencoded
client_id:CLIENTID
refresh_token:REFRESHTOKEN
grant_type:refresh_token

Cross-client Google OAuth: Xamarin/Android to .NET web service

I have a similar question as found in this post, but for Xamarin.
Cross-client Google OAuth: Get auth code on iOS and access token on server
I'm using Xamarin.Auth to successfully get a token back from Google for the user of my app. I'd like to send that token to the web service, so it can do background queries of Google APIs impersonating that logged in user. (i.e. querying their liked videos). The web service would have to configured with the Xamarin client ID to use the token, but it seems cleaner to use separate client IDs for front-end/back-end.
Xamarin app is using the Google API client ID, which is setup for Android (and has no client secret). I'm using a 'local' package name redirect URI in the app itself, so it never hits a server component to obtain the token. Also, I've created a web application Google API client which has both client id and secrets.
Unless I use the Xamarin/Android client ID for the web service as well, If I'm reading the cross-client docs correctly, I need to somehow transfer the token between these clients (on front-end and back-end). I've tried using the web app client ID/secret to obtain a refresh token, for the Xamarin access token, but get an invalid client error. Which makes sense, I guess, since the token was created with a different client.
I'm supporting multiple OAuth logins (i.e. Google, Facebook, Instagram), and was planning to create a shadow user in my database, which would hold the active token. I'm letting the auth code->token workflow all happen on the client (using Xamarin.Auth.OAuth2Authenticator).
To make this work, do I need implement the authorization code->token transfer on the backend web service during my app login (using web service client ID), or is there some other way to transfer tokens between app/web service clients?
Or does it seem fine to just use the Xamarin client ID on the back-end, and be done with it?
Thanks!

Obtaining offline access for web backend using Firebase for Android

I am using Firebase SDK for authorising user on the Android app for a project which is on App Engine and already using many of the GCP and`G-Suite functionalities.
The web application relies on getting offline access to the user's Google Account.
The Android app is trying to use the same backend APIs that web front end is using. For this, I am sending the ID token of the user to backend.
The problem is that this ID token expires after some time and I am forced to re-authenticate the user to get the new ID token. Initially, I wanted it to not expire or generate a new ID token automatically on the Android app itself, but then I checked the OAuth2 documentation for this, which mentions the following statement -
It is important that the Android app never attempt to exchange the
code for a refresh token on its own. This would require that the app
store the server's client ID and client secret. Including these in
your Android app is insecure, because apps can be easily decomposed.
The recommended flow is mentioned there, but I couldn't find anything which can help me do the same using the Firebase Android SDK.
Is it possible to get the authorization code using Firebase which can be later exchanged for refresh token by the backend? If yes, then can you point me to correct documentation or code example for the same?

Authenticated communication b/w Android app And GAE server using OAuth2

New to OAuth2. I am writing an Android app that communicates with an App engine server application.
The app needs to authenticate itself with the server on behalf of the user, using Google account info of the user. The server needs to retrieve the user's basic info and create an account . That's the easy part and I know how to do this.
Furthermore, the Android app will also have the user authenticate himself/herself using Oauth2 and retrieve basic user info using Google account info of the user. I can do this as well.
This is where I need help Assuming the previous steps have been completed successfully, how can I use the Android app (where the user has logged in) to communicate with the server securely using the user's credentials.
Any ideas or am I missing something obvious?
The Android to App Engine OAuth2 communication is documented in this answer:
google app engine oauth2 provider
Using OAuth, 1.0 or 2.0, doesn’t matter in this, leads to the app obtaining an access token - then based on the API of your server, you pass this access token with requests instead of login and password. I guess the way to attach the access token string to URL requests may be slightly different between different APIs, see the documentation for yourself. Or if you are making the server app at the same time, then you need to figure out your way to do so (like sending a HTTP header Authorization: OAuth access_token=abcdefgh….

On Google App Engine, can I relate a Google OAuth 2 Token and a SACSID token I got using Android's AccountManager?

I am writing a Google App Engine application along with a CLI client, an Android client and a Javascript client. The purpose of this application is to allow one to control an Android phone on which the Android client is installed, by using either the CLI or the Javascript client.
Authentication plays a crucial role as a bug might allow a malicious user to control others' phones.
The Android client is written and works. It authenticates the user using this method. Basically, this give me a so-called SACSID token I can store in a cookie. When this cookie is set App Engine recognizes my user. The server application can then call the UserService to get a User on which to call getUserId(). getUserId() returns me an opaque string that identifies my user. So far so good.
Now I am writing the JS and CLI clients.
Because the CLI client has no reliable way of displaying a CAPTCHA or opening a browser, I suppose that it needs to use the Device API ("Client login" is not an option). This API requires using OAuth 2 for authentication. Also, I want the JS client to access the user's contacts, which also seems to indicates that OAuth 2 would be suitable.
If my user authenticates using OAuth 2, will I be hable to somehow transform this Google OAuth 2 token into the same opaque String that I get when the Android client connects ? If not, can I modifiy my Android Application so that it uses OAuth instead of a Sacsid token ?
To be more specific, I see three things that would solve my problem :
A way of getting an OAuth 2 token from the Account Manager
A way of exchanging the OAuth 2 token for a SACSID token
A way of getting the same opaque UserID both with the SACSID token and the OAuth2, but only if I can have both authentication system on the same application.
Something that seems similar to the third possible solution is to get the user's email address from both OAuth and the SACSID token, and to use that as the user ID. This however looks a bit clumsy to me :
Every time I receive an OAuth 2 request, I would need to call Google APIs to retrieve the user's email address (or build my own system of tokens which seems insecure and introduces many other difficulties).
The email address of a given user can change, making me lose the association between the user and his previous data.
Use End Points instead:
https://developers.google.com/appengine/docs/java/endpoints/
They use oauth2, they are easy to implement and have support for android IOS and Web.

Categories

Resources