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.