Chiah Soon
Chiah Soon

Reputation: 587

Bad response from idP in Auth Code Exchange during google account linking with Rails and DialogFlow

I'm trying to build a rails app as backend for custom Google Actions. The rough user flow would be for users of my app to invoke my custom action via "talk to my_action", which would require them to sign in. From there, i could proceed with extracting user info from their google accounts. The problem i'm facing right now is during the account linking process.

So, the current flow is as such:

'talk to my_action' >> user prompted to view Google Home app to link accounts >> user clicks on the link to link their accounts >> redirected to page where they choose user accounts/ sign in with google account >> 'Bad response from IdP in Auth Code Exchange'. I've searched high and low regarding this error message but i could only find one regarding this specific message.

(I'm unable to post the screenshot due to lack of reputation sorry! But essentially the error screen is just *Bad response from IdP in Auth Code Exchange* and a link to *Re-run linking flow* which still doesn't work.)

Currently, I'm using the gem 'omniauth-google-oauth2' to authenticate with Google via OAuth2 in OmniAuth. I'm not too sure about the omniauth part, but the oauth auth code exchange should take place as described in here.

I am also using the gem google_assistant, specifically the assistant-api-v2 branch. This gem hasn't been updated in a while, and might not have been extensively used/tested, so this might be a potential cause. My server is hosted on heroku, and i use DialogFlow as the fulfilment tool. In DialogFlow, i've already enabled webhooks to my app /myapp/google_assistant, and i've ticked the Sign-In Required checkbox.

As for my accounts linking settings in the Actions on Google Dashboard, i've

  1. Set the linking type to be only Oauth, and grant type to be implicit.
  2. Set the Client ID as my oauth2 client ID
  3. Authorization URL as 'my-app.com/users/auth/google_oauth2' (Token url not required)
  4. Set scope as gmail
  5. Set testing information as 'username: [email protected], password: password'. I do not know what is the proper format for this field yet.

The logs on my Heroku web-app server during the linking process are as follows:

2018-07-05T10:44:16.955840 #4]  INFO -- : [a5b63d61-d97d-4b04-a10b-b3fee18c1c7d] Started GET "/users/auth/google_oauth2?response_type=token&client_id=*my_client_id*&redirect_uri=https://oauth-redirect.googleusercontent.com/r/*my_project_id*&scope=https://mail.google.com/&state=AA7-RQxyASRZMH3DU8v1lXOx08dXZdlDa_8qIqoQfcdSdbT2ltPpyO4JVYGo7SZWmCLgu2oq1aPnojP_ygDQQgjH-3fz7EFopdKVl1WqABA_uhSfwxGqN5ywmLXWE-Y74AFMTs4sEVkG_ctUxCz7oMXDumdPELRjHlhO0VRhcJXQFhCZ_2OOrEDKkST-pPLy_cD4T2Pptni9JQj8QUeXYkklg1I-836q4zqt6vOA9mCEEFqS_h0hwaVizBypk8joO85dOibe8w4OYlp4BHDegSQ_97oPeHJu_7TSJg9M2fAyZqww0XDNjwQAFCwFR1Z0fZ3b4RySlG5Uy_yLr_F5wLbMLvLa0mX63mwuf3hOUX4zoCpBoMnBcLi7hFUiaPj1wpTBhmrAZ05Oq6jKRcOqC-FX6yERPl5tQvNdsGdjH63mc-4J3tDL0tUzvvkYm6p0CjuOho4GiQwA1XZGvHZmOcKPLA6CKr26THAXmPVJSQmiIH1CSAuAypguuiNy0yhmMKgTH_WH5M8banpYYob-Yv2jVqu2H5f2RjF0i_XApCcHUj6VoNEg0cFYiMYaiIKJRH20-HpymW3IgOEd_2TjPg5yKEbYN5bN7C-zILVLC_1qyofyze0ag0lxgvsx3kvbAEI1MLpVAF0EACZeHJujzb8YM0vmOB8FuQLOeSanyZ8zrwrWXRzu9hSBQ4eHegsSneb5CugcQkt09uSnQhOTGGwOi0TVk_f6Sw" for *my_ip* at 2018-07-05 10:44:16 +0000

2018-07-05T10:44:16.956747+00:00 app[web.1]: I, [2018-07-05T10:44:16.956679 #4]  INFO -- omniauth: (google_oauth2) Request phase initiated.

2018-07-05T10:44:17.015111+00:00 heroku[router]: at=info method=GET path="/users/auth/google_oauth2?response_type=token&client_id=*my-client-id*&redirect_uri=https://oauth-redirect.googleusercontent.com/r/my-project-id&scope=https://mail.google.com/&state=AA7-RQxyASRZMH3DU8v1lXOx08dXZdlDa_8qIqoQfcdSdbT2ltPpyO4JVYGo7SZWmCLgu2oq1aPnojP_ygDQQgjH-3fz7EFopdKVl1WqABA_uhSfwxGqN5ywmLXWE-Y74AFMTs4sEVkG_ctUxCz7oMXDumdPELRjHlhO0VRhcJXQFhCZ_2OOrEDKkST-pPLy_cD4T2Pptni9JQj8QUeXYkklg1I-836q4zqt6vOA9mCEEFqS_h0hwaVizBypk8joO85dOibe8w4OYlp4BHDegSQ_97oPeHJu_7TSJg9M2fAyZqww0XDNjwQAFCwFR1Z0fZ3b4RySlG5Uy_yLr_F5wLbMLvLa0mX63mwuf3hOUX4zoCpBoMnBcLi7hFUiaPj1wpTBhmrAZ05Oq6jKRcOqC-FX6yERPl5tQvNdsGdjH63mc-4J3tDL0tUzvvkYm6p0CjuOho4GiQwA1XZGvHZmOcKPLA6CKr26THAXmPVJSQmiIH1CSAuAypguuiNy0yhmMKgTH_WH5M8banpYYob-Yv2jVqu2H5f2RjF0i_XApCcHUj6VoNEg0cFYiMYaiIKJRH20-HpymW3IgOEd_2TjPg5yKEbYN5bN7C-zILVLC_1qyofyze0ag0lxgvsx3kvbAEI1MLpVAF0EACZeHJujzb8YM0vmOB8FuQLOeSanyZ8zrwrWXRzu9hSBQ4eHegsSneb5CugcQkt09uSnQhOTGGwOi0TVk_f6Sw" host=*my-web-app* request_id=a5b63d61-d97d-4b04-a10b-b3fee18c1c7d fwd="*my-ip*" dyno=web.1 connect=0ms service=63ms status=302 bytes=5935 protocol=https

As for the redirect chain of the process, i'm not sure how to entirely save the network logs, but using a Chrome extension, the redirect-chain when signing in to google account, leading to the bad response error is:

Status Code URL IP  Page Type   Redirect Type   Redirect URL    
302 https://oauth-redirect.googleusercontent.com/r/*my-project-id*?state=AA7-RQyd1KsD63DBoQF_-NfYijzGvptfXTEj8D3AwQzW_ByUe8K0UnLZVuQjE6y8txJMcabFTC4fQhxHqqpTv28_e3dDuLBpYaGKqo_urwHkswmf1pAV2da7nPoVb-n1DHe1P-xU-jzU5c8vlyWCXJPpMDZyR7K0AQ7qdDCQRtr9oPpDymPyYknGIrQB6rI9VRSFinsGhZTnno2AvtOJCkTZfe3abYSdzjB-Am3PI9p-oAwh0f6mBzUGDYCMIB-traI_INV9fSa8tS9K363pBKUBQ-YgKI5nKI8Uqbz5UduNDwB99eQSUaEZu48vabVTwGjsLUczbkA46-u-AKAV65iwTPE6e-zRI11LRgfw4uObam8S3xvL3ok9pESzwGpMlBmEO0goyg9xJa2ULatLOy2PGRcMbWcuhyp84ttzedmiD2gdidVxHafEwgSpSEqad6YLWvCtV4XGbHxyuFZXF8rjFiDUK__KaJ2G-cbzyiXaVQ-YOh80NM8QQmAIPvys-2BTteP_G-1xjRZFpgJO6-dnZw2jelcF8KkITIGTNMuLejrcCyADjusaNOMrHMkASXohnq5p0lpkjPIcEZryghziPu3soPJ8A9jj8K9Ka-CWNosv9aBAnpN4eKYlOBEVljc6W824XPYgYMW62cBHlTlqV8RMNpo_5h6LRf2UdmY2T85xk3Iuz1_1Lr8jeu-UYZILPP2sc7HrjP7eFp70qgMCUQEk_JwsyQ&code=4/AAC6qctB8IxI0ijzYibSubvzae-yNgNcVOtUrbnhORSMNRxQXi2DeZE9wqn6lLqOLkb0NYeYRU15IH8H6qP9CcY# 172.217.160.1   server_redirect temporary   https://gala-demo.appspot.com/app#redirect_state=AA7-RQxBXe_JzFx7iXtcObVa7AJ4qPiiLY_XHrtgX861Z1TlUiOLFM3ymhzxqHWCONLFXjOJQkhNyCsH35cylVBrKtyLDaE-4J7wJ-P9PS3-JEPVeaoRnm7uo4ncLPW5EMxR--onGLFNZydFbqNKhdhWTox3FkUuv2lNZB2FcY9ZuhmE7LwiMXFYatawmFXpjZ0QdLkKEvqGcrG0gxi6G9e_Rsa1maUBWLvb3GKU3jXfL5J0YQI_Y6WwJj5c1c8gzBnABulzSR9wak3r9J-wTSM1-doKNIWr1OBeeoj40AR-NwIcj_9BgOGupUTQA-jdV0mQL6q69bVDuwrMJ_ftuC2ojAINWuGcVlF8MaT8phT347rFS8jAfZXKMM2N6gwEbO6Pepgtndg74JcKcwN6jhN0_dWE9XnNH78iwZoQP2nIu1_hojLOiN26-Y3l1xjKUu9WpCrdbIn3jdBIjUs_82pwM2uRqdvLAuiJJVktaJ9CNaky29bihLV1KwcyzQU5zMZ0YdOgvDi7vDHF15FyR2mlywXhx2Pzqs_Gi09Q3CUQ_u0JKiM3_Iyo9RxuzDUZIvZRUtGbu4W2rIWHgKuwGEw6C611ZGtUjORNpEjgHc_861OLJJBSqAIqGgE1tvilyV9y6FbqoXtP5bAfYFuWWl5lmcy9r6s3D3coagPdKlHcrxYxkUETRSyuaCcBo75ilztd3YqgyxVIadbgOwHmU0Cx-mtdwwJOfEdousw2dXnAkdVuG1d4fv6dT6XKyd4x7dyh7CPtVH9O2j65NvIqFE90NfQdNupm_kSKfnt3xCnwzTv155BM4B9tiXd6aKp3d2xIkY57nsTqOTBmTZ6_lf9-EWeHxS_0ukbDYiSVQsFwDz8d0GilKeU&state=AA7-RQyd1KsD63DBoQF_-NfYijzGvptfXTEj8D3AwQzW_ByUe8K0UnLZVuQjE6y8txJMcabFTC4fQhxHqqpTv28_e3dDuLBpYaGKqo_urwHkswmf1pAV2da7nPoVb-n1DHe1P-xU-jzU5c8vlyWCXJPpMDZyR7K0AQ7qdDCQRtr9oPpDymPyYknGIrQB6rI9VRSFinsGhZTnno2AvtOJCkTZfe3abYSdzjB-Am3PI9p-oAwh0f6mBzUGDYCMIB-traI_INV9fSa8tS9K363pBKUBQ-YgKI5nKI8Uqbz5UduNDwB99eQSUaEZu48vabVTwGjsLUczbkA46-u-AKAV65iwTPE6e-zRI11LRgfw4uObam8S3xvL3ok9pESzwGpMlBmEO0goyg9xJa2ULatLOy2PGRcMbWcuhyp84ttzedmiD2gdidVxHafEwgSpSEqad6YLWvCtV4XGbHxyuFZXF8rjFiDUK__KaJ2G-cbzyiXaVQ-YOh80NM8QQmAIPvys-2BTteP_G-1xjRZFpgJO6-dnZw2jelcF8KkITIGTNMuLejrcCyADjusaNOMrHMkASXohnq5p0lpkjPIcEZryghziPu3soPJ8A9jj8K9Ka-CWNosv9aBAnpN4eKYlOBEVljc6W824XPYgYMW62cBHlTlqV8RMNpo_5h6LRf2UdmY2T85xk3Iuz1_1Lr8jeu-UYZILPP2sc7HrjP7eFp70qgMCUQEk_JwsyQ&service=*my_project_id*dev

200 https://gala-demo.appspot.com/app#redirect_state=AA7-RQxBXe_JzFx7iXtcObVa7AJ4qPiiLY_XHrtgX861Z1TlUiOLFM3ymhzxqHWCONLFXjOJQkhNyCsH35cylVBrKtyLDaE-4J7wJ-P9PS3-JEPVeaoRnm7uo4ncLPW5EMxR--onGLFNZydFbqNKhdhWTox3FkUuv2lNZB2FcY9ZuhmE7LwiMXFYatawmFXpjZ0QdLkKEvqGcrG0gxi6G9e_Rsa1maUBWLvb3GKU3jXfL5J0YQI_Y6WwJj5c1c8gzBnABulzSR9wak3r9J-wTSM1-doKNIWr1OBeeoj40AR-NwIcj_9BgOGupUTQA-jdV0mQL6q69bVDuwrMJ_ftuC2ojAINWuGcVlF8MaT8phT347rFS8jAfZXKMM2N6gwEbO6Pepgtndg74JcKcwN6jhN0_dWE9XnNH78iwZoQP2nIu1_hojLOiN26-Y3l1xjKUu9WpCrdbIn3jdBIjUs_82pwM2uRqdvLAuiJJVktaJ9CNaky29bihLV1KwcyzQU5zMZ0YdOgvDi7vDHF15FyR2mlywXhx2Pzqs_Gi09Q3CUQ_u0JKiM3_Iyo9RxuzDUZIvZRUtGbu4W2rIWHgKuwGEw6C611ZGtUjORNpEjgHc_861OLJJBSqAIqGgE1tvilyV9y6FbqoXtP5bAfYFuWWl5lmcy9r6s3D3coagPdKlHcrxYxkUETRSyuaCcBo75ilztd3YqgyxVIadbgOwHmU0Cx-mtdwwJOfEdousw2dXnAkdVuG1d4fv6dT6XKyd4x7dyh7CPtVH9O2j65NvIqFE90NfQdNupm_kSKfnt3xCnwzTv155BM4B9tiXd6aKp3d2xIkY57nsTqOTBmTZ6_lf9-EWeHxS_0ukbDYiSVQsFwDz8d0GilKeU&state=AA7-RQyd1KsD63DBoQF_-NfYijzGvptfXTEj8D3AwQzW_ByUe8K0UnLZVuQjE6y8txJMcabFTC4fQhxHqqpTv28_e3dDuLBpYaGKqo_urwHkswmf1pAV2da7nPoVb-n1DHe1P-xU-jzU5c8vlyWCXJPpMDZyR7K0AQ7qdDCQRtr9oPpDymPyYknGIrQB6rI9VRSFinsGhZTnno2AvtOJCkTZfe3abYSdzjB-Am3PI9p-oAwh0f6mBzUGDYCMIB-traI_INV9fSa8tS9K363pBKUBQ-YgKI5nKI8Uqbz5UduNDwB99eQSUaEZu48vabVTwGjsLUczbkA46-u-AKAV65iwTPE6e-zRI11LRgfw4uObam8S3xvL3ok9pESzwGpMlBmEO0goyg9xJa2ULatLOy2PGRcMbWcuhyp84ttzedmiD2gdidVxHafEwgSpSEqad6YLWvCtV4XGbHxyuFZXF8rjFiDUK__KaJ2G-cbzyiXaVQ-YOh80NM8QQmAIPvys-2BTteP_G-1xjRZFpgJO6-dnZw2jelcF8KkITIGTNMuLejrcCyADjusaNOMrHMkASXohnq5p0lpkjPIcEZryghziPu3soPJ8A9jj8K9Ka-CWNosv9aBAnpN4eKYlOBEVljc6W824XPYgYMW62cBHlTlqV8RMNpo_5h6LRf2UdmY2T85xk3Iuz1_1Lr8jeu-UYZILPP2sc7HrjP7eFp70qgMCUQEk_JwsyQ&service=*my_project_id*_dev   74.125.24.153   normal  none    none

I also noticed that there's a single error 400 during the last step of authentication:

{
  "error": {
    "code": 400,
    "message": "Bad response from IdP in Auth Code Exchange",
    "status": "FAILED_PRECONDITION"
  }
}

    Request URL: https://oauthintegrations.googleapis.com/v1/token:getForService
    Request Method: POST
    Status Code: 400
    Remote Address: 74.125.24.95:443
    Referrer Policy: no-referrer-when-downgrade
    access-control-allow-origin: https://gala-demo.appspot.com
    access-control-expose-headers: content-encoding,date,server,content-length
    alt-svc: quic=":443"; ma=2592000; v="43,42,41,39,35"
    cache-control: private
    content-encoding: gzip
    content-length: 136
    content-type: application/json; charset=UTF-8
    date: Thu, 05 Jul 2018 13:17:41 GMT
    server: ESF
    status: 400
    vary: Origin, X-Origin, Referer
    x-content-type-options: nosniff
    x-frame-options: SAMEORIGIN
    x-xss-protection: 1; mode=block
    Provisional headers are shown
    Authorization: Bearer *my access_token*
    Content-Type: application/json
    Origin: https://gala-demo.appspot.com
    Referer: https://gala-demo.appspot.com/app
    User-Agent: *my user agent*
    {credential: {,…}, gdiState: "APP_AUTH", serviceId: "ardent-fusion-209108_dev",…}
    credential
    :
    {,…}
    gdiState
    :
    "APP_AUTH"
    scopes
    :
    ["https://mail.google.com/"]
    serviceId
    :
    "*my_project_id*_dev"

Any help would be much appreciated! Please do comment if you need any more information. Thanks and have a nice day! :)

Updates: I've since realized that omniauth follows the auth code flow. I've thus changed my linking flow to auth code and added /users/auth/google_oauth2 as my auth url and /users/auth/google_oauth2/callback as my token url. However, there is now an error of redirect_uri_mismatch even though i have added my_app.com/users/auth/google_oauth2/callback and my_app.com/users/auth/google_oauth2 and oauth-redirect.googleusercontent.com/r/my_proj_id into my oauth client's authorized uri redirects. I've since tried adding a trailing / to the redirect uri in the client, as well as swapping https for http and adding a www in front of each uri, but all of these methods don't work. (All urls above are with https; my reputation is too low to post more than 8 links so i have to omit them)

The new errors logs are as such:

2018-07-06T10:06:48.542310+00:00 app[web.1]: I, [2018-07-06T10:06:48.542182 #4]  INFO -- : [2270a384-f7a5-4b6a-9dce-a6999dc47b28] Started POST "/users/auth/google_oauth2/callback/" for 66.249.83.158 at 2018-07-06 10:06:48 +0000

2018-07-06T10:06:48.542796+00:00 app[web.1]: I, [2018-07-06T10:06:48.542726 #4]  INFO -- omniauth: (google_oauth2) Callback phase initiated.

2018-07-06T10:06:48.651257+00:00 app[web.1]: E, [2018-07-06T10:06:48.651082 #4] ERROR -- omniauth: (google_oauth2) Authentication failure! invalid_credentials: OAuth2::Error, redirect_uri_mismatch: Bad Request

2018-07-06T10:06:48.651261+00:00 app[web.1]: {
2018-07-06T10:06:48.651264+00:00 app[web.1]:   "error" : "redirect_uri_mismatch",
2018-07-06T10:06:48.651266+00:00 app[web.1]:   "error_description" : "Bad Request"
2018-07-06T10:06:48.651268+00:00 app[web.1]: }

2018-07-06T10:06:48.652619+00:00 app[web.1]: I, [2018-07-06T10:06:48.652524 #4]  INFO -- : [2270a384-f7a5-4b6a-9dce-a6999dc47b28] Processing by Users::OmniauthCallbacksController#failure as JSON

2018-07-06T10:06:48.652781+00:00 app[web.1]: I, [2018-07-06T10:06:48.652696 #4]  INFO -- : [2270a384-f7a5-4b6a-9dce-a6999dc47b28]   Parameters: {"grant_type"=>"authorization_code", "code"=>"*my_auth_code*", "redirect_uri"=>"https://oauth-redirect.googleusercontent.com/r/*my_proj_id*", "client_id"=>"*my_client_id*", "client_secret"=>"*my_client_secret*"}

Upvotes: 2

Views: 1166

Answers (1)

Prisoner
Prisoner

Reputation: 50701

Let's look at what is going wrong and, rather than trying to fix it, a completely different approach to the problem which should hopefully work better.

What is going wrong (and some background)

Traditional authentication with Actions on Google required you to setup an OAuth server. When the user gets to a point in their Action where you require an authenticated user, it directs them to your OAuth web server to login, expects your server to send an access token or auth code back to it, possibly do some further work to get an auth token, and then send you the access or auth token every time your webhook fulfillment is called. You then use this token to figure out who the user is and act appropriately.

What looks like is happening is that the Assistant is sending the user to your login point with information that says "when you're done, redirect back here with an access token". That part seems fine. You're going through a login process that includes Google Sign In. At some point in there, you're redirecting back to the same URL the Assistant wants.

The problem is that instead of sending back an access token, it is sending a one time auth code. The Assistant gets this and, since it isn't what it is configured to handle, bails out with an error.

It isn't clear why it is sending the code instead of the access token. It could be that OmniAuth is designed to use the "auth code" method, and you've configured the Assistant to use the "implicit" method. Or it could be that both the Sign In and Assistant are using the same URL as part of the process, and this is confusing things. OR it could be that OmniAuth isn't really meant to play the role of an OAuth server.

If you really want to go this route, investigate the OmniAuth configuration and consider changing its or the Action's configuration.

Update: Sounds like it was using the incorrect auth flow, and I'm glad you've straightened that out. The authorized redirect_uri that you should be setting for OmniAuth needs to be exactly what Google is sending as part of its request: https://oauth-redirect.googleusercontent.com/r/my_project_id

However... you may not need this.

Using Google Sign-In for Account Linking

Since you are signing in the user in your webapp using Google Sign-In, you may be able to avoid the entire OAuth server issue and take advantage of a shortcut that is now available. If your webapp and your Action are both part of the same Google Cloud Project, then Google Sign In for the Assistant will send you an ID Token for the user once they have authenticated themselves to the project. They can authenticate themselves either through voice in the Action or by logging into a webapp with Google Sign In.

The ID Token that is sent is not an auth token. However, if you have saved the auth token and refresh token from the user logging into your webapp, you can use the information in the ID Token to look this information up and use them.

The big "gotcha" as part of this is that you need to request the additional scopes only through your webapp - there is no way to do this as part of the Action. This isn't a major hurdle, however - it just means that if a user reaches your Action without an ID, direct them to log into your webapp first.

See further discussion and diagrams at this Stack Overflow question

Upvotes: 1

Related Questions