Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do i get the web browser password store to remember R/Shiny passwords?

The problem

I have a shiny application that requires user to login to access the underlying dataset.

The username and password are collected from form fields and submitted via a RESTful API on another server to get an access token which is used in future requests. I haven't included those details in this example.

enter image description here

I want to get the web browser to remember the login details and login automatically, but can't quite see how.

What I tried

In my first implementation, the <input type="text" name="username"> and <input type="password" name="password"> plus an actionButton were dynamically added to the page. This forced the user to re-login each time the shiny application was restarted, which was complex for development and unpleasant for users.

I then found https://gist.github.com/kostiklv/968927 which details the conditions for having the web browser remember the password and log in.

Shiny works on one page, so I couldn't have a separate login page (this would generate a new shiny session, discarding the login!).

I have tried various combinations of things, here is the closest I have got. This script correctly fills in a past password, but the user still has to manually hit submit.

Example code

Note that I have a custom hack my shiny in to enable type="password" to be treated the same as type="text". See bottom of question for access to this code

save this code as login.R then run R and type source("login.R")

write("","blank.html") require(shiny) addResourcePath("login",tools:::file_path_as_absolute("./")) runApp(list(   ui=bootstrapPage(     tags$form(action="#",target="loginframe",       tags$input(id="username",type="text",placeholder="Username"),       tags$input(id="password",type="password",placeholder="Password"),       tags$input(id="loginButton",class="btn btn-primary",type="submit",value="Login")     ),     tags$iframe(name="loginframe",src="login/blank.html",style="display:none")   ),   server=function(input, output) {     observe({message(         "username ",input$username,"\n",         "password ",input$password,"\n"     )})   }) ) 

Analysis of what happened

Note that the presence of an html input submit button seems to tell shiny that it should only update the inputs once every submit. Without the submit button shiny updates its inputs every keystroke.

The same is true for shiny's submitButton.

Leaving the form but removing the button allows input$username and input$password to reach the server code, but...

To enable both conventional user login and automated login, I need the button to avoid repeated attempts to authenticate (which might cause problems) for partial usernames and passwords.

Log of what happened

Here are the console logs from the tests

Log with a submit button:

username  password  <enter username AA and password BB> *no update* <hit submit> *browser requests to save password / yes* username A password B <refresh page> username  password * onscreen form inputs are populated * <hit submit> username A password B 

Log without a submit button

Comment out tags$input(id="loginButton",class="btn btn-primary",type="submit",value="Login") and the preceding comma

note you may want to tell your browser to forget localhost web passwords for now.

username password <enter username AA and password BB> username A password username AA password username AA password B password BB <refresh browser> * onscreen form inputs are not populated * * browser requests to save password * username password <refresh browser> * onscreen form inputs are populated * username password username AA username BB 

Shiny patch to enable password handling:

Install using library(devtools)

install_github("shiny","alexbbrown",ref="password-field") 

Or download and install manually:

https://github.com/alexbbrown/shiny.git (branch password-field) 

Or patch your shiny manually:

index 9b63c7b..15377d8 100644 --- a/inst/www/shared/shiny.js +++ b/inst/www/shared/shiny.js @@ -1336,7 +1336,7 @@    var textInputBinding = new InputBinding();    $.extend(textInputBinding, {      find: function(scope) { -      return $(scope).find('input[type="text"]'); +      return $(scope).find('input[type="text"],input[type="password"]');      },      getId: function(el) {        return InputBinding.prototype.getId.call(this, el) || el.name; 

cf Password field using R Shiny framework

like image 390
Alex Brown Avatar asked Jan 14 '14 18:01

Alex Brown


People also ask

How do I create a shiny login page in R?

Manual steps to build authentication page. Username : myuser Password : mypass Username : myuser1 Password : mypass1 . To change them, you can edit the following code in R program. In order to modify sidebar section, you can edit the following section of code.


2 Answers

I was looking for something similar, and trestletech's fantastic package shinyStore worked for me.

It enables HTML5 client-side data storage for any data in your shiny app.

The github page is here, and an example of how it works is here.

You may wish to read the "Security" section on the README and ensure it is secure enough for your purposes.

like image 51
Hamilton Blake Avatar answered Oct 07 '22 10:10

Hamilton Blake


I believe that you can use postForm() from RCurl package to perform a regular HTTP form submit request (unless Shiny would interfere with this functionality, which is based on using underlying libcurl library). For an example code, please see function srdaLogin() in my R module "getSourceForgeData.R": https://github.com/abnova/diss-floss/blob/master/import/getSourceForgeData.R.

like image 30
Aleksandr Blekh Avatar answered Oct 07 '22 10:10

Aleksandr Blekh