MarkEdmondson1234 / googleAuthR

Google API Client Library for R. Easy authentication and help to build Google API R libraries with OAuth2. Shiny compatible.
https://code.markedmondson.me/googleAuthR
Other
175 stars 51 forks source link

Deploying a Shiny app using gar_shiny_ui to shinyapps tries to redirect to localhost (and fails) #136

Closed gilliganondata closed 5 years ago

gilliganondata commented 5 years ago

What goes wrong

I have a Shiny app that runs locally, but, when I deploy to shinyapps.io, it gets through the permissions granting on the authentication screens but then redirects to a localhost URL with an error:

localhost refused to connect

The app is at https://gilligan.shinyapps.io/time-normalized/, FWIW. I don't think you'll be able to see much there.

Steps to reproduce the problem

Things I think I've done correctly, but which I suspect hold the key to the issue:

A fully reproducible example might be a bit cumbersome. But, the relevant (I'm pretty sure) flow of the code is as follows:

library(shiny)
library(googleAuthR)

gar_set_client(web_json = "ga-web-client.json",
               scopes = c("https://www.googleapis.com/auth/analytics.readonly"))

library(googleAnalyticsR) 
library(tidyverse)

# If I *don't* include this, then the app -- when deployed to shinyapps.io -- immediately
# halts (grays out) as soon as it loads with the "Login" button.  
gar_auth(".httr-oauth")

## ui.R
ui <- fluidPage(title = "Time-Normalized Pageviews"
[additional UI code]
:

## server.R
server <- function(input, output, session){

  gar_shiny_auth(session)
  view_id <- callModule(authDropdown, "auth_menu", ga.table = ga_account_list)
[additional server code]
:
}

shinyApp(gar_shiny_ui(ui, login_ui = gar_shiny_login_ui), server)

When I deploy the app, I'm deploying three files (all of which are in the same directory):

deployApp(appFiles = c("app.R", "ga-web-client.json", ".httr-oauth"), appName = "time-normalized", appTitle = "Google Analytics - Time-Normalized Pageviews")

Session Info

R version 3.5.1 (2018-07-02)
Platform: x86_64-apple-darwin15.6.0 (64-bit)
Running under: macOS  10.14.1
googleAnalyticsR_0.5.0.9000 shiny_1.1.0
googleAuthR_0.7.0

I don't think this is a bug. I think I've just failed to quite put everything in its proper place and am having a hard time figuring out what exactly applies from the various notes and posts (there seems to be a bit more posted on the JS authentication option, but I'm trying to avoid that if possible).

MarkEdmondson1234 commented 5 years ago

Hi Tim,

I would remove gar_auth(".httr-oauth") as that will confuse things, only letting you authenticate for one user.

This is most likely related to an issue with shinyapps.io where it does not load the options set on loading the package, including your client ID/secret etc. Some discussion in this thread https://github.com/MarkEdmondson1234/googleAuthR/issues/74 which advises to set those arguments in an .Renviron file instead.

gilliganondata commented 5 years ago

Thanks, Mark! I made some updates, and I'm back to having the app error out as soon as it loads.

The shinyapps.io log:

2018-12-31T14:40:57.280305+00:00 shinyapps[624885]: Listening on http://127.0.0.1:37324
2018-12-31T14:41:03.170269+00:00 shinyapps[624885]: Warning: Error in : Authentication options didn't match existing session token and not interactive session
2018-12-31T14:41:03.170273+00:00 shinyapps[624885]:            so unable to manually reauthenticate
2018-12-31T14:41:03.175500+00:00 shinyapps[624885]:   88: stop
2018-12-31T14:41:03.175502+00:00 shinyapps[624885]:   87: make_new_token
2018-12-31T14:41:03.175508+00:00 shinyapps[624885]:   79: ga.table
2018-12-31T14:41:03.175508+00:00 shinyapps[624885]:   78: <reactive>
2018-12-31T14:41:03.175503+00:00 shinyapps[624885]:   86: gar_auth
2018-12-31T14:41:03.175504+00:00 shinyapps[624885]:   85: get_google_token
2018-12-31T14:41:03.175505+00:00 shinyapps[624885]:   84: _f
2018-12-31T14:41:03.175505+00:00 shinyapps[624885]:   82: cachedHttrRequest
2018-12-31T14:41:03.175506+00:00 shinyapps[624885]:   81: memDoHttrRequest
2018-12-31T14:41:03.175507+00:00 shinyapps[624885]:   80: acc_sum
2018-12-31T14:41:03.175509+00:00 shinyapps[624885]:   62: pList
2018-12-31T14:41:03.175537+00:00 shinyapps[624885]:   13: runApp
2018-12-31T14:41:03.175510+00:00 shinyapps[624885]:   56: <observer>
2018-12-31T14:41:03.175539+00:00 shinyapps[624885]:   12: fn
2018-12-31T14:41:03.175540+00:00 shinyapps[624885]:    7: connect$retry
2018-12-31T14:41:03.175541+00:00 shinyapps[624885]:    6: eval
2018-12-31T14:41:03.175542+00:00 shinyapps[624885]:    5: eval

This was what I was seeing that led me to (erroneously) add in the gar_auth(".httr-oauth") line (which I've removed.

From reading through #74 , what I did was put an .Renviron in the same directory as my Shiny app. It looks like:

GAR_WEB_CLIENTID="XXXXXXXXXXX-XXXXXXXXXXb4vu05mergi9hbohnm.apps.googleusercontent.com"
GAR_WEB_CLIENT_SECRET="XXXXXXXXXXXXXXsI2StNT"
GAR_SCOPES="https://www.googleapis.com/auth/analytics.readonly"

I removed the gar_set_client() call (because environment variables with the names above automatically get picked up by googleAnalyticsR, right?).

I removed the gar_auth(".httr-oauth") call.

So, my app now looks like:

library(shiny)
library(googleAuthR)
library(googleAnalyticsR)  
library(tidyverse)

## ui.R
ui <- ...

(This runs fine locally.)

My deploy script:

deployApp(appFiles = c("app.R", ".Renviron"),
          appName = "time-normalized",
          appTitle = "Google Analytics - Time-Normalized Pageviews")

I tried deploying both with and without a .httr-oauth file with the same results.

Did I misunderstand something in the workaround to shinyapps.io not reading options?

Thanks for your help!

gilliganondata commented 5 years ago

I feel like there are either multiple options for setting options, or I'm just struggling to figure out some shorthand. I've tried a number of different permutations -- always following the same process before deploying to shinyapps.io:

  1. Restarting R
  2. Deleting any .httr-oauth files
  3. Running locally and confirming that the Google project for which permission is being checked is not the default googleAnalyticsR and, instead, is the one I've set up.

I've uncovered a number of ways that I feel like I'm guessing.

Credentials: Web application vs. Other

I've got two sets of credentials set up: a "Web application" on and an "Other" one. Do I need both? I've started including options for both, and it seems like the "Other" one is the one that I'm getting prompted to provide permissions for when I run the app locally.

Setting the client ID(s), secret(s), and scope

I've created 5 variables in a .Renviron file that I'm uploading with app.R when I deploy my app to shinyapps.io.

GAR_WEB_CLIENTID="[Web application client ID]"
GAR_WEB_CLIENT_SECRET="[Web application client secret]"
GAR_CLIENTID="['Other' client ID]"
GAR_CLIENT_SECRET="['Other' client secret]"
GAR_SCOPES="https://www.googleapis.com/auth/analytics.readonly"

I'm not entirely sure I'm then accessing those values correctly. I'd thought at one point that, if they existed with those specific names in the .Renviron file that googleAuthR would load them in automatically without needing to actually set any options. But...no?

So, my code looks like this:

library(googleAuthR)

# Should it be this...
options("googleAuthR.client_id" = Sys.getenv("GAR_CLIENTID"))
options("googleAuthR.client_secret" = Sys.getenv("GAR_CLIENT_SECRET"))
options("googleAuthR.webapp.client_id" = Sys.getenv("GAR_WEB_CLIENTID"))
options("googleAuthR.webapp.client_secret" = Sys.getenv("GAR_WEB_CLIENT_SECRET"))
options("googleAuthR.scopes.selected" = Sys.getenv("GAR_SCOPES"))

# ...or this? I've tried both, as well as included both -- figuring I would start removing different bits if
# and when I got it working.
options(googleAuthR.client_id = Sys.getenv("GAR_CLIENTID"),
        googleAuthR.client_secret = Sys.getenv("GAR_CLIENT_SECRET"),
        googleAuthR.webapp.client_id = Sys.getenv("GAR_WEB_CLIENTID"),
        googleAuthR.webapp.client_secret = Sys.getenv("GAR_WEB_CLIENT_SECRET"),
        googleAuthR.scopes.selected = Sys.getenv("GAR_SCOPES"))

library(googleAnalyticsR) 

To upload .httr-oauth or not?

I think I shouldn't need/want to upload .httr-oauth, as that's the auth to actually access the data. But, I've tried both ways with no luck.

The error in shinyapps.io

I continue to see the "...didn't match existing session token..." error in the shinyapps.io logs:

2018-12-31T18:23:20.024181+00:00 shinyapps[624885]: Listening on http://127.0.0.1:41153
2018-12-31T18:23:27.146474+00:00 shinyapps[624885]: Warning: Error in : Authentication options didn't match existing session token and not interactive session
2018-12-31T18:23:27.146477+00:00 shinyapps[624885]:            so unable to manually reauthenticate
2018-12-31T18:23:27.151985+00:00 shinyapps[624885]:   89: stop
2018-12-31T18:23:27.151987+00:00 shinyapps[624885]:   88: make_new_token
2018-12-31T18:23:27.151989+00:00 shinyapps[624885]:   87: gar_auth
2018-12-31T18:23:27.151989+00:00 shinyapps[624885]:   86: get_google_token
2018-12-31T18:23:27.151990+00:00 shinyapps[624885]:   85: _f
2018-12-31T18:23:27.151991+00:00 shinyapps[624885]:   83: cachedHttrRequest
2018-12-31T18:23:27.151991+00:00 shinyapps[624885]:   82: memDoHttrRequest
2018-12-31T18:23:27.151992+00:00 shinyapps[624885]:   80: gar_api_page
2018-12-31T18:23:27.151993+00:00 shinyapps[624885]:   79: ga.table
2018-12-31T18:23:27.151994+00:00 shinyapps[624885]:   78: <reactive>
2018-12-31T18:23:27.151992+00:00 shinyapps[624885]:   81: f
2018-12-31T18:23:27.151994+00:00 shinyapps[624885]:   62: pList
2018-12-31T18:23:27.151995+00:00 shinyapps[624885]:   56: <observer>
2018-12-31T18:23:27.151995+00:00 shinyapps[624885]:   13: runApp
2018-12-31T18:23:27.151996+00:00 shinyapps[624885]:   12: fn
2018-12-31T18:23:27.151997+00:00 shinyapps[624885]:    7: connect$retry
2018-12-31T18:23:27.151997+00:00 shinyapps[624885]:    6: eval
2018-12-31T18:23:27.151998+00:00 shinyapps[624885]:    5: eval

I appreciate your help! My hope is that I'll get to something that is clean and reliable and I won't just be embarrassed for having opened this issue.

MarkEdmondson1234 commented 5 years ago

Oh is it only using your own GA data? In that case just upload the auth file you have locally, and no need for any Shiny specific auth at all :) call ga_auth() as you would locally.

gilliganondata commented 5 years ago

The intention is to have it allow a user to authenticate and then use their own data. I'm pretty sure I just got lost in a series of troubleshooting posts and took that wrong turn. So... I definitely don't want to be uploading a httr-oauth, it sounds like? (That seems so obvious in hindsight.) But, I'm still stuck when it comes to getting shinyapps.io to allow authentication -- it just crashes out immediately with the Error in : Authentication options didn't match existing session token and not interactive session so unable to manually reauthenticate error.

MarkEdmondson1234 commented 5 years ago

I think for now use the older methods or JavaScript authentication, it seems shinyapps.io needs some special configurations I will do on googleAuthR end to fix it. Sorry about that, its a bug as I guess shinyapps.io is a popular platform, it works on my local Shiny server but not shinyapps.io specifically.

I've confirmed the older methods work though with shinyapps.io still. e.g.

#server 
library(shiny)
library(googleAuthR)
library(googleAnalyticsR)

options(shiny.port = 1221) # for local testing
options(googleAuthR.webapp.client_id = "xxx") # web application client id
options(googleAuthR.webapp.client_secret = "xxxx")
options(googleAuthR.scopes.selected = c("https://www.googleapis.com/auth/analytics.readonly"))

function(input, output, session){

  #####--------- Setup

  token <- callModule(googleAuth, "login")

  ga_accounts <- reactive({
    validate(
      need(token(), "Authenticate")
    )

    with_shiny(google_analytics_account_list, shiny_access_token = token())
  })

etc..

and

#ui 
library(shiny)
library(googleAuthR)
library(googleAnalyticsR)

navbarPage("GA v4 API",
           tabPanel("Setup", tabName = "setup", ,
                    googleAuthUI("login"),
                    authDropdownUI("auth_menu")
           ),
etc.
MarkEdmondson1234 commented 5 years ago

But, it does work now with the new method if the latest version of googleAuthRis installed: you just have to specify the redirect yourself in a new option. The below works, note the new googleAuthR.redirect option which should be set to the same URL you put in the Google project redirect origin field.

This is live at this URL: https://mark.shinyapps.io/googleAnalyticsR_test_deployment/

library(shiny)
library(googleAuthR)
library(googleAnalyticsR) 

gar_set_client(web_json = "ga-web-client.json",
               scopes = "https://www.googleapis.com/auth/analytics.readonly")

options(googleAuthR.redirect = "https://mark.shinyapps.io/googleAnalyticsR_test_deployment/")

## ui.R
ui <- fluidPage(title = "googleAnalyticsR Test Deployment",

      authDropdownUI("auth_menu"),
      textOutput("viewid"),
      textOutput("client_id")

)

## server.R
server <- function(input, output, session){

  gar_shiny_auth(session)

  al <- reactive(ga_account_list())
  view_id <- callModule(authDropdown, "auth_menu", ga.table = al)

  output$viewid <- renderText(view_id())

  output$client_id <- renderText(getOption("googleAuthR.webapp.client_id"))

}

shinyApp(gar_shiny_ui(ui, login_ui = silent_auth), server)
gilliganondata commented 5 years ago

That did it -- updated to match your example, installed googleAuthR from Github (0.7.0.9000), and it's now working!

Thanks, Mark!!!

On Tue, Jan 1, 2019 at 1:06 PM Mark notifications@github.com wrote:

But, it does work now with the new method, you just have to specify the redirect yourself in a new option. The below works, note the new googleAuthR.redirect option which should be set to the same URL you put in the Google project redirect origin field

library(shiny) library(googleAuthR) library(googleAnalyticsR) library(tidyverse)

options(googleAuthR.webapp.client_id = "1080525199262-qecndq7frddi66vr35brgckc1md5rgcl.apps.googleusercontent.com", googleAuthR.webapp.client_secret = "3nVkQuvrooNO8t2OId4Vtha4", googleAuthR.scopes.selected = "https://www.googleapis.com/auth/analytics.readonly", googleAuthR.client_id = "1080525199262-outv8jk106qla9e9n03pfrcclqkk7vsa.apps.googleusercontent.com", googleAuthR.client_secret = "BJ_B0TMcr9NtTa8zYIgP5y0K", googleAuthR.verbose = 1, googleAuthR.redirect = "https://mark.shinyapps.io/googleAnalyticsR_test_deployment/") log_option <- function(x){ cat("\n Option: ",x, " ",getOption(x)) }

ui.Rui <- fluidPage(title = "googleAnalyticsR Test Deployment",

  authDropdownUI("auth_menu"),

  textOutput("viewid"),
  textOutput("client_id")

)

server.Rserver <- function(input, output, session){

gar_shiny_auth(session)

al <- reactive(ga_account_list()) view_id <- callModule(authDropdown, "auth_menu", ga.table = al)

output$viewid <- renderText(view_id())

output$client_id <- renderText(getOption("googleAuthR.webapp.client_id"))

} log_option("googleAuthR.client_id") log_option("googleAuthR.webapp.client_id")

shinyApp(gar_shiny_ui(ui, login_ui = silent_auth), server)

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/MarkEdmondson1234/googleAuthR/issues/136#issuecomment-450747202, or mute the thread https://github.com/notifications/unsubscribe-auth/ASf4p9wq-htZfykKyAmqlDuSgKPRF2-Fks5u-6O-gaJpZM4ZlKog .