Search code examples
authenticationmeteortokenserver-sidedropbox-sdk-js

How to achieve the Dropbox equivalent of long-lived token now that they're gone (dropbox-sdk-js, Meteor, React)


For a while now I've been using dropbopx-sdk-js in a Meteor application without any trouble.

My Meteor app simply uses Dropbox to fetch images to be used in product cards. These files are synced now and then and that's it. By synced what I mean is they are scanned, shared links created or obtained, and some info is then saved in Mongo (name, extension, path, public link)

End users do not remove nor add files, nor are the files related to an end user specific account.

To achieve this, I created (in the far past) an App in the Dropbox App Console, generated a permanent token, and used that token in my Meteor app to handle all the syncing.

Now I've tried to replicate that very same thing in a new similar project, but found that the permanent tokens have been recently deprecated and are no longer an option.

Now, checking Dropbox's Authentication Types it seems to me like "App Authentication"

"This type only uses the app's own app key and secret, and doesn't identify a specific user or team".

is what I'm after. I can safely provide app key and secret in the server exclusively, as the client will never need those. The question is how do I achieve such kind of authentication? Or for that matter, how do I achieve an equivalent of the long-lived token for my app, ultimately meaning that end users don't actually need to know Dropbox is behind the scenes in any way (and they surely don't need dropbox accounts to use this app nor should be prompted with any Dropbox authentication page)

In the js-sdk examples repo, I only found this example using app key and secret. Yet afterwards it goes through the oauth process in the browser anyways. If I don't do the oauth part, I get an error

"error": {
    "name": "DropboxResponseError",
    "status": 409,
    "headers": {},
    "error": {
        "error_summary": "path/unsupported_content_type/...",
        "error": {
            ".tag": "path",
            "path": {
                ".tag": "unsupported_content_type"
             }
         }
    }
}

as a result of calling

dbx.filesListFolders({ path: '', recursive: true }):

If I replace the initialization of the dbx object with a generated token everything works out. However eventually the token expires and I'm back in square one.

Any ideas what may I be missing?


Solution

  • The short answer is:

    You need to obtain a refresh-token. You can then use this token for as long as you want. But in order to get it is necessary to go through at least one oauth flow in the browser. Then capturing the generated refresh-token in the backend. Then store it and use it to initialize the API. So it's kind of "hacky" (IMO).

    For example, you can use the mentioned example code, and log/store the obtained refresh token in this line (as per Greg's accepted answer in the forum). Then use that value as a constant to immediately call the setRefreshToken method (as done in that very same line) upon initialization.

    The long answer is:

    1. ClientId + Client secret are not enough to programmatically generate a refresh token.
    2. Going through the oauth flow at least once is mandatory to obtain a refresh token
    3. If you want to hide such flow from your clients, you'll need to do what the short answer says.
    4. The intended flow of usage according to Dropbox is: each user access his own files. Having several users accessing a single folder is not officially supported.

    The longer answer is:

    Check out the conversation we had in the dropbox forum

    I suggested to replace the "Generate Access Token" button in the console for a "Generate Refresh Token" button instead. At least it made sense to me according to what we discussed. Maybe if it gets some likes... ;).