Normally, when I want to provide authentication to a service, I use OAuth2. There are libraries to integrate this authentication mechanism into a web application, but sometimes we cannot do this easily because it is a third-party service over which we have no control. In these cases, it is possible that this third-party service has support for OAuth2 and can also log in with OAuth2. But sometimes this is not possible, or it is too complicated. In these cases, a solution is to use a proxy that handles the authentication and communicates with the third-party service. In this example, we will use a Streamlit application as if it were a third-party application.
import streamlit as st
st.set_page_config(
page_title="Home",
page_icon="👋",
)
st.write("# Welcome to Streamlit! 👋")
st.markdown(
"""
Streamlit is an open-source app framework built specifically for
Machine Learning and Data Science projects.
**👈 Select a demo from the sidebar** to see some examples
of what Streamlit can do!
### Want to learn more?
- Check out [streamlit.io](https://streamlit.io)
- Jump into our [documentation](https://docs.streamlit.io)
- Ask a question in our [community
forums](https://discuss.streamlit.io)
### See more complex demos
- Use a neural net to [analyze the Udacity Self-driving Car Image
Dataset](https://github.com/streamlit/demo-self-driving)
- Explore a [New York City rideshare dataset](https://github.com/streamlit/demo-uber-nyc-pickups)
"""
)
st.sidebar.success("Select a demo above.")
Our Streamlit application has a page.
from random import randint
import streamlit as st
st.set_page_config(
page_title="Hello",
page_icon="👋",
)
st.markdown("# Plotting Demo")
st.sidebar.header("Plotting Demo")
st.write("This demo illustrates a combination of plotting with Streamlit. Enjoy!")
data = [dict(name=f"name{i}", value=randint(1, 1000)) for i in range(1, 101)]
progress_bar = st.sidebar.progress(0)
status_text = st.sidebar.empty()
chart = st.line_chart([item['value'] for item in data])
progress_bar.empty()
st.button("Re-run")
To use OAuth authentication in the Streamlit application, we are using Nginx as a reverse proxy with the auth_request directive to direct requests to an OAuth2-proxy service deployed in our stack. OAuth2-proxy can be configured to authenticate any OAuth2 server compatible with OpenID. In my example, I am using GitHub, but you can use ActiveDirectory, Google, Keycloak, or even your own OAuth2 server. This is my Nginx configuration:
This is my Nginx configuration:
upstream app {
server streamlit:8501;
}
upstream oauth2 {
server oauth2-proxy:4180;
}
server {
listen 8000;
location / {
auth_request /oauth2/auth;
error_page 401 = @error401;
try_files $uri @proxy_to_app;
}
location /_stcore/stream {
auth_request /oauth2/auth;
error_page 401 = @error401;
proxy_pass http://app/_stcore/stream;
proxy_http_version 1.1;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 86400;
}
location @error401 {
return 302 /oauth2/sign_in;
}
location /oauth2/ {
try_files $uri @proxy_to_oauth2;
}
location @proxy_to_oauth2 {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://oauth2;
}
location @proxy_to_app {
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Url-Scheme $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://app;
}
}
The complete stack can be seen in the docker-compose.yml:
version: '3.9'
services:
streamlit:
build: .
environment:
- ENVIRONMENT=docker
command: ["streamlit", "run", "st.py", "--server.port=8501", "--server.address=0.0.0.0"]
nginx:
build: .docker/nginx
ports:
- "8000:8000"
oauth2-proxy:
image: quay.io/oauth2-proxy/oauth2-proxy:v7.8.1
env_file:
- .env
And that’s all. The advantage of using oauth2-proxy is that we don’t need to do anything within the Streamlit application to have OAuth2 authentication. This greatly simplifies the integration process, as all the authentication logic is handled outside the main application. Additionally, oauth2-proxy is compatible with any OAuth2 server that complies with OpenID, giving us the flexibility to use different authentication providers. By using Nginx as a reverse proxy, we can efficiently redirect and manage authentication requests, ensuring that only authenticated users can access our Streamlit application.
Full code available in my github account.