3

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).

genau
  • 184
  • 1
  • 5
  • 16

4 Answers4

1

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:

enter image description here

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:

enter image description here

enter image description here

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:

  1. 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.
  2. 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.
  3. create an endpoint in order to call google API such as google calendar.
  4. 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.
Benyamin Jafari
  • 27,880
  • 26
  • 135
  • 150
1

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
Roman O
  • 3,172
  • 30
  • 26
0

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.

Linda Lawton - DaImTo
  • 106,405
  • 32
  • 180
  • 449
  • Thank you for the reply. How can I create refresh token in my backend if user does the authorization via native app? As mentioned above - when my native app gets access to auth code and sends it to backend, the request for tokens fails (because of clientId issues) – genau Mar 25 '22 at 17:48
  • Like i said you cant. The clients are not compatible. – Linda Lawton - DaImTo Mar 25 '22 at 17:50
  • I was asking about "You can do it the other way around though. If you created the refresh token in your backend app" – genau Mar 25 '22 at 17:55
  • Yes as far as i know it is possible. I read about it a few years ago. As long as both clients are in the same project on google cloud console you should be able to use a refresh token created from for example with a web or desktop client, With an android or ios app. I will have to look around to see if i can find the documentation that menotned it. – Linda Lawton - DaImTo Mar 26 '22 at 10:20
0

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