Dropbox OAuth2 API always prompts user for permission when a refresh token is requested - oauth-2.0

I'm writing an offline application that uses the Dropbox API. When a user comes to the application, I'm using the https://api.dropbox.com/oauth2/token (docs) to get a refresh_token, which I store for later use.
I am calling the same endpoint every time the user logs in (unless I've already got the user's data in a cookie). I'm not sure that this is the best way to go about it: I at least need to get the user's account_id, so that I can look up their refresh_token in the database if I already have it. But every time I call https://api.dropbox.com/oauth2/token, the user is redirected to the Dropbox app authorization interface, as if they've never approved the app before.
So I would either like to know how to stop Dropbox from forcing the user to re-authorize an app every time. Or, if that is just how https://api.dropbox.com/oauth2/token is supposed to work, I'd instead like to be able to get their account_id somehow when they visit my page.
(In case it's relevant, the app is still in development mode at this point.)

The https://api.dropbox.com/oauth2/token endpoint is an OAuth endpoint that the app can call to get an access token/refresh token. Being an API endpoint, it does not itself redirect the user to the Dropbox app authorization page.
The Dropbox app authorization page is at https://www.dropbox.com/oauth2/authorize (documented here), and the app decides if/when to direct the user there to authorize the app.
You generally only need to send the user through the app authorization flow (sending them to https://www.dropbox.com/oauth2/authorize and then calling https://api.dropbox.com/oauth2/token) once per user for an "offline" application. Once you do so, you should store the resulting refresh token for that user. You'll typically store the refresh token for that user tied to their user account in your own app.
Exactly how you manage the user accounts in your own app will depend on how it's built, but, as it sounds like this is a web app, typically you would use the user's browser cookies to identify the user when they return to your page so that you can look them up in your database and retrieve their details, such as their corresponding refresh token. (Or, if they're not already signed in to your web app, you would have them do so first.)

Greg's answer is very helpful, and very politely addresses my misunderstanding of the auth flow. (I was revisiting old code I'd written years previously—obviously I should have documented it better than I had!)
In the end I believe that Dropbox was forcing me to reauthorize because my application was in development mode, and had a small user base. When I used the identical code in an app set to production mode, it stopped forcing me to reauthorize. So the “problem” is really a Dropbox security feature, and the solution was just to use production mode.

Related

Is there a way to skip the "Your domain administrator has approved" page in Apps Marketplace Oauth2?

I have a Google Apps Marketplace (v2) app I am working on setting up Oauth2 for.
I've got everything working, but for some reason when I do a redirect to the authentication page, after, after you select which Google account to use (if like you're me and are testing, you have to pick one of several Google accounts you're currently signed into), I get sent to another page which seems utterly pointless:
This is bizarre and annoying, because I am logging in as the domain administrator!
Does anyone know a way to skip this screen, or what I might be doing to be cursed with this terrible user experience?
I just confirmed that having access_type=offline will always display this page, even with approval_prompt=auto. You will always get back a refresh token as well.
The only way to hide it is to remove access_type=offline on future login requests (ask only on signup).
I believe this shows up only if app requests refresh token for offline access. Also this should only appear first time you access the app after installation.
In order to skip this you need to update app to not request refresh tokens.

Mobile app: Persistent login (with two authentication method)

I am designing a mobile app which has the following features:
The first time a user opens the app it is ask to authenticate himself to the app web service by signing in/up using a classical username/password schema or to use Facebook login.
Then, the next time it opens the app, the user won't have to enter its credential again and is automatically sign in.
The first authentication method is implemented. The web service sends back an authentication token that the user use to authenticate himself. The latter is stored together with the user ID in a non-volatile (protected) storage of the mobile.
I know lots of apps provide the two authentication method we are talking about. I was wondering how it is usually combine with the Facebook authentication. At the moment, I was thinking of generating credentials after Facebook login and authenticating Facebook users to my web service as if they were classical users. The users would be stored in the same web-service database table. Note that a flag in the database would tell us whether the user used Facebook or not for login, for if a user logs with the same Facebook account (identified by e-mail) on another device there won't be duplicate.
EDIT: Moreover, some apps let Facebook user to play with their Facebook friends for instance, but how is it done in a persistent manner since one can only have a temporary access token to query Facebook API ? More generally, how some apps do to keep the FB session persistent?
Do you think it is viable?
Facebook Access Tokens are of two types: short term and long term ones. You probably have played with the short term ones, but Facebook documentations say [1] that normally mobile apps use the long term one.
Native mobile applications using Facebook's SDKs will get long-lived access tokens, good for about 60 days. These tokens will be refreshed once per day when the person using your app makes a request to Facebook's servers. If no requests are made, the token will expire after about 60 days and the person will have to go through the login flow again to get a new token.
iOS Facebook SDK [2] has a sample about maintaining session, sample is coming in the installation package of the bundle. (Same code also at GitHub[3].) Here is the most essential part from the GitHub one:
SLAppDelegate *appDelegate = [[UIApplication sharedApplication]delegate];
if (!appDelegate.session.isOpen) {
// Open new session
}
Once the session is restored / found active with isOpen, there is no line of code in the example to refresh it. I am not an iOS programmer but for me that quoted paragraph from documentation and that code snippet from tutorial show I think clearly, that no other action to refresh is even needed, only successful use within about 60 days.
In short, you cannot have a permanent token lasting forever, but luckily enough you have almost one, if you just keep your users using the app in enough frequent manner.
[1] https://developers.facebook.com/docs/facebook-login/access-tokens
[2] https://developers.facebook.com/docs/ios/sample-apps#sdk
[3] https://github.com/Citrrus/facebook-ios-sdk/tree/master/samples/SessionLoginSample

How to handle authorizing the same third-party application multiple times for a single user account?

I'm working on a cloud-storage API, authorized via OAuth. Users of third-party applications can permit said application to access their files/data via our RESTful API.
Currently, we are limiting a third-party app access to a users account once. E.g., the Access Token table has a UNIQUE on the consumer column and the user column. This makes sense at first glance, as the user should never be sent to our service to authorize a third-party application twice, since the third-party would already know their user is already tied to our service and wouldn't need to be re-authorized.
However, what if this user has two accounts on the third-party app, and they want said app to connect to their single account on our service twice? This seems likely, given the prevalence of multiple accounts on services such as Reddit.
Here are the possible solutions I've come up with so far, none of them being perfect:
Display an error during the second auth request: This seems like a frustrating experience for the user, a "cop out" of sorts.
Delete the previous token: This would likely annoy the user, as their previous accounts stop working. Even if we display a warning, it would likely be hard to explain what exactly is happening.
Return the same access token as the first request: Each time the access is requested, a set of permissions are also passed along. The permissions for the second request could be different than the permissions for the first request. Also, not sure if this will violate the OAuth spec, as the secondly generated Request Token isn't tied to the Access Token properly.
Allow two to be generated: This would be confusing, as when the user visits their screen full of authorized applications to revoke one, they don't know which authorization is tied to which third-party account. We could ask for an optional third-party username parameter when the Request Token is generated to identify the different auth's (we currently ask for a non-OAuth-standard permission parameter already). But, this seems like it wouldn't be used by 99% of developers and could make application development more confusing.
What is the best way to handle this situation? Is there a standardized practice for handling this use-case?
I think your last case is the right way to go - Allow two to be generated
When the user visits his screen full of authorized application, it's not necessary to show him one and the same Application twice - you just have to delete the tokens associated with the app if the user revokes application access. That is, all his authorizations to the app with all tokens will go away with the revoke, which is fine.

Soundcloud as Oauth Provider: How to make it connect only one time

I'm currently implementing an Oauth consumer service which is going to use Soundcloud as an Oauth service provider as well. But I'm having the following issue with it: Taking Facebook or Twitter example, you go there, you sign in, you fill up the permission form, and you are redirected back to your app. If you go there a second time, and given you are already sign in, you basically skip all steps and are redirected back instantly. That means, Facebook recognized that you already gave permission to that 3rd party service, so it doesn't ask your permission constantly.
And that's what's happening when I use Soundcloud. Basically everytime I redirected the user to the Soundcloud Oauth connect endpoint, the permission form always shows up, even though I already gave permission to that 3rd party service previously. I'm forced to press "connect" every single time, which is a drag from the user perspective (how many times can you give permission to the same entity). My question is: is there a parameter I can use to make soundcloud recognize/validate the previous permission from the user account to that specific 3rd party service? Or is this Soundcloud Oauth design implementation and we have to live with it?
Edit:
Maybe this wasn't clear, but each time I press "connect" in soundcloud, a new access token is being generated and delivered. Since my app uses this access token to identify its users, it doesn't work very well for me that the access token is getting updated everytime I want to log in, making me effectively "sign up" everytime. To sum it up, I want to get the previously attributed token to my account, so I can look up in my database, identify it and log him in.
I'm also looking for a solution which doesn't involve storing state in the client that might get cleaned up.
What you can do is store the user's oauth token in local storage and reuse it in future sessions. That's what happens on soundcloud.com.
A longer explanation:
When you use the Connect flow, the user is authenticated by SoundCloud (either by using username/password, Facebook Connect, or an already-existing session on soundcloud.com), and then when it is successful, your app is given an oauth token for that user. This is passed to the callback page which is registered for your app.
That token is the only piece of information needed to have the user be "logged in". Unless the token expires (by time, or by the user manually revoking it), then you can reuse that in future sessions.
I think I'm a bit confused about your application's design: where and how is the oauth token being used? I think that instead of using the token as an identifier, perhaps the user's permalink might be better? If you have the oauth token, you can find out the permalink by querying api.soundcloud.com/me.

omniauth - is there any reason why I should store the OAuth2 token in db?

So, I'm just starting to use omniauth and have gotten it working with facebook. I have set it up so that it automatically redirects back to facebook for a new token when the current token expires. Based upon that, is there any reason why I should be storing the token to the db? I currently log user accesses but don't really see any value in logging the token. Would appreciate any ideas on why I should.
thx
Depends on your business logic. For example, do you need to access the user's Facebook details at a later time, even when he is logged out? Or if you are queuing tasks (i.e. running this in the background), do you need to post to his wall a few hours later, instead of this very instant?
Another reason I can think of, is. Do you require your app to obtain a new token via Facebook all the time when the user needs to interact to Facebook via your app? Or would you like to store these tokens in your app, so the user does not need to go through the same process over and over?
It all depends on the kind of user experience you are trying to deliver.

Resources