curso-r / auth0

Authentication in shinyapps using Auth0 service
https://curso-r.github.io/auth0/
Other
154 stars 21 forks source link

Shiny app goes gray after refresh #54

Open MislavSag opened 4 years ago

MislavSag commented 4 years ago

I set up auth0 authentication, everything works fine on login and log out, but when I click refresh in my browser (Firefox), shiny up goes to gray and it returns an error (from shinyapps.io logs):

2019-10-16T13:08:13.633470+00:00 shinyapps[1335290]: Error in httr::oauth2.0_access_token(api, app(redirect_uri), params$code) : 2019-10-16T13:08:13.628803+00:00 shinyapps[1335290]: Warning: Error in httr::oauth2.0_access_token: Forbidden (HTTP 403). Failed to get an access token. 2019-10-16T13:08:13.633472+00:00 shinyapps[1335290]: Forbidden (HTTP 403). Failed to get an access token.

jtrecenti commented 4 years ago

This is a problem and sadly there's no workaround for now. You need to manually delete the "code=xxx" parameter if you want to refresh your app

MislavSag commented 4 years ago

Maybe it is possible to programmatically delete code part when refreshing the page event occur, using JavaScript?

dfalbel commented 4 years ago

Yeah, you can probably use some client side JS to check if the page has been reloaded. For example: https://stackoverflow.com/questions/5004978/check-if-page-gets-reloaded-or-refreshed-in-javascript

MislavSag commented 4 years ago

Thanks, I will try to implement this JS code.

gbradley commented 4 years ago

For a temporary workaround I used the history.pushState method to update the browser history once the page has loaded. An ugly hack but seems to do the trick.

mohang13 commented 4 years ago

Hi @gbradley can you give me a working example where I can use the same method for my shiny apps. Thanks.

gbradley commented 4 years ago

@mohan1331 Here's what I added:

tags$script(JS("setTimeout(function(){history.pushState({}, 'Page Title', '/');},2000);")),

This simply waits for 2 seconds after the page loads before adding "/" to the browser history stack, meaning the URL parameters are removed without reloading the page.

snestler commented 4 years ago

@gbradley Where in your Shiny app did you put this code? TIA.

mohang13 commented 4 years ago

@snestler This is how I included it in my apps. What @gbradley gave is a Javascript code so we can put it inside tags$head. I like to call my tags at first. So ui <- tagList( tags$head( tags$script(JS("setTimeout(function(){history.pushState({}, 'Page Title', '/application_name');},2000);")) ) This can be followed by your usual UI code. You can replace your application name in the code so that refreshing the page will refresh the app without any error. Thanks, @gbradley this is the first thing I do whenever I create a shiny application with auth0.

snestler commented 4 years ago

@mohang13 I'm still having issues getting this to work. Part of it is my lack of JS knowledge. I'm wondering if it has to do with not having the correct entries for 'Page Title' and '/application_name'. I'm pretty sure I've got the second one right, but am not sure what to put for the first one. Can you provide a specific example for me to reference? Thank you.

mohang13 commented 4 years ago

@snestler I'm attaching a sample shiny application named 'github_app'. As you can see I mentioned the same name in tags$script. Only change the app name (here it is github_app) in your code do not change Page Title (it'll automatically take your page name).

library(shiny)
library(htmlwidgets)

# Define UI for application that draws a histogram
ui <- tagList(
    tags$head(
              tags$script(JS("setTimeout(function(){history.pushState({}, 'Page Title', '/github_app');},2000);"))),
    fluidPage(

        # Application title
        titlePanel("Old Faithful Geyser Data"),

        # Sidebar with a slider input for number of bins 
        sidebarLayout(
            sidebarPanel(
                sliderInput("bins",
                            "Number of bins:",
                            min = 1,
                            max = 50,
                            value = 30)
            ),

            # Show a plot of the generated distribution
            mainPanel(
                plotOutput("distPlot")
            )
        )
    )
    )

# Define server logic required to draw a histogram
server <- function(input, output) {

    output$distPlot <- renderPlot({
        # generate bins based on input$bins from ui.R
        x    <- faithful[, 2]
        bins <- seq(min(x), max(x), length.out = input$bins + 1)

        # draw the histogram with the specified number of bins
        hist(x, breaks = bins, col = 'darkgray', border = 'white')
    })
}

# Run the application 
shinyApp(ui = ui, server = server)

I forgot about calling the library htmlwidgets in my previous answer, usually my other libraries like DT calls it automatically. If you still have trouble let me know.

snestler commented 4 years ago

Thank you. This is helpful; I wasn't including the whole fluidPage inside the tagList. And the library(htmlwidgets) call was part of the issue. I've got it "working" now, in that clicking "Reload" will restart the app, rather than disconnecting from the server.

But, I seem to experience random disconnects when working in the Shiny app when this is enabled. Not sure why that might be. Any insights?

chintanp commented 3 years ago

@snestler What do you mean by random disconnects? Do you see an error in auth0.com logs? Anything printed in your Rstudio session? It would help if you included your code and deployment details like OS, R version etc.

chintanp commented 3 years ago

Also, I had to use: tags$script(htmlwidgets::JS("setTimeout(function(){history.pushState({}, 'Page Title', window.location.pathname);},2000);")). This worked in both development (where pathname = '/') and in production where it is not root.

YO-SC commented 3 years ago

Any workarounds for this issue ? (Besides what @gbradley suggested)

devhawkio commented 3 years ago

This is a pretty important issue to address. Why is it marked wontfix?

lemuelemos commented 3 years ago

The problem of this solution, is that if the user don't logout, the page will be logged forever.

Conengmo commented 1 year ago

I used replaceState instead, so it doesn't add a new entry to the history but replaces the one that has the 'code' parameter.

tags$script(JS(
  "setTimeout(function(){history.replaceState(null, '', '/')}, 2000);"
))
peernisse commented 1 year ago

I will just point out that this hack works,

setTimeout(function(){history.replaceState(null, '', '/myAppName')}, 2000);

but I did encounter a problem where it prevented all my page resources (images, some CSS and JS) from loading when I moved my app to my own Shiny Server instead of shinyapps.io. This flummoxed me for a couple days. I presume the solution to that would be to extend the wait time from 2 seconds to 5, 10 or 20 seconds. Overall I would say that changing the state like this works but causes unexpected behavior and it would be cool if auth0 can figure something out for this. Cheers!

mxmlnmrk commented 1 month ago

This code worked for me as well. Does anyone know about plans to fix this problem in the r auth0 package?

tags$script(JS( "setTimeout(function(){history.replaceState(null, '', '/')}, 2000);" ))