Managing Shiny-Server authentication with Django

Paolo Cozzi
6 min readNov 4, 2020
Photo by Halacious on Unsplash

Deploying web applications in R with shiny

Shiny is an R package which allow building interactive web applications by combining the power of R with the current trends of the modern web. Users can develop web applications directly in R using RStudio, without worrying about Javascripts, CSS and HTML (or at least, with a little knowledge of them). Web applications can then be shared using RStudio products, such as shinyapps.io, which is a SaaS for hosting shiny applications in the cloud, RStudio Connect, which is the main publishing platform made by the RStudio team (formerly known as Shiny Server Pro) and the Shiny Server Open Source, which is a stand alone application for displaying shiny applications on a local machine.

The Shiny Server Open source is the only application that is made free for the community (shinyapps.io has a free plan, but is limited in number of applications and in hours of usage, while RStudio connect is affordable to medium/large organizations), however its features are limited compared to the commercial products made by RStudio: for example the community edition lacks of the authentication features implemented in the other RStudio products, and this is a key feature I need in order to share some projects with a limited number of users.

Adding an authentication layer to Shiny Server Community Edition

I spent a lot of time in understanding how to implement an authentication layer in front of the Shiny Server community edition: the first attempt I made was adding a HTTP Basic Authentication on each shiny application I need to make private. This solution however was not ideal, since this type of authentication is not safe, and passwords are stored in the browser cache during usage. Closing and re-opening the browser requires to start everytime a new authentication and it’s impossible to logout and login again with another user without closing the browser. So I searched authentication alternatives made by the community (I wrote down a small list here), when I found this beautiful guide made by pawamoy on how to use Django as an Authentication layer for Shiny:

This guide has inspired me to do something similar (I had a good experience with Django in another project) and I want to create a more structured project in which I could enhance the solution proposed in the pawamoy guide. So, instead of writing about how the Django authentication works with shiny (I think that pawamoy explains those details better than me, I suggest you to read his guide), I want to explain how I added more features in my Django-Shiny authentication project.

Enhancing the Shiny — Django authentication layer

In my mind, I want to structure the authentication layer in a better way. Ideally I want to:

  1. Structure the project with docker-compose
  2. Ensure authentication per application
  3. Direct access to the shiny application (without the django container but with authentication)
  4. Customize the layout

1. Structuring the project with docker-compose

Instead to install all required stuff on a local machine, I prefer to organize my project with docker compose. This is easier to maintain (for example, if I need to update the R version) and keeps images shorter (consider that the R based image needs a lot of packages to work properly in different situations). If I need to clean-up my shiny-server installation, I could easily remove a docker image instead of search-and-clean every single package I’ve installed.

By sharing volumes between container, I could set a NgINX container as the frontend application (which forwards request to the backend and can serve static content itself). Shiny and Django containers (with the database) are part of the backend and are linked to the NgINX container since they are not accessible from the outside. By defining an .env configuration file, I could define passwords and runtime specific variables required by the application (like the django SECRET_KEY) which can’t be tracked in GitHub. Image are pre-builded and loaded into Docker Hub in order to save time with CI tests and for a faster installation on production environment. Here is an extract of docker-compose.yml file:

shiny-server docker-compose example

2. Ensuring authentication per application

In my project, I want to be able to add a new shiny application without modifying configuration files. In order to do this, the shiny application need to be managed entirely by django: the shiny application location and ownership need to be managed in models in order to exploit the django Class-based Views. In the following example, the application ownership is determined using a ManyToMany relationship with the default django-auth User model, while the application location is a CharField in which we indicate the application location where we put shiny code inside the docker-compose project folder:

shiny-server django models.py

This allows to add a new application using the default django-admin application (however the shiny application code need to be placed manually in the project folder, for the moment. I plan to add a custom django FormView in order to upload code using the admin). The location field in this case will also be part of the final URL which will be served by the Shiny Server docker-compose application:

add a new shiny application using django-admin

By customizing the django views.py, I could customize how applications could be displayed: a public application is available to everyone, even anonymous users; superuser can always display the applications while logged user can see applications only if they own them. In the following example, by inheriting the UserPassesTestMixin from django-auth modules, a generic View can be displayed only if a custom test_func(self) method returns True:

shiny-server django views

3. Direct access to the shiny application

Like the Shiny — Gallery, I want to be able to display the shiny application outside the django container application view: this allows to display an application alone in the browser page. The example below enhance the pawamoy solution and give to the authorization url the same behaviour described in the django view (which embeds the shiny application) described above:

shiny-server: direct access to shiny applications using django

The previous code works together with the following NgINX configuration block: every direct access to shiny application need to be tested using django. Moreover, anonymous users are redirected to login and then towards the requested application URL, while not authorized users got a 403 (access denied) page:

shiny-server: nginx.conf

4. Customize the layout

The application layout is determined by using bootstrap with the django-templates files: in such way I can customize the application with a few lines of HTML code:

Conclusion

This guide tries to summarize how I customized a clever solution found on the web by describing the enhancements I implemented. This is not an attempt to substitute the commercial solutions provided by RStudio: this is considered as an exercise in which I can model an authentication layer in front of the Shiny Server Community Edition. There are others features that are available in the commercial editions and should be evaluated carefully: for example the multi threaded support and the better resource management which let you to scale your applications and support a very large community. Moreover the support that RStudio can provide to their customers will be better than the support given to a simple open-source project and should be carefully considered if you need to provide shiny applications to your partners or customers.

If you want to learn more, the full application is available in GitHub:

While a more user-oriented guide on how to install the whole application and add a shiny application can be found in the GitHub — Wiki of the project:

If you liked this article, feel free to make a comment or make a clap. See you for another amazing-super complicated guide!

--

--