Actions on Google - Account Linking process hits Token URL before Authorize URL? - actions-on-google

We are trying to support the 'traditional' Account Linking flow as it seems the most general purpose, gives us a chance to surface T&C's, and we thought would be most bedded in.
But testing in the Assistant mobile app for starters, it fails for most users in our Actions app in Dev - After the user sees the Google-driven pop-up in the Assistant app with the "LINK ACCOUNTS" option - They tap that option, and our authorization screen does not appear.
Actions support have had a look at our Account Linking config and can't see any problems.
A couple of test users with newer Android phones DO see our Authorization screen, but the majority do not.
If we test the Authorization URL by pasting into a browser on the same device - It always displays just fine.
What is strange - If we look in our web server logs during the failed cases, the only hits we are seeing are to our 'TOKEN URL', whereas my understanding is a newly linking user should hit our 'Authorization URL' before ever hitting Token.
The successful cases DO hit our Authorization URL first, as expected.
Feel free to pipe up if anyone can answer ANY of the following:
Any ideas what could be causing problems here?
Or ways we might investigate deeper?
Does an app need to be in Alpha testing, or anything like that before Account Linking works?
Is it normal/expected to hit the Token URL for a user that has never successfully linked accounts?
Can anyone confirm what the Token fetch response should be in that case? (Maybe we are not responding in a way that satisfies the other end)
Does anyone have a dummy/HelloWorld Account Linking web end-point we could test against? (Geeze that would be handy for the developer community!)

I don't know exactly what is going on, but there are a couple of hints about what is happening and what avenue to investigate. I'm going to assume you're doing Account Linking with OAuth only. If you are doing a combination of "Google Sign In for Assistant and OAuth", that might change some things. To address some of your questions:
What could cause the Assistant to go to the Token Endpoint instead of the Auth endpoint?
It wouldn't go to the Token Endpoint unless it already had a Token. I could think of a few possible scenarios:
If it was going to Auth, getting a token since it was already authorized, so no window would pop up. (But you indicated it isn't going to that page.)
If the account in question is already authorized to the project via some other means. You can check https://myaccount.google.com/permissions to see if it is already authorized.
If you had tested it with this account previously and it has a token from then. If so, it should be listed at https://myaccount.google.com/permissions. Probably.
If you're not using the account you think you're using on the device in question.
How to investigate this?
Once you double-check some of the more obvious things (using the right account?):
Look at what is being sent to the Token endpoint
Does the token look familiar? Is it the same between calls? Same between different accounts?
Do you log tokens being issued? Can you?
What about the other information sent along with the token such as the client_id and client_secret?
Does it need to be in Alpha?
I'm not sure. Last I checked, it did not. I do think that it no longer works in the simulator, which is annoying, but doesn't require being in Alpha.
It does make it a little more difficult to check, however, since there is no Directory page that can tell you if the account is already linked. You'll need to go to the list of linked apps for the account to remove your app if it is: https://myaccount.google.com/permissions
Is this normal?
I wouldn't think so. It shouldn't hit the Token Endpoint unless it has an auth code or refresh token to exchange. It has to have that code/token from somewhere.
How should you respond?
If you get an auth code or refresh token that is invalid, or any of the other information provided at the token endpoint doesn't match what it should, you must return HTTP error code 400 "Bad Request" and include as the body the JSON
{"error": "invalid_grant"}
This should force it to go through reauth with the user.
Is there a public test server?
Auth0 isn't exactly public, but is free for basic use, and well suited for test purposes.

Related

Is there anyway to authenticate a user with Github without redirecting them within the current page?

I am looking to allow a user to sign in with github for a website I am creating that will be API driven. However, I am running into a problem that there seems to be no way of authenticating a user and getting their email and name without redirecting them on the current page to github. I have tried to create a popup, but there is no way for me to get the necessary data from the popup, namely an api token to be used for the next calls.
The answer to the question as framed is "use a different grant flow" but your questions tell me you don't understand OAuth grant flows so you may be better served by a lecture on OAuth.
Popups and iframes are specifically designed to prevent code running outside them from fishing out data, because if you could do it so could invisible iframes in dodgy ads. Give up on that approach because in the unlikely event that you find a way, browser makers will immediately take steps to prevent your solution from working.
The behaviour you describe sounds to me like implicit grant flow.
Here's a walkthrough of the various ways OAuth2 can work.
Why so many ways?
Implicit grant is a flow that uses redirection to deliberately take control away from your code - which might be compromised or impersonated - and give it to a trusted third party, the OAuth provider: GitHub in this case. You pre-register the point to which control is returned after authentication, the point of which is the token is always given to your code.
Amnesia, popups, and what was I doing before we were so rudely interrupted?
There are flows that use popups. Usually this is the authorisation code grant flow. Popups are not suitable for mobile devices and this led to the creation of the implicit grant flow.
The usual reason for not liking redirection is the amnesia it causes. The solution is to store app state persistently prior to passing control to the OAuth provider, and to write a return-from-oauth handler that unpacks the JWT from the redirect parameter and then restores the app state you saved.
Note to self
If the user is anonymous prior to authentication serialise your state to a string and put it in a cookie or in localStorage.
If the user is not anonymous and is authenticating to elevate privilege you'll have to send any privileged data to the server and just persist a retrieval token on the browser. You must ensure that retrieval of this state requires both a valid OAuth token and a valid state token, and that it discards the state after honouring a request so that a replay attack will be conspicuous (you'll have to handle the fallout).
Having acquired a valid token you can use it to request profile information from GitHub. A very small amount may already be present in the JWT; you'll probably have the email address that served as a login, but this isn't necessarily the right one for correspondence.
GitHub OAuth documentation
It appears GitHub only supports code grant auth. That means you have to do the popup/iframe thing. Here's their doco:
https://developer.github.com/v3/oauth/
Code grant - why?
This flow doesn't give you an encoded token, it gives you a code you can redeem for an encoded token. The idea is that when the token expires you can use the code to get a refresh token without sending credentials over the wire.
Not only you have a redirection, but starting Dec. 2020, you also have:
OAuth 2.0 Device Authorization Flow now GA
GitHub Apps and OAuth Apps now feature GA support for the OAuth 2.0 Device Authorization Grant, in addition to the existing Web Application Flow.
This allows any CLI client or developer tool to authenticate using a secondary system with a browser.
GitHub CLI uses this authentication method on the login command.
Read the full documentation on Authorizing OAuth Apps and Authorizing Users for GitHub Apps for more information.
Confirmed March 2022:
Enable OAuth Device Authentication Flow for Apps
From today the OAuth Device Authorization flow feature must be manually enabled for all OAuth and GitHub Apps.
This change reduces the likelihood of Apps being used in phishing attacks against GitHub users by ensuring integrators are aware of the risks and make a conscious choice to support this form of authentication.
If you own or manage an OAuth App or GitHub App that makes use of the OAuth Device Authorization flow, you can enable it for your App via its settings page:
The OAuth Device Authorization flow API endpoints will respond with status code 400 to Apps that have not enabled this feature.
Documentation: "Device flow"

Google oAuth2 tokens invalidated more and more

I have a web app built on oAuth2 that has been in production for 5+ years. Users Authenticate and Authorize with Google and grant my application access to the Google Analytics data.
All of a sudden I am seeing a surge in failures when refreshing my users oAuth2 tokens. This is the call:
https://accounts.google.com/o/oauth2/token
Passing these parameters:
client_id=xxyyzz
client_secret=xxyyzz
grant_type=refresh_token
refresh_token=xxyyzz
This seems to be be on accounts that are less active (i.e. it could be 15+ days between instances where we make calls on their behalf). I have to reach out to them and have them "ReAuthorize" against Google to get things working.
1) Did something recently change with Google oAuth2 or the GA Core Reporting API?
2) If access tokens are not refreshed after some time period will my refresh token become invalid? i.e. should I make calls against all accounts even thought I don't need the data; just to keep the refresh token from going stale?
Thanks,
Mark.
Update on Scope
It was requested to provide the scopes in play here:
https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile
https://www.googleapis.com/auth/analytics.readonly
11/17/2016 Update:
We did find an issue that resulted in some tokens being purged. We are working on to make sure it doesn't happen again. Unfortunately there is no way to restore the tokens that were deleted and your users will have to reauthorize again.
11/11/2016 update:
We are actively investigating the issue. You should ask your users to re-authorize the application.
(from Google Identity/Auth team) We would like to investigate this a bit more to make sure our system is working as intended. Other than the token revocation (with certain scopes) on password change, we haven't changed the token revocation policy.
Would you please ping me via my G+ profile?

"Developer Inactive" on Beats Music server-side auth token request

I'm working on a project and a new Beats Music API library for Clojure, but in my testing I'm finding it difficult to get write access authentication, but read-only user authentication works fine.
In testing my library I set up a HTML page to do the OAuth and get the OAuth code and then feed that code in to my library to fetch the actual authentication token. The first part works flawlessly, the second part has the dreaded "Developer Inactive" error:
URL: /oauth/token
PARAMS: client_secret, client_id, redirect_uri, code, grant_type=authorization_code
METHOD: post (application/x-www-form-urlencoded)
I've double checked my redirect_uri is the same as defined in my app settings and is the url of the HTML page I generated the code with. I even checked with the support folks to double check that my application wasn't throttled or something, but that took too long and I made a second application and had the exact same results. I've looked at other support questions like this and nothing has helped, so unless I'm missing something in my auth request, my only other thought was that my user account is still on it's 14-day trail and maybe that is affecting my auth token in some way?
Any ideas or suggestions would be greatly appreciated.
From https://developer.beatsmusic.com/docs/read/getting_started/Client_Side_Applications
"The scope of an access token using the implicit flow is limited to read only since client side applications cannot keep a secret. You'll need to request the authorization grant flow via the Web Server Authentication for write permissions, such as updating a playlist."
I hope this helps.
As #jsd pointed out in a comment on my question, there was a typo in the url endpoint. The correct endpoint is (which I had in the other function and that's why it was working correctly):
/oauth2/token

Unexpected Authorization Request in Workflow C2QB WF3.0

We have a multi-tenanted/multi-domain app and we're looking at publishing on IPP. Because of the multi-domain nature our configured endpoints in the App setup are generic and users are then redirected to their specific account once their identity is established.
The issue is with C2QB WF3.0.
The test steps are:
go here: https://appcenter.intuit.com/Home/MyApps/
on the "Launch My Apps" tab, click the app
Expected Result:
the Sign In screen for the app is displayed
The requirement is:
if not still signed into the app, sign in screen is displayed
if still signed into the app, take user into the app
The issue is that the even if the user is currently logged into our application, it still requests authorization as per this message:
"domain" is requesting some information from your Intuit account
By approving this request "domain" will be able to access your:
Name
Email Address
The workflow that it is actually following is to perform a callback to our connect url. The normal way to determine which account the callback is coming from is via the realmId, but this is not received from Intuit and therefore it needs to be requested. Once a user has completed this authorization, it will not ask again. It should be noted that we're not actually requesting a name or an email address as the screen suggests.
We've been informed by Intuit that it should not request authorization and it is not part of the workflow.
We're wondering if anyone else has encountered this problem and if there is a workaround for it.
We discussed with the Engineering teams and they confirmed what Pete has mentioned above. This is not a bug and please follow the steps as Pete has mentioned.
If you want to replicate the 'access your app with appcenter flow', you have be either logged in QBO online company file in same browser session or navigate to the app via blue dot menu from your application or run your application from localhost(.net) and then go to Appcenter and login there on same tab and then click on your app.
Since your desktop application is running, your code will be hit.
You will then get the second Auth screen only for authorizing your company file. After authorization your realm will be set in a cookie and in the code you can see its value. You can replicate this behavior via firebug and see the qbn.parentid cookie value has the realm after authorization is done.

Possible approach to secure a Rest API endpoints using Facebook OAuth

I've been reading a lot about the topic but all I find are obsolete or partial answers, which don't really help me that much and actually just confused me more.
I'm writing a Rest API (Node+Express+MongoDB) that is accessed by a web app (hosted on the same domain than the API) and an Android app.
I want the API to be accessed only by my applications and only by authorized users.
I also want the users to be able to signup and login only using their Facebook account, and I need to be able to access some basic info like name, profile pic and email.
A possible scenario that I have in mind is:
The user logs-in on the web app using Facebook, the app is granted
permission to access the user Facebook information and receives an
access token.
The web app asks the API to confirm that this user
is actually registered on our system, sending the email and the
token received by Facebook.
The API verifies that the user
exists, it stores into the DB (or Redis) the username, the token and
a timestamp and then goes back to the client app.
Each time the
client app hits one of the API endpoint, it will have to provide the
username and the token, other than other info.
The API each time
verifies that the provided pair username/token matches the most
recent pair username/token stored into the DB (using the timestamp
to order), and that no more than 1 hour has passed since we stored
these info (again using the timestamp). If that's the case, the API
will process the request, otherwise will issue a 401 Unauthorized
response.
Does this make sense?
Does this approach have any macroscopic security hole that I'm missing?
One problem I see using MongoDB to store these info is that the collection will quickly become bloated with old tokens.
In this sense I think it would be best to use Redis with an expire policy of 1 hour so that old info will be automatically removed by Redis.
I think the better solution would be this:
Login via Facebook
Pass the Facebook AccessToken to the server (over SSL for the
android app, and for the web app just have it redirect to an API endpoint
after FB login)
Check the fb_access_token given, make sure its valid. Get user_id,email and cross-reference this with existing users to
see if its a new or old one.
Now, create a random, separate api_access_token that you give back to the webapp and android app. If you need Facebook for
anything other than login, store that fb_access_token and in your
DB associate it with the new api_access_token and your user_id.
For every call hereafter, send api_access_token to authenticate it. If you need the fb_access_token for getting more info, you can
do so by retrieving it from the DB.
In summary: Whenever you can, avoid passing the fb_access_token. If the api_access_token is compromised, you have more control to see who the attacker is, what they're doing etc than if they were to get ahold of the fb_access_token. You also have more control over settings an expiration date, extending fb_access_tokens, etc
Just make sure whenever you pass a access_token of any sort via HTTP, use SSL.
I know I'm late to the party, but I'd like to add a visual representation of this process as I'm dealing with this problem right now (specifically in dealing with the communication between the mobile app and the web api by securing it with a 3rd party provider like facebook).
For simplicity, I haven't included error checks, this is mostly just to outline a reasonable approach. Also for simplicity, I haven't included Tommy's suggestion to only pass your own custom api token once the authorization flow is over, although I agree that this is probably a good approach.
Please feel free to criticize this approach though, and I'll update as necessary.
Also, in this scenario, "My App" refers to a mobile application.