Reputation: 587
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
- Set the linking type to be only Oauth, and grant type to be implicit.
- Set the Client ID as my oauth2 client ID
- Authorization URL as 'my-app.com/users/auth/google_oauth2' (Token url not required)
- Set scope as gmail
- 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
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