fe6783c Merge pull request #19030 from open-webui/dev
fc05e0a Merge pull request #19405 from open-webui/dev
e3faec6 Merge pull request #19416 from open-webui/dev
9899293 Merge pull request #19448 from open-webui/dev
140605e Merge pull request #19462 from open-webui/dev
6f1486f Merge pull request #19466 from open-webui/dev
b766a23 fix: MCP OAuth discovery via Protected Resource metadata flow
📊 Changes
1 file changed (+77 additions, -2 deletions)
View changed files
📝backend/open_webui/utils/oauth.py (+77 -2)
📄 Description
Summary
This PR fixes MCP OAuth 2.1 client registration failing when the OAuth authorization server is on a different domain than the MCP server (e.g., Todoist MCP at ai.todoist.net with OAuth at todoist.com).
Problem
Currently, Open WebUI only looks for OAuth metadata at:
But according to the MCP Authorization spec, clients should follow the Protected Resource discovery flow when the OAuth server is on a different domain.
Solution
Implements the full MCP Protected Resource discovery flow:
Make unauthenticated request to MCP endpoint → receives 401 with WWW-Authenticate header
Use discovered servers for OAuth metadata discovery
Example flow for Todoist:
POST ai.todoist.net/mcp (no auth)
↓ 401 + WWW-Authenticate: Bearer resource_metadata="https://ai.todoist.net/.well-known/oauth-protected-resource/mcp"
GET ai.todoist.net/.well-known/oauth-protected-resource/mcp
↓ { "authorization_servers": ["https://todoist.com"] }
GET todoist.com/.well-known/oauth-authorization-server
↓ { "registration_endpoint": "https://todoist.com/oauth/register", ... }
POST todoist.com/oauth/register (DCR)
↓ { "client_id": "...", "client_secret": "..." } ✅
Changes
Added discover_authorization_server_from_mcp() function that implements the Protected Resource discovery flow
Modified get_oauth_client_info_with_dynamic_client_registration() to:
First try MCP Protected Resource discovery
Build discovery URLs from discovered authorization servers
Fall back to existing behaviour if discovery fails
Backwards Compatibility
The fix is fully backwards-compatible. If Protected Resource discovery fails (no WWW-Authenticate header, network error, etc.), it falls back to the existing discovery behavior.
Pull Request Checklist
Target branch: PR targets dev
Description: Included above
Testing: Manual validation performed (see below)
Code review: Self-review done
Testing
✅I have personally tested ALL changes in this PR
How I tested it:
Applied the patch to a running Open WebUI Docker instance
Navigated to Admin Settings → External Tools → Add Server
Set Type to "MCP (Streamable HTTP)"
Entered URL: https://ai.todoist.net/mcp
Set Auth to "OAuth 2.1"
Clicked "Register Client"
Before fix: Registration failed with 400 Bad Request
After fix: Registration succeeded, OAuth flow completed, Todoist tools available
Verification of discovery flow:
# Confirmed MCP server returns WWW-Authenticate header
$ curl -s -D - https://ai.todoist.net/mcp -X POST -H "Content-Type: application/json"\
-d '{"jsonrpc":"2.0","method":"initialize","params":{},"id":1}'
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer resource_metadata="https://ai.todoist.net/.well-known/oauth-protected-resource/mcp"# Confirmed Protected Resource metadata returns authorization server
$ curl -s https://ai.todoist.net/.well-known/oauth-protected-resource/mcp
{"resource":"https://ai.todoist.net/mcp","authorization_servers":["https://todoist.com"],...}# Confirmed DCR endpoint works at discovered authorization server
$ curl -s https://todoist.com/oauth/register -X POST -H "Content-Type: application/json"\
-d '{"redirect_uris":["https://example.com/callback"],"client_name":"Test"}'{"client_id":"tdd_xxx","client_secret":"xxx",...}
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.
🔄 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/19796
**Author:** [@jamie-dit](https://github.com/jamie-dit)
**Created:** 12/7/2025
**Status:** ❌ Closed
**Base:** `dev` ← **Head:** `fix/mcp-oauth-protected-resource-discovery-v2`
---
### 📝 Commits (7)
- [`fe6783c`](https://github.com/open-webui/open-webui/commit/fe6783c16699911c7be17392596d579333fb110c) Merge pull request #19030 from open-webui/dev
- [`fc05e0a`](https://github.com/open-webui/open-webui/commit/fc05e0a6c5d39da60b603b4d520f800d6e36f748) Merge pull request #19405 from open-webui/dev
- [`e3faec6`](https://github.com/open-webui/open-webui/commit/e3faec62c58e3a83d89aa3df539feacefa125e0c) Merge pull request #19416 from open-webui/dev
- [`9899293`](https://github.com/open-webui/open-webui/commit/9899293f050ad50ae12024cbebee7e018acd851e) Merge pull request #19448 from open-webui/dev
- [`140605e`](https://github.com/open-webui/open-webui/commit/140605e660b8186a7d5c79fb3be6ffb147a2f498) Merge pull request #19462 from open-webui/dev
- [`6f1486f`](https://github.com/open-webui/open-webui/commit/6f1486ffd0cb288d0e21f41845361924e0d742b3) Merge pull request #19466 from open-webui/dev
- [`b766a23`](https://github.com/open-webui/open-webui/commit/b766a23e36062e52c852a849beba64e67de9d0c8) fix: MCP OAuth discovery via Protected Resource metadata flow
### 📊 Changes
**1 file changed** (+77 additions, -2 deletions)
<details>
<summary>View changed files</summary>
📝 `backend/open_webui/utils/oauth.py` (+77 -2)
</details>
### 📄 Description
## Summary
This PR fixes MCP OAuth 2.1 client registration failing when the OAuth authorization server is on a different domain than the MCP server (e.g., Todoist MCP at `ai.todoist.net` with OAuth at `todoist.com`).
## Problem
Currently, Open WebUI only looks for OAuth metadata at:
```
{MCP_SERVER_URL}/.well-known/oauth-authorization-server
```
But according to the [MCP Authorization spec](https://modelcontextprotocol.io/specification/2025-03-26/basic/authorization), clients should follow the Protected Resource discovery flow when the OAuth server is on a different domain.
## Solution
Implements the full MCP Protected Resource discovery flow:
1. **Make unauthenticated request** to MCP endpoint → receives 401 with `WWW-Authenticate` header
2. **Parse `resource_metadata` URL** from the header
3. **Fetch Protected Resource metadata** → contains `authorization_servers` array
4. **Use discovered servers** for OAuth metadata discovery
### Example flow for Todoist:
```
POST ai.todoist.net/mcp (no auth)
↓ 401 + WWW-Authenticate: Bearer resource_metadata="https://ai.todoist.net/.well-known/oauth-protected-resource/mcp"
GET ai.todoist.net/.well-known/oauth-protected-resource/mcp
↓ { "authorization_servers": ["https://todoist.com"] }
GET todoist.com/.well-known/oauth-authorization-server
↓ { "registration_endpoint": "https://todoist.com/oauth/register", ... }
POST todoist.com/oauth/register (DCR)
↓ { "client_id": "...", "client_secret": "..." } ✅
```
## Changes
- Added `discover_authorization_server_from_mcp()` function that implements the Protected Resource discovery flow
- Modified `get_oauth_client_info_with_dynamic_client_registration()` to:
1. First try MCP Protected Resource discovery
2. Build discovery URLs from discovered authorization servers
3. Fall back to existing behaviour if discovery fails
## Backwards Compatibility
The fix is fully backwards-compatible. If Protected Resource discovery fails (no `WWW-Authenticate` header, network error, etc.), it falls back to the existing discovery behavior.
---
## Pull Request Checklist
* [x] **Target branch:** PR targets `dev`
* [x] **Description:** Included above
* [x] **Testing:** Manual validation performed (see below)
* [x] **Code review:** Self-review done
---
## Testing
✅ **I have personally tested ALL changes in this PR**
### How I tested it:
1. Applied the patch to a running Open WebUI Docker instance
2. Navigated to Admin Settings → External Tools → Add Server
3. Set Type to "MCP (Streamable HTTP)"
4. Entered URL: `https://ai.todoist.net/mcp`
5. Set Auth to "OAuth 2.1"
6. Clicked "Register Client"
7. **Before fix:** Registration failed with 400 Bad Request
8. **After fix:** Registration succeeded, OAuth flow completed, Todoist tools available
### Verification of discovery flow:
```bash
# Confirmed MCP server returns WWW-Authenticate header
$ curl -s -D - https://ai.todoist.net/mcp -X POST -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"initialize","params":{},"id":1}'
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer resource_metadata="https://ai.todoist.net/.well-known/oauth-protected-resource/mcp"
# Confirmed Protected Resource metadata returns authorization server
$ curl -s https://ai.todoist.net/.well-known/oauth-protected-resource/mcp
{"resource":"https://ai.todoist.net/mcp","authorization_servers":["https://todoist.com"],...}
# Confirmed DCR endpoint works at discovered authorization server
$ curl -s https://todoist.com/oauth/register -X POST -H "Content-Type: application/json" \
-d '{"redirect_uris":["https://example.com/callback"],"client_name":"Test"}'
{"client_id":"tdd_xxx","client_secret":"xxx",...}
```
---
## Related Issues
Fixes #19794
---
## Contributor License Agreement
By submitting this pull request, I confirm that I have read and fully agree to the [Contributor License Agreement (CLA)](/CONTRIBUTOR_LICENSE_AGREEMENT), and I am providing my contributions under its terms.
---
<sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
📋 Pull Request Information
Original PR: https://github.com/open-webui/open-webui/pull/19796
Author: @jamie-dit
Created: 12/7/2025
Status: ❌ Closed
Base:
dev← Head:fix/mcp-oauth-protected-resource-discovery-v2📝 Commits (7)
fe6783cMerge pull request #19030 from open-webui/devfc05e0aMerge pull request #19405 from open-webui/deve3faec6Merge pull request #19416 from open-webui/dev9899293Merge pull request #19448 from open-webui/dev140605eMerge pull request #19462 from open-webui/dev6f1486fMerge pull request #19466 from open-webui/devb766a23fix: MCP OAuth discovery via Protected Resource metadata flow📊 Changes
1 file changed (+77 additions, -2 deletions)
View changed files
📝
backend/open_webui/utils/oauth.py(+77 -2)📄 Description
Summary
This PR fixes MCP OAuth 2.1 client registration failing when the OAuth authorization server is on a different domain than the MCP server (e.g., Todoist MCP at
ai.todoist.netwith OAuth attodoist.com).Problem
Currently, Open WebUI only looks for OAuth metadata at:
But according to the MCP Authorization spec, clients should follow the Protected Resource discovery flow when the OAuth server is on a different domain.
Solution
Implements the full MCP Protected Resource discovery flow:
WWW-Authenticateheaderresource_metadataURL from the headerauthorization_serversarrayExample flow for Todoist:
Changes
discover_authorization_server_from_mcp()function that implements the Protected Resource discovery flowget_oauth_client_info_with_dynamic_client_registration()to:Backwards Compatibility
The fix is fully backwards-compatible. If Protected Resource discovery fails (no
WWW-Authenticateheader, network error, etc.), it falls back to the existing discovery behavior.Pull Request Checklist
devTesting
✅ I have personally tested ALL changes in this PR
How I tested it:
https://ai.todoist.net/mcpVerification of discovery flow:
Related Issues
Fixes #19794
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.
🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.