Search code examples
iosoauth-2.0google-oauthappauth

Cross-client Google OAuth: Get auth code on iOS and access token on server


I'm trying to set up Google OAuth with my iOS app and Rails web app. I have 2 separate clients (with of course different client IDs, but with the same prefix) set up in the API Console. One for the iOS app, and the other for the web app (which also has a client_secret. I want to use the AppAuth SDK on iOS to get the user's auth code, then send that to my web app, which will then perform the exchange for the access token.

First of all, does this sound like a reasonable thing to do, or is it not possible to split the transaction across clients like that?

My first try was to just take the auth code and perform the exchange, but that failed with the missing_code_verifier invalid_grant error, so I also passed the same code_verifier that AppAuth used to get the auth code to my server, and that fixed that error. First of all, is it necessary to pass this code verifier to the server? Seems a little strange.

Now though, it fails with the unauthorized_client error. My web app is making a request like this:

{
  "grant_type"=>"authorization_code",
  "code"=>"4/XYZ...",
  "client_id"=>"WEB_APP_CLIENT_ID_HERE.apps.googleusercontent.com", 
  "client_secret"=>"WEB_APP_CLIENT_SECRET_HERE", 
  "redirect_uri"=>"https://www.myapp.com/oauth_callback", 
  "parse"=>"json",
  "code_verifier"=>"CODE_VERIFIER_STRING_HERE"
}

Looking at posts like:

it looks like the redirect_uri might be an issue here. My AppAuth config on iOS has the redirect URI set as com.googleusercontent.apps.iOS_CLIENT_ID_HERE, and the Info.plist URL scheme too. The web app's "Authorized redirect URIs" section in the API Console has a bunch of web URLs, and I added the com.google... to it as well. Is this config incorrect? Is the redirect_uri important when doing cross-client auth?

Any help is greatly appreciated! All my trial-and-error have had no fruition so far :(


Solution

  • I am the lead maintainer of AppAuth, and work on the Google Identity Platform; hopefully I can help.

    I want to use the AppAuth SDK on iOS to get the user's auth code, then send that to my web app, which will then perform the exchange for the access token.

    First of all, does this sound like a reasonable thing to do, or is it not possible to split the transaction across clients like that?

    Exchanging the code on your server sounds reasonable, however I think the configuration you are using is possibly incorrect. If you are requesting a code for exchange on your server, use the server's client id in the request to the authorization server. From your description it sounds like your authorization server request is sending your iOS client ID, and you are then doing the exchange with your server client ID, and I believe this is why you are seeing an "unauthorized_client" error.

    This is not terribly well documented, apologies for that. It is alluded to in this section of the documentation on "offline access", though it talks about it purely in terms of Android usage via GoogleApiClient.

    is it necessary to pass this code verifier to the server? Seems a little strange.

    The intention behind PKCE is to ensure that the entity making the authorization request is the same as the entity making the code exchange request. The code_verifier should not leave the device under normal circumstances.

    However, it is not necessary to use PKCE if you are exchanging your code using a client secret controlled by your backend; you can disable PKCE in AppAuth for this scenario.