Hi everyone!
I’m embedding the Streamlit app with iframe and using nginx reverse proxy and auth server to authenticate requests. Authentication server sets additional headers to be passed into the app. However, it’s not accessible through st.context.headers
.
What I’ve discovered so far, is that st.context.headers
shows headers coming within /_stcore/stream
request and not the initial /dashboards/mydashboard
request, that was behind the auth_request
.
Any ideas / hints how I can access / pass the data to be accessible at the time of the script running?
Below are some setup and request details:
Headers Dump
{
"Upgrade": "websocket",
"Connection": "upgrade",
"Host": "origin.click",
"X-Forwarded-For": "66.247.226.183",
"X-Forwarded-Proto": "https",
"X-Test-Me": "test_header_4",
"X-Header-Address": "_stcore/stream",
"Pragma": "no-cache",
"Cache-Control": "no-cache",
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36",
"Origin": "https://origin.click",
"Sec-Websocket-Version": "13",
"Accept-Encoding": "gzip, deflate, br, zstd",
"Sec-Websocket-Extensions": "permessage-deflate; client_max_window_bits",
"Sec-Websocket-Protocol": "streamlit, PLACEHOLDER_AUTH_TOKEN"
}
Nginx location config
location ~* ^/dashboards/((component|component-lib|static|app|favicon\.ico|manifest\.json|vega.*\.js|stream|healthz|api|media|app_icon\.ico|avatar/default|login/callback|index\.js|_stcore).*) {
proxy_pass http://127.0.0.1:8501/$1;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Test-Me "test_header_4";
proxy_set_header X-Header-Address $1;
proxy_pass_request_headers on;
proxy_buffering off;
}
location ~ ^/dashboards/([^/]+)$ {
set $auth_token $arg_token;
# Auth verification
auth_request /auth;
auth_request_set $auth_token $arg_token;
# User info from auth service
auth_request_set $user_id $upstream_http_x_user_id;
auth_request_set $user_email $upstream_http_x_user_email;
# CRITICAL: For static files, bypass file lookup and always proxy to Streamlit
# This prevents Nginx from looking for files in /var/www/html
# Proxy ALL requests in this location to Streamlit
rewrite ^/dashboards/([^/]+)/(.*)$ /$1/$2 break;
proxy_pass http://127.0.0.1:8501;
proxy_pass_request_headers on;
proxy_http_version 1.1;
# Headers
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Prefix /dashboards/$1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
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_set_header X-Auth-Token $auth_token;
proxy_set_header X-Test-Me "test_header_1";
proxy_set_header X-User-ID $user_id;
proxy_set_header X-User-Email $user_email;
# Don't buffer
proxy_buffering off;
proxy_redirect off;
# Error handling
proxy_intercept_errors on;
error_page 401 403 = @error_page;
}
# Keep your auth and error_page locations as they are
location = /auth {
internal;
proxy_pass http://localhost:3000/validate-session/;
proxy_pass_request_headers on;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Original-URI $request_uri;
proxy_set_header Cookie $http_cookie;
proxy_set_header X-Auth-Token $auth_token;
}
location @error_page {
internal;
root /var/www/html;
try_files /error.html =404;
}
Streamlit page
st.set_page_config(
page_title="My Dashboard",
layout='wide',
initial_sidebar_state='collapsed'
)
# Apply CSS styles
with open(pathlib.Path('./assets/sla_style.css')) as f:
st.markdown(f'<style>{f.read()}<style>', unsafe_allow_html=True)
# Read headers parameters
headers = st.context.headers
st.write(headers)