5

I'm attempting to retrieve a cookie from a user's browser in a shiny app to produce a different UI for different users. To work with cookie sin R shiny, I've followed this tutorial and I've extended shinyjs with the following javascript code:

shinyjs.getcookie = function(params) {
    var cookie = Cookies.get("id");
    if (typeof cookie !== "undefined") {
        Shiny.onInputChange("jscookie", cookie);
    } else {
        var cookie = "";
        Shiny.onInputChange("jscookie", cookie);
    }
}
shinyjs.setcookie = function(params) {
    Cookies.set("id", escape(params), {
        expires: 0.5
    });
    Shiny.onInputChange("jscookie", params);
}
shinyjs.rmcookie = function(params) {
    Cookies.remove("id");
    Shiny.onInputChange("jscookie", "");
}

I'm also using attempting to set and get the cookie within a R Shiny module, which may be significant.

I'm able to set the cookie from within the module, I can verify this from my browser; however, when I try and get the cookie, I consistently get NULL.

I call the module in server.R like this:

  user_auth_return <- observe({
    callModule(
      user_auth_module,
      "user_auth"
    )
  })

And here is the module itself:

user_auth_module <- function(input, output, session) {
  print("1")

  # Initializing reactive values.
  values <- reactiveValues(
    passwords = data.frame(matrix(nrow = 0, ncol = 2)),
    cookies = data.frame(matrix(nrow = 0, ncol = 2)),
    cookies.match = FALSE,
    user = NULL,
    password.error = FALSE
  )

  # Setting new cookie.
  observeEvent(input$login, {
    print("5")

    # Reading in pasword table.
    try(values$passwords <- read.csv("data/passwords.csv", header = FALSE, quote = "", stringsAsFactors = FALSE))

    # Checking if match exists for username-password pair.
    if (input$username != "" &&
        input$username %in% values$passwords[, 1] &&
        checkpw(input$password, hash = values$passwords[values$passwords[, 1] == input$username, 2])) {
      print("6")
      # Creating random session ID.
      sessionid <- paste(
        collapse = '',
        sample(x = c(letters, LETTERS, 0:9), size = 64, replace = TRUE)
      )

      sessionid <- "cookie123"
      # Setting new cookie to session ID.
      print("setting cookie")
      js$setcookie(sessionid)

      # Updating user cookie if already present, otherwise, creating new username-cookie pair.
      if (input$username %in% values$cookies[, 1]) {
        print("7")
        values$cookies[values$cookies[, 1] == input$username, 2] <- sessionid
      } else {
        print("8")
        values$cookies <- rbind(values$cookies, c(input$username, sessionid))
      }

      # Writing updated cookie data frame to data file.
      write.table(values$cookies, file = "data/cookies.csv", quote = FALSE, sep = ",", row.names = FALSE, col.names = FALSE)
    } else {
      print("9")
      values$password.error <- TRUE
    }
  })

  # Checking if match exists for cookie.
  observe({

    # Check cookies when input is pressed.
    input$login

    # Reading in cookie table.
    try(values$cookies <- read.csv("data/cookies.csv", header = FALSE, quote = "", stringsAsFactors = FALSE))

    # Getting cookie.
    js$getcookie()

    print("user")
    print(input$jscookie)

    print("database")
    print(values$cookies[, 2])

    # Checking if match exists for cookie.
    if (!is.null(input$jscookie) &&
        input$jscookie %in% values$cookies[, 2]) {
      print("3")
      values$cookies.match <- TRUE
      values$user <- values$cookies[values$cookies[, 2] == input$jscookie, 1]
    } else {
      print("4")
      values$cookies.match <- FALSE
    }
  })

  # Toggling password error message if username/password combination is not found.
  observe({
    print("10")
    toggleState("password.error.message", condition = values$password.error)
  })

  # Toggling between login and logout tab if cookie is present.
  observeEvent(values$cookie.match, {
    print("11")
    hide("login_page")
    show("logout_page", anim = TRUE, animType = "fade")
  })

  # Remove user cookie at logout.
  observeEvent(input$logout, {
    print("12")
    js$rmcookie()
  })

  # Returning login status.
  return("return")#values$cookies.match)
}

When I run the module I get the following numbers, showing progression through the program at each print statement:

[1] "1"
[1] "user"
NULL
[1] "database"
[1] "cookie123"
[1] "4"
[1] "10"

And after entering the correct password:

[1] "5"
[1] "6"
[1] "setting cookie"
[1] "7"
[1] "user"
NULL
[1] "database"
[1] "cookie123"
[1] "4"

Any help is appreciated.

EDIT:

I've since found that I am able to retrieve the cookie from server.R using this code:

observe({
    js$getcookie()
    print("server cookie")
    print(input$jscookie)
})

Because I still can't access the cookie using the same code in the module, I think that I've narrowed down my issue to the variable input$jscookie. Would I have to get this value in a different way in a Shiny module compared to on a Shiny server?

J0HN_TIT0R
  • 323
  • 1
  • 13

0 Answers0