[PR #22341] fix: surface OAuth auth prompt for default MCP tools via toast + popup #26621

Open
opened 2026-04-20 06:36:28 -05:00 by GiteaMirror · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/open-webui/open-webui/pull/22341
Author: @MedlockM
Created: 3/6/2026
Status: 🔄 Open

Base: devHead: fix/mcp-oauth-default-tools-and-token-refresh


📝 Commits (4)

  • d20fcde refactor: simplify MCP OAuth 2.1 401 detection in middleware
  • 3c1c4e1 refactor: simplify MCP OAuth callback redirect logic
  • 0420874 refactor: remove dead code from OAuth popup flow
  • 6fe57a8 Merge branch 'dev' into fix/mcp-oauth-default-tools-and-token-refresh

📊 Changes

6 files changed (+153 additions, -5 deletions)

View changed files

📝 backend/open_webui/main.py (+6 -0)
📝 backend/open_webui/utils/mcp/client.py (+3 -2)
📝 backend/open_webui/utils/middleware.py (+34 -0)
📝 backend/open_webui/utils/oauth.py (+9 -2)
📝 src/lib/components/chat/Chat.svelte (+91 -1)
📝 src/routes/+layout.svelte (+10 -0)

📄 Description

This PR addresses issues discussed in #20858 — OAuth 2.1 MCP tools set as model defaults fail silently and tokens can expire mid-session with no proactive renewal.

Problem

Two issues identified in #20858:

  1. No pre-flight check: Users have no way to know that one of their default OAuth 2.1 tools is not yet authenticated. The chat silently fails with "Failed to connect to MCP server" and no prompt to authorize.

  2. No mid-session reauth: If a refresh token expires for any reason during a conversation, the pre-flight check cannot catch it. There is currently no mechanism to re-authenticate without leaving the chat.

Out of scope: This PR does not address the API/headless path (raised by @jk-f5 in #20858) — when OAuth 2.1 MCP tools are called programmatically without a browser UI. That scenario requires a different approach and should be handled in a separate PR.

Solution

Pre-flight toast (before sending a message):

  • When a user selects a model with unauthenticated OAuth MCP tools, a persistent toast.warning appears with an "Authorize" button
  • Clicking opens the OAuth flow in a popup window — the user never leaves the chat
  • On success, the popup signals the parent via localStorage, the toast auto-dismisses, and the tool becomes available

Mid-session reauth toast (during a conversation):

  • If a 401 is detected from an MCP server during message processing, the backend emits an oauth_reauth_toast event
  • The frontend shows the same toast+popup flow, allowing the user to re-authorize without losing their conversation

Pull Request Checklist

  • Target branch: dev
  • Description: provided above
  • Changelog: see below
  • Dependencies: no new dependencies
  • Testing: manual tests performed, see steps and screenshots below
  • Code review: self-reviewed
  • Design & Architecture: no new settings introduced; uses existing patterns (Banner component, periodic_* task pattern, get_sessions_by_user_id pattern)
  • Git Hygiene: single atomic commit, rebased on dev
  • Title Prefix: fix:

Testing

Tested against 4 OAuth 2.1 MCP servers (Atlassian, Zapier, Notion, Linear).

  • Pre-flight auth: Selected a model with default OAuth MCP tools → toast appears → clicked "Authorize" → popup opens → completed OAuth → popup closes → toast auto-dismisses → tool works
  • Mid-session reauth: Manually deleted OAuth session tokens from the database to simulate token expiration → sent a message using the MCP tool → mid-session toast appears → clicked "Authorize" → completed OAuth → tool reconnects and works
  • Non-invasive UX: Verified that the chat remains fully usable even when the OAuth toast is displayed — users can continue chatting, and the toast does not block any interaction

Changelog Entry

Fixed

File Change
src/lib/components/chat/Chat.svelte Pre-flight toast logic, mid-session oauth_reauth_toast handler, OAuth popup storage listener
src/routes/+layout.svelte Popup detection: signal parent via localStorage and close
backend/open_webui/utils/middleware.py Detect 401 in ExceptionGroup from MCP servers, emit oauth_reauth_toast event
backend/open_webui/utils/mcp/client.py Defensive disconnect() fix
backend/open_webui/utils/oauth.py return_url parameter in handle_callback for popup redirect
backend/open_webui/main.py Pass return_url through authorize/callback endpoints

Screenshots or Videos

Video of the pre-flight oauth process
Capture vidéo du 2026-03-13 19-57-15.webm

Video of the mid-session oauth process
Capture vidéo du 2026-03-13 18-39-58.webm

Multiple unauthenticated tools — stacked toasts:
image

Credit

Approach inspired by @Lemmons ' interrupt-based flow from their branch. Simplified to use toasts instead of modal dialogs, and duck-typed 401 detection instead of a custom exception class.

Contributor License Agreement

By submitting this pull request, I confirm that I have read and fully agree to the Contributor License Agreement (CLA), and I am providing my contributions under its terms.

Note

Deleting the CLA section will lead to immediate closure of your PR and it will not be merged in.


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/open-webui/open-webui/pull/22341 **Author:** [@MedlockM](https://github.com/MedlockM) **Created:** 3/6/2026 **Status:** 🔄 Open **Base:** `dev` ← **Head:** `fix/mcp-oauth-default-tools-and-token-refresh` --- ### 📝 Commits (4) - [`d20fcde`](https://github.com/open-webui/open-webui/commit/d20fcdee087459c36c688be563952d0b2d7f7848) refactor: simplify MCP OAuth 2.1 401 detection in middleware - [`3c1c4e1`](https://github.com/open-webui/open-webui/commit/3c1c4e100cce6e99ecd06a6317b918fc8ab7c870) refactor: simplify MCP OAuth callback redirect logic - [`0420874`](https://github.com/open-webui/open-webui/commit/0420874806840edcb2821d12b0fa0846f640c938) refactor: remove dead code from OAuth popup flow - [`6fe57a8`](https://github.com/open-webui/open-webui/commit/6fe57a88a76ec474dd8035bb781ebff135c21cc2) Merge branch 'dev' into fix/mcp-oauth-default-tools-and-token-refresh ### 📊 Changes **6 files changed** (+153 additions, -5 deletions) <details> <summary>View changed files</summary> 📝 `backend/open_webui/main.py` (+6 -0) 📝 `backend/open_webui/utils/mcp/client.py` (+3 -2) 📝 `backend/open_webui/utils/middleware.py` (+34 -0) 📝 `backend/open_webui/utils/oauth.py` (+9 -2) 📝 `src/lib/components/chat/Chat.svelte` (+91 -1) 📝 `src/routes/+layout.svelte` (+10 -0) </details> ### 📄 Description > This PR addresses issues discussed in [#20858](https://github.com/open-webui/open-webui/discussions/20858) — OAuth 2.1 MCP tools set as model defaults fail silently and tokens can expire mid-session with no proactive renewal. ## Problem Two issues identified in #20858: 1. **No pre-flight check**: Users have no way to know that one of their default OAuth 2.1 tools is not yet authenticated. The chat silently fails with "Failed to connect to MCP server" and no prompt to authorize. 2. **No mid-session reauth**: If a refresh token expires for any reason during a conversation, the pre-flight check cannot catch it. There is currently no mechanism to re-authenticate without leaving the chat. **Out of scope**: This PR does not address the API/headless path (raised by @jk-f5 in #20858) — when OAuth 2.1 MCP tools are called programmatically without a browser UI. That scenario requires a different approach and should be handled in a separate PR. ## Solution **Pre-flight toast (before sending a message):** - When a user selects a model with unauthenticated OAuth MCP tools, a persistent toast.warning appears with an "Authorize" button - Clicking opens the OAuth flow in a popup window — the user never leaves the chat - On success, the popup signals the parent via localStorage, the toast auto-dismisses, and the tool becomes available **Mid-session reauth toast (during a conversation):** - If a 401 is detected from an MCP server during message processing, the backend emits an oauth_reauth_toast event - The frontend shows the same toast+popup flow, allowing the user to re-authorize without losing their conversation ## Pull Request Checklist - [x] **Target branch:** `dev` - [x] **Description:** provided above - [x] **Changelog:** see below - [x] **Dependencies:** no new dependencies - [x] **Testing:** manual tests performed, see steps and screenshots below - [x] **Code review:** self-reviewed - [x] **Design & Architecture:** no new settings introduced; uses existing patterns (`Banner` component, `periodic_*` task pattern, `get_sessions_by_user_id` pattern) - [x] **Git Hygiene:** single atomic commit, rebased on `dev` - [x] **Title Prefix:** `fix:` ## Testing Tested against 4 OAuth 2.1 MCP servers (Atlassian, Zapier, Notion, Linear). - **Pre-flight auth**: Selected a model with default OAuth MCP tools → toast appears → clicked "Authorize" → popup opens → completed OAuth → popup closes → toast auto-dismisses → tool works - **Mid-session reauth**: Manually deleted OAuth session tokens from the database to simulate token expiration → sent a message using the MCP tool → mid-session toast appears → clicked "Authorize" → completed OAuth → tool reconnects and works - **Non-invasive UX**: Verified that the chat remains fully usable even when the OAuth toast is displayed — users can continue chatting, and the toast does not block any interaction --- # Changelog Entry ### Fixed | File | Change | |------|--------| | `src/lib/components/chat/Chat.svelte` | Pre-flight toast logic, mid-session `oauth_reauth_toast` handler, OAuth popup storage listener | | `src/routes/+layout.svelte` | Popup detection: signal parent via localStorage and close | | `backend/open_webui/utils/middleware.py` | Detect 401 in ExceptionGroup from MCP servers, emit `oauth_reauth_toast` event | | `backend/open_webui/utils/mcp/client.py` | Defensive `disconnect()` fix | | `backend/open_webui/utils/oauth.py` | `return_url` parameter in `handle_callback` for popup redirect | | `backend/open_webui/main.py` | Pass `return_url` through authorize/callback endpoints | --- ### Screenshots or Videos **Video of the pre-flight oauth process** [Capture vidéo du 2026-03-13 19-57-15.webm](https://github.com/user-attachments/assets/80af1c48-cb38-4e9f-b54f-73130ab68f43) **Video of the mid-session oauth process** [Capture vidéo du 2026-03-13 18-39-58.webm](https://github.com/user-attachments/assets/71d413f7-5b2e-4b24-b988-c3ccea231f59) **Multiple unauthenticated tools — stacked toasts:** <img width="1859" height="1081" alt="image" src="https://github.com/user-attachments/assets/be915bd7-57f5-415a-a714-88ad3fbc2e00" /> ### Credit Approach inspired by @Lemmons ' interrupt-based flow from [their branch](https://github.com/open-webui/open-webui/compare/main...Lemmons:open-webui:Lemmons/openwebui-oauth2.1-fix). Simplified to use toasts instead of modal dialogs, and duck-typed 401 detection instead of a custom exception class. ### Contributor License Agreement <!-- 🚨 DO NOT DELETE THE TEXT BELOW 🚨 Keep the "Contributor License Agreement" confirmation text intact. Deleting it will trigger the CLA-Bot to INVALIDATE your PR. --> By submitting this pull request, I confirm that I have read and fully agree to the [Contributor License Agreement (CLA)](https://github.com/open-webui/open-webui/blob/main/CONTRIBUTOR_LICENSE_AGREEMENT), and I am providing my contributions under its terms. > [!NOTE] > Deleting the CLA section will lead to immediate closure of your PR and it will not be merged in. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
GiteaMirror added the pull-request label 2026-04-20 06:36:28 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/open-webui#26621