-
Notifications
You must be signed in to change notification settings - Fork 935
Open
Labels
bugSomething isn't workingSomething isn't working
Description
Describe the bug
It appears that the authentication middleware approach described here broke in 0.19.0 and above (issue still present on latest as of this writing 0.20.2): https://docs.marimo.io/guides/deploying/programmatically/#authentication-middleware-example
See attached minimal reproduction example (run with uv run name_of_file.py). If you downgrade marimo to 0.18.4 via the header you'll see the state propagated into the notebook correctly. Does not work with later versions.
Will you submit a PR?
- Yes
Environment
Details
{
"marimo": "0.20.2",
"editable": false,
"location": "/Users/wlach/src/voltus/voltuspy/marimo-app-server/.venv/lib/python3.11/site-packages/marimo",
"OS": "Darwin",
"OS Version": "24.6.0",
"Processor": "arm",
"Python Version": "3.11.13",
"Locale": "C/en_US",
"Binaries": {
"Browser": "145.0.7632.110",
"Node": "v20.19.5",
"uv": "0.9.14 (Homebrew 2025-12-01)"
},
"Dependencies": {
"click": "8.3.1",
"docutils": "0.22.3",
"itsdangerous": "2.2.0",
"jedi": "0.19.2",
"markdown": "3.10",
"narwhals": "2.13.0",
"packaging": "25.0",
"psutil": "7.1.3",
"pygments": "2.19.2",
"pymdown-extensions": "10.18",
"pyyaml": "6.0.3",
"starlette": "0.50.0",
"tomlkit": "0.13.3",
"typing-extensions": "4.15.0",
"uvicorn": "0.38.0",
"websockets": "15.0.1"
},
"Optional Dependencies": {
"altair": "6.0.0",
"anywidget": "0.9.21",
"duckdb": "1.4.3",
"loro": "1.10.3",
"nbformat": "5.10.4",
"openai": "2.9.0",
"pandas": "1.5.3",
"polars": "1.36.0",
"pyarrow": "22.0.0",
"pytest": "9.0.2",
"python-lsp-ruff": "2.3.0",
"python-lsp-server": "1.14.0",
"ruff": "0.14.8",
"sqlglot": "28.6.0",
"watchdog": "5.0.3"
},
"Experimental Flags": {}
}
Code to reproduce
#!/usr/bin/env python3
# /// script
# requires-python = ">=3.11"
# dependencies = [
# "fastapi",
# "marimo==0.20.2",
# "uvicorn",
# ]
# ///
"""Reproduction: BaseHTTPMiddleware sets scope["user"] for HTTP but NOT WebSocket.
marimo 0.20+ reads scope["user"] during WebSocket session init
(HTTPRequest.from_request(websocket)), so the dict set by HTTP middleware
is never seen. Instead marimo's own AuthBackend returns SimpleUser("user"),
which is not subscriptable — causing:
TypeError: 'SimpleUser' object is not subscriptable
Then open http://localhost:8000/ — the cell that accesses
mo.app_meta().request.user["username"] will blow up.
"""
import textwrap, tempfile, os, pathlib
import marimo
import uvicorn
from fastapi import FastAPI
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.requests import Request
# ── 1. Write a tiny marimo notebook to a temp file ──────────────────────────
notebook_code = textwrap.dedent('''\
import marimo
__generated_with = "0.20.2"
app = marimo.App(width="medium")
@app.cell
def _():
import marimo as mo
return (mo,)
@app.cell
def _(mo):
req = mo.app_meta().request
user = req.user if req else None
mo.md(f"""
## User info from `mo.app_meta().request.user`
- **type**: `{type(user).__name__}`
- **value**: `{user}`
- **subscript test**: `{user['username'] if isinstance(user, dict) else 'N/A — not a dict!'}`
""")
return
if __name__ == "__main__":
app.run()
''')
tmp_dir = tempfile.mkdtemp(prefix="marimo_repro_")
notebook_path = os.path.join(tmp_dir, "repro.py")
pathlib.Path(notebook_path).write_text(notebook_code)
print(f"Notebook written to {notebook_path}")
# ── 2. Build the ASGI app exactly like the marimo docs suggest ──────────────
app = FastAPI(title="Repro: scope['user'] not visible on WebSocket")
# This is the canonical middleware from marimo's docs.
# It ONLY runs for HTTP requests — NOT for WebSocket upgrades.
class AuthMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next):
request.scope["user"] = {
"is_authenticated": True,
"username": "example_user",
}
request.scope["meta"] = {"some_key": "some_value"}
response = await call_next(request)
return response
app.add_middleware(AuthMiddleware)
# Mount marimo
marimo_app = (
marimo.create_asgi_app(include_code=True)
.with_app(path="/", root=notebook_path)
.build()
)
app.mount("/", marimo_app)
# ── 3. Run ──────────────────────────────────────────────────────────────────
if __name__ == "__main__":
print("\n→ Open http://localhost:8000/ and look at the cell output.\n")
print("Expected: user is a dict with 'username'")
print("Actual (marimo ≥0.20): SimpleUser object — TypeError on subscript\n")
uvicorn.run(app, host="127.0.0.1", port=8000)Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
bugSomething isn't workingSomething isn't working