Skip to content

fix(auth): make require_auth async so the user ContextVar reaches the endpoint#485

Merged
pancacake merged 1 commit into
HKUDS:devfrom
truffle-dev:fix/auth-contextvar-async-481
May 28, 2026
Merged

fix(auth): make require_auth async so the user ContextVar reaches the endpoint#485
pancacake merged 1 commit into
HKUDS:devfrom
truffle-dev:fix/auth-contextvar-async-481

Conversation

@truffle-dev

Copy link
Copy Markdown
Contributor

Description

When AUTH_ENABLED=true, every non-admin HTTP request hits 404 because the user ContextVar set inside require_auth is invisible by the time the endpoint resolves the per-user path service.

require_auth is declared as a sync def. FastAPI dispatches sync deps via anyio.to_thread.run_sync, which captures the request context with copy_context() and runs the function in a worker thread under that copy. Mutations made inside the thread, including ContextVar.set, live on the copy and are discarded when the thread returns. The endpoint then runs in the original event-loop context with _current_user unset, so get_current_path_service() falls back to PathService.get_instance(), which points at data/user/ — the admin workspace. Admin requests appear to work because the fallback coincides with their intended workspace; user requests resolve to the admin DB and 404 on every session lookup.

The user-context middleware that #474 introduced for exactly this case was removed in 8bae3ca on the assumption that require_auth was sufficient. With require_auth running in a threadpool, it was not.

Declaring require_auth (and require_admin, for symmetry) as async def keeps the dependency on the event loop; the ContextVar mutation now propagates to the endpoint and per-user path resolution works.

Related Issues

Module(s) Affected

  • api
  • tests

Checklist

  • I have read and followed the contribution guidelines.
  • My code follows the project's coding standards.
  • I have run pre-commit run --all-files and fixed any issues.
  • I have added relevant tests for my changes.
  • I have updated the documentation (if necessary).
  • My changes do not introduce any new security vulnerabilities.

Additional Notes

Regression coverage in tests/api/test_auth_contextvar.py pins two invariants:

  1. require_auth and require_admin are declared async.
  2. With AUTH_ENABLED=true and a valid token, the user ContextVar set inside require_auth is visible from inside the endpoint, so get_path_service() resolves to the per-user multi-user/<uid>/ workspace.

Verified locally with pytest tests/api/test_auth_contextvar.py — all four cases pass on the fix and fail on the prior sync def.

… endpoint

Closes HKUDS#481.

When AUTH_ENABLED=true, every non-admin HTTP request hit 404 because the
user ContextVar set inside require_auth was invisible by the time the
endpoint resolved the per-user path service.

require_auth was declared as a sync def. FastAPI dispatches sync deps via
anyio.to_thread.run_sync, which captures the request context with
copy_context() and runs the function in a worker thread under that copy.
Mutations made inside the thread, including ContextVar.set, live on the
copy and are discarded when the thread returns. The endpoint then ran in
the original event-loop context with _current_user unset, so
get_current_path_service() fell back to PathService.get_instance(), which
points at data/user/ -- the admin workspace. Admin requests appeared to
work because the fallback coincided with their intended workspace; user
requests resolved to the admin DB and 404'd on every session lookup.

The user-context middleware that PR HKUDS#474 introduced for exactly this
case was removed in 8bae3ca on the assumption that require_auth was
sufficient. With require_auth running in a threadpool, it was not.

Declaring require_auth (and require_admin, for symmetry) as async def
keeps the dependency on the event loop; the ContextVar mutation now
propagates to the endpoint and per-user path resolution works.

Regression coverage in tests/api/test_auth_contextvar.py pins both
invariants: the dependencies are async, and the user ContextVar set
inside require_auth is observable from the endpoint and from
get_path_service().
@pancacake pancacake merged commit 69ea8b3 into HKUDS:dev May 28, 2026
4 of 9 checks passed
@pancacake

Copy link
Copy Markdown
Collaborator

Thanks for your contribution!

pancacake added a commit that referenced this pull request May 28, 2026
…streaming everywhere

- Centralize Gemini 2.5/3 reasoning_effort=none in
  reasoning_params.default_reasoning_effort_for so Visualize / Chat /
  Solve / agentic loop stop returning empty bodies on those models.
- Visualize: per-capability max_tokens default (16k) seeded from
  DEFAULT_AGENTS_SETTINGS, defensive root-tag trim on SVG/HTML output,
  graceful fallback when JSON-mode review step crashes.
- Fix #485: require_auth / require_admin are async so the
  set_current_user ContextVar reaches the endpoint instead of being
  discarded by anyio.to_thread.run_sync's worker-thread context copy.
  Adds _install_current_user helper shared by HTTP + WebSocket.
- Reasoning + native-tools chat protocol: formal content stream must
  still start with FINISH/TOOL/THINK/PAUSE; tool-call deltas no longer
  force-resolve labels and implicit_think_label is ignored, so
  protocol-repair catches missing labels instead of mis-routing turns.
- Smooth streaming on every chat surface: useSmoothStreamText through
  AssistantResponse, pin-to-bottom (useLayoutEffect) on book chat +
  quiz follow-up, data-chat-scroll-root opt-in for overflow-anchor:none.
- Sidebar: collapsible Recents region with own scroll viewport,
  deterministic Lucide icon per session via SessionAvatar, Docs link
  next to GitHub footer, "New Chat" button removed (nav handles it).
- Add Lemonade local provider (port 13305) — registry entry, README
  Docker host-gateway row, providers.md docs.
- Context-window models-endpoint probe honors DISABLE_SSL_VERIFY via
  TCPConnector(ssl=False).
- README: insert v1.4.2 release row, push v1.3.10 inside "Past
  releases" fold, bump install opt-in note to v1.4.2.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
truffle-dev added a commit to truffle-dev/truffleagent-site that referenced this pull request May 28, 2026
Three new external merges since last refresh:
- alash3al/stash#1 (docs alignment, 2026-05-28)
- HKUDS/DeepTutor#485 (sync→async require_auth, 2026-05-28)
- coleam00/Archon#1742 (chat bubble overflow wrap, 2026-05-25)

Totals: 46 → 49 PRs, 25 → 26 orgs.
@truffle-dev

Copy link
Copy Markdown
Contributor Author

Thanks for the quick review and merge.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants