[GH-ISSUE #23788] issue: terminal websocket ignores session/system_oauth auth modes #58742

Closed
opened 2026-05-05 23:49:14 -05:00 by GiteaMirror · 2 comments
Owner

Originally created by @shaun0927 on GitHub (Apr 16, 2026).
Original GitHub issue: https://github.com/open-webui/open-webui/issues/23788

Check Existing Issues

  • I have searched for any existing and/or related issues.
  • I have searched for any existing and/or related discussions.
  • I have also searched in the CLOSED issues AND CLOSED discussions and found no exact duplicate.
  • I am using the latest version of Open WebUI.

Installation Method

Git Clone

Open WebUI Version

latest main as of 2026-04-16 (latest release also checked: v0.8.12)

Ollama Version (if applicable)

No response

Operating System

macOS Sequoia

Browser (if applicable)

No response

Confirmation

  • I have read and followed all instructions in README.md.
  • I am using the latest version of Open WebUI.
  • I have provided a deterministic local reproduction of the affected code path.
  • I have included the relevant code path, expected behavior, actual behavior, and exact reproduction steps.

Expected Behavior

The terminal websocket proxy should support the same auth modes as the terminal HTTP proxy.

If proxy_terminal supports bearer, session, and system_oauth, then ws_terminal should not silently drop the non-bearer auth paths.

Actual Behavior

proxy_terminal handles:

  • bearer
  • session
  • system_oauth

but ws_terminal only sends upstream auth material when auth_type == 'bearer'.

That makes the websocket path behavior inconsistent with the HTTP proxy path.

This is not the same bug as #22581 (ws:// vs wss:// under HTTPS).
It is an auth-mode mismatch.

There was also a nearby closed PR #23603 (Fix terminal orchestrator ws auth), but the current main / v0.8.12 code still shows the mismatch below.

Steps to Reproduce

Current HTTP proxy path in backend/open_webui/routers/terminals.py:

if auth_type == 'bearer':
    headers['Authorization'] = f'Bearer {connection.get("key", "")}'
elif auth_type == 'session':
    cookies = request.cookies
    headers['Authorization'] = f'Bearer {request.state.token.credentials}'
elif auth_type == 'system_oauth':
    cookies = request.cookies
    oauth_token = request.headers.get('x-oauth-access-token', '')
    if oauth_token:
        headers['Authorization'] = f'Bearer {oauth_token}'

Current websocket path:

auth_type = connection.get('auth_type', 'bearer')
if auth_type == 'bearer':
    key = connection.get('key', '')
    await upstream.send_str(_json.dumps({'type': 'auth', 'token': key}))

A deterministic local reproduction of the logic is:

import asyncio
import json

class FakeUpstream:
    def __init__(self):
        self.sent = []
    async def send_str(self, data):
        self.sent.append(('str', data))

async def simulate(auth_type, key='secret-token'):
    upstream = FakeUpstream()
    if auth_type == 'bearer':
        await upstream.send_str(json.dumps({'type': 'auth', 'token': key}))
    return upstream.sent

for auth_type in ['bearer', 'session', 'system_oauth', 'none']:
    sent = asyncio.run(simulate(auth_type))
    print(f'{auth_type} -> sent = {sent}')

Actual output:

bearer -> sent = [('str', '{"type": "auth", "token": "secret-token"}')]
session -> sent = []
system_oauth -> sent = []
none -> sent = []

Logs & Screenshots

Relevant current websocket code path (backend/open_webui/routers/terminals.py):

auth_type = connection.get('auth_type', 'bearer')
if auth_type == 'bearer':
    key = connection.get('key', '')
    await upstream.send_str(_json.dumps({'type': 'auth', 'token': key}))

Additional Information

This looks like an implementation mismatch rather than a security issue.

I have a narrow fix ready that centralizes the auth assembly used by proxy_terminal and reuses it for the websocket handshake so the two paths do not drift.

Originally created by @shaun0927 on GitHub (Apr 16, 2026). Original GitHub issue: https://github.com/open-webui/open-webui/issues/23788 ### Check Existing Issues - [x] I have searched for any existing and/or related issues. - [x] I have searched for any existing and/or related discussions. - [x] I have also searched in the CLOSED issues AND CLOSED discussions and found no exact duplicate. - [x] I am using the latest version of Open WebUI. ### Installation Method Git Clone ### Open WebUI Version latest `main` as of 2026-04-16 (latest release also checked: `v0.8.12`) ### Ollama Version (if applicable) _No response_ ### Operating System macOS Sequoia ### Browser (if applicable) _No response_ ### Confirmation - [x] I have read and followed all instructions in `README.md`. - [x] I am using the latest version of Open WebUI. - [x] I have provided a deterministic local reproduction of the affected code path. - [x] I have included the relevant code path, expected behavior, actual behavior, and exact reproduction steps. ### Expected Behavior The terminal websocket proxy should support the same auth modes as the terminal HTTP proxy. If `proxy_terminal` supports `bearer`, `session`, and `system_oauth`, then `ws_terminal` should not silently drop the non-bearer auth paths. ### Actual Behavior `proxy_terminal` handles: - `bearer` - `session` - `system_oauth` but `ws_terminal` only sends upstream auth material when `auth_type == 'bearer'`. That makes the websocket path behavior inconsistent with the HTTP proxy path. This is **not** the same bug as `#22581` (`ws://` vs `wss://` under HTTPS). It is an auth-mode mismatch. There was also a nearby closed PR `#23603` (`Fix terminal orchestrator ws auth`), but the current `main` / `v0.8.12` code still shows the mismatch below. ### Steps to Reproduce Current HTTP proxy path in `backend/open_webui/routers/terminals.py`: ```python if auth_type == 'bearer': headers['Authorization'] = f'Bearer {connection.get("key", "")}' elif auth_type == 'session': cookies = request.cookies headers['Authorization'] = f'Bearer {request.state.token.credentials}' elif auth_type == 'system_oauth': cookies = request.cookies oauth_token = request.headers.get('x-oauth-access-token', '') if oauth_token: headers['Authorization'] = f'Bearer {oauth_token}' ``` Current websocket path: ```python auth_type = connection.get('auth_type', 'bearer') if auth_type == 'bearer': key = connection.get('key', '') await upstream.send_str(_json.dumps({'type': 'auth', 'token': key})) ``` A deterministic local reproduction of the logic is: ```python import asyncio import json class FakeUpstream: def __init__(self): self.sent = [] async def send_str(self, data): self.sent.append(('str', data)) async def simulate(auth_type, key='secret-token'): upstream = FakeUpstream() if auth_type == 'bearer': await upstream.send_str(json.dumps({'type': 'auth', 'token': key})) return upstream.sent for auth_type in ['bearer', 'session', 'system_oauth', 'none']: sent = asyncio.run(simulate(auth_type)) print(f'{auth_type} -> sent = {sent}') ``` Actual output: ```text bearer -> sent = [('str', '{"type": "auth", "token": "secret-token"}')] session -> sent = [] system_oauth -> sent = [] none -> sent = [] ``` ### Logs & Screenshots Relevant current websocket code path (`backend/open_webui/routers/terminals.py`): ```python auth_type = connection.get('auth_type', 'bearer') if auth_type == 'bearer': key = connection.get('key', '') await upstream.send_str(_json.dumps({'type': 'auth', 'token': key})) ``` ### Additional Information This looks like an implementation mismatch rather than a security issue. I have a narrow fix ready that centralizes the auth assembly used by `proxy_terminal` and reuses it for the websocket handshake so the two paths do not drift.
Author
Owner

@shaun0927 commented on GitHub (Apr 16, 2026):

I opened a narrow fix PR for this report: #23790. The PR reuses the same terminal auth assembly for the HTTP proxy and websocket handshake so non-bearer auth modes do not drift between the two paths.

<!-- gh-comment-id:4260961446 --> @shaun0927 commented on GitHub (Apr 16, 2026): I opened a narrow fix PR for this report: #23790. The PR reuses the same terminal auth assembly for the HTTP proxy and websocket handshake so non-bearer auth modes do not drift between the two paths.
Author
Owner

@tjbck commented on GitHub (Apr 16, 2026):

Intended behaviour.

<!-- gh-comment-id:4264018121 --> @tjbck commented on GitHub (Apr 16, 2026): Intended behaviour.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/open-webui#58742