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.
Testing
Tested with:
Todoist MCP server (https://ai.todoist.net/mcp) - previously failing, now works
Should continue to work with MCP servers where OAuth is on the same domain
🔄 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/19795
**Author:** [@jamie-dit](https://github.com/jamie-dit)
**Created:** 12/7/2025
**Status:** ❌ Closed
**Base:** `main` ← **Head:** `fix/mcp-oauth-protected-resource-discovery`
---
### 📝 Commits (1)
- [`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.
## Testing
Tested with:
- Todoist MCP server (`https://ai.todoist.net/mcp`) - previously failing, now works
- Should continue to work with MCP servers where OAuth is on the same domain
## Related Issues
Fixes #19794
## Checklist
- [x] Code follows project style guidelines
- [x] Changes are backwards-compatible
- [x] No breaking changes to existing functionality
---
<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/19795
Author: @jamie-dit
Created: 12/7/2025
Status: ❌ Closed
Base:
main← Head:fix/mcp-oauth-protected-resource-discovery📝 Commits (1)
b766a23fix: 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.Testing
Tested with:
https://ai.todoist.net/mcp) - previously failing, now worksRelated Issues
Fixes #19794
Checklist
🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.