Search code examples
rdropbox-apirdrop2

Get a refresh token for Dropbox API using rdrop2 and drop_auth()


I'm trying to create a shiny app which links to my dropbox using the package rdrop2.

I have successfully managed to deploy the app and it runs as planned for around 4 hours. However, I need long lasting offline access. Dropbox help pages say that I'll need a 'refresh token'.

Currently to get my token I am using:

library(rdrop2)
token <- drop_auth() # gets credentials

saveRDS(token, "droptoken.rds") # saves credentials


token<-readRDS("droptoken.rds") # read in credentials

drop_auth(new_user = FALSE,
          cache = TRUE,
          rdstoken = "droptoken.rds")

ui <- # some UI code



server <- function(input, output,session) {
  # some server code
}

shinyApp(ui = ui, server = server)

This creates a token that has a 'sl.' access token (short lived) which expires_in 14400, which is 4 hours. After 4 hours, the app no longer works due to an 'Unathorised HTTP 401' error.

Could anyone provide me help on how to adapt this code to obtain a refresh token?

NB: dropbox no longer allow tokens with no expiry (as of September 2021) so I need to go down the refresh token route.


Solution

  • I don't know if you still need help but I was recently tasked to address this issue in my internship program and managed to find a solution.

    Currently, rdrop2's drop_auth() function will generate a token with these credentials: <credentials> access_token, token_type, expires_in, uid, account_id. Since access tokens last only 4 hours now, we will need a refresh token as a part of our credentials so that we may get a new access token every time it expires.

    To generate a token object with a refresh token, we will need to modify the authorization endpoint inside the drop_auth() function. This will look something like this:

    library(rdrop2)
    
    .dstate <- new.env(parent = emptyenv())
    
    drop_auth_RT <- function (new_user = FALSE, key = "mmhfsybffdom42w", secret = "l8zeqqqgm1ne5z0", cache = TRUE, rdstoken = NA) 
    {
      if (new_user == FALSE & !is.na(rdstoken)) {
        if (file.exists(rdstoken)) {
          .dstate$token <- readRDS(rdstoken)
        }
        else {
          stop("token file not found")
        }
      }
      else {
        if (new_user && file.exists(".httr-oauth")) {
          message("Removing old credentials...")
          file.remove(".httr-oauth")
        }
        dropbox <- httr::oauth_endpoint(authorize = "https://www.dropbox.com/oauth2/authorize?token_access_type=offline",
                                        access = "https://api.dropbox.com/oauth2/token")
        # added "?token_access_type=offline" to the "authorize" parameter so that it can return an access token as well as a refresh token
        dropbox_app <- httr::oauth_app("dropbox", key, secret)
        dropbox_token <- httr::oauth2.0_token(dropbox, dropbox_app, 
                                              cache = cache)
        if (!inherits(dropbox_token, "Token2.0")) {
          stop("something went wrong, try again")
        }
        .dstate$token <- dropbox_token
      }
    }
    
    refreshable_token <- drop_auth_RT()
    

    This will generate a token with these credentials: <credentials> access_token, token_type, expires_in, refresh_token, uid, account_id. The new token will now have a refresh token that the HTTP API can use to automatically refresh the access token.

    It is very important that you specify the new token when calling rdrop2 functions, otherwise it will not work. Example:

    > drop_dir()
    Error in drop_list_folder(path, recursive, include_media_info, include_deleted,  : 
      Unauthorized (HTTP 401).
    > drop_dir(dtoken = refreshable_token)
    # A tibble: 4 x 11
      .tag   name      path_lower path_display id    client_modified server_modified rev      size
      <chr>  <chr>     <chr>      <chr>        <chr> <chr>           <chr>           <chr>   <int>
    1 folder Screensh~ /screensh~ /Screenshots id:_~ NA              NA              NA         NA
    

    Hope this helps!