Tuesday 24 August 2021

Auth Simple for Streamlit

This blog has moved to Medium.

I liked the simplicity of the username/password database authentication solution in this post (by madflier) over in the Streamlit discussion forum. I thought I'd have a go at making it more flexible and possibly production ready. My thought is contrary to madflier's objectives around simplicity, but since I've seen a lot of requests for simple database-backed authentication in the Streamlit discussion forum I felt it was worth the effort to take his solution one step further. I'm honored to be a member of Streamlit's Creators group and I the opportunity to work on my ideas in a recent Streamlit internal hackathon. Apologies to madflier! :-)

As a side note, I've already implemented a Streamlit component for Auth0 Authentication. That's definitely the way to go, but feel that the Streamlit community has been a little hesitant to take it up. Perhaps it's considered to be something for use in big enterprise applications? That's not my experience, given how easy it is to use Auth0. Streamlit components can get complicated and require separate Streamlit and web apps to make them work. So, perhaps something with fewer moving parts is more palatable for most folks (a) getting started with Streamlit, and (b) needing authentication to boot?

I've redesigned the original solution and added the following functionality:

  • Session state support so logins survive a Streamlit's top-down reruns which occur in it's normal execution.
  • Support for logoutauthenticated check, and a requires_auth function decorator to protect areas of your own apps, e.g. secure pages in a multi-page Streamlit application.
    • See how requires_auth is used to secure superuser functions in auth.py. You can do the same in your code.
  • Built-in authentication/login status header widget that will sit nicely in most Streamlit apps.
  • Refactored the SQLite local DB dependency in the main auth module so it uses a DB provider design pattern implementation.
  • Given the refactoring, I added a simple factory for multiple provider implementations, so different persistence technologies could be used, for example a cloud DB.

    • In fact, I built an Airtable cloud database provider which can replace SQLite as an alternative.
  • The abstract provider interface is super simple and should allow almost any database to be adapted, and it works fine for this specific auth use case in the implementations I created.

    • Some Streamliters have mentioned Google Sheets and Firebase - yep, they should be easy.
  • Configuration has been externalized for things like database names and locations, cloud service account secrets, api keys, etc. The configuration is managed in a root .env and env.py files, and small Python settings files for the main app (app_settings.py), and each provider implementation (settings.py).
  • There's just enough exception handling to allow you to get a handle on your own extension implementations.
  • I use debugpy for remote debugging support of Streamlit apps, and include a little module that makes it work better with Streamlit's execution reruns.

All code is published under MIT license, so feel free to make changes and please fork the repo if you're making changes and submit pull requests.

No comments:

Post a Comment