From a680f21e12b2e8c3a20c71ca239462fb12d184e4 Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Tue, 11 Aug 2026 05:41:07 +0200 Subject: [PATCH] feat: make OAuth admin settings read-only when ENABLE_OAUTH_PERSISTENT_CONFIG is off (#28276) When ENABLE_OAUTH_PERSISTENT_CONFIG is off (the default), oauth.* config is never persisted and is read from environment variables, but the admin panel still let admins edit the OAuth/OIDC fields and silently dropped every save on restart, which kept confusing users who missed the docs warning (open-webui/open-webui#28247). The OAuth/OIDC section is now read-only in that case: the admin oauth config endpoint reports the flag and the UI wraps the section in a disabled fieldset, slightly dimmed with every control inert but all values still visible, plus a note naming the env var. Saving skips the OAuth POST since nothing can change. With the flag enabled the section behaves exactly as before. Known limits: the guard is UI-side only (the POST endpoint keeps accepting writes, unchanged), and disabled fields mean values cannot be selected and the masked client secret cannot be revealed while read-only. Switch.svelte gains a disabled:cursor-not-allowed style that applies to any disabled switch app-wide. Co-authored-by: Tim Baek --- backend/open_webui/routers/auths.py | 12 +- .../admin/Settings/Authentication.svelte | 545 +++++++++--------- src/lib/components/common/Switch.svelte | 2 +- 3 files changed, 291 insertions(+), 268 deletions(-) diff --git a/backend/open_webui/routers/auths.py b/backend/open_webui/routers/auths.py index 6961bc0db9..9168240d47 100644 --- a/backend/open_webui/routers/auths.py +++ b/backend/open_webui/routers/auths.py @@ -1428,11 +1428,13 @@ def _parse_oauth_update_value(field: str, value): async def get_oauth_config_values() -> dict: values = await Config.get_many(*OAUTH_CONFIG_KEYS.values()) - return { + form_values = { field: _format_oauth_form_value(field, values[storage_key]) for field, storage_key in OAUTH_CONFIG_KEYS.items() if storage_key in values } + form_values['ENABLE_OAUTH_PERSISTENT_CONFIG'] = Config.OAUTH_PERSISTENT_ENABLED + return form_values def oauth_config_updates(data: dict) -> dict: @@ -1443,12 +1445,16 @@ def oauth_config_updates(data: dict) -> dict: } -@router.get('/admin/config/oauth', response_model=OAuthConfigForm) +class OAuthConfigResponse(OAuthConfigForm): + ENABLE_OAUTH_PERSISTENT_CONFIG: bool + + +@router.get('/admin/config/oauth', response_model=OAuthConfigResponse) async def get_oauth_config(request: Request, user=Depends(get_admin_user)): return await get_oauth_config_values() -@router.post('/admin/config/oauth', response_model=OAuthConfigForm) +@router.post('/admin/config/oauth', response_model=OAuthConfigResponse) async def update_oauth_config(request: Request, form_data: OAuthConfigForm, user=Depends(get_admin_user)): await Config.upsert(oauth_config_updates(form_data.model_dump(exclude_none=True))) return await get_oauth_config_values() diff --git a/src/lib/components/admin/Settings/Authentication.svelte b/src/lib/components/admin/Settings/Authentication.svelte index 46b0ce5035..24a389b2ae 100644 --- a/src/lib/components/admin/Settings/Authentication.svelte +++ b/src/lib/components/admin/Settings/Authentication.svelte @@ -49,6 +49,7 @@ }; let oauthConfig: any = null; + $: oauthEditable = oauthConfig?.ENABLE_OAUTH_PERSISTENT_CONFIG ?? true; const inputClass = 'w-full h-7 rounded-lg border border-gray-100/50 bg-gray-50/40 px-2 text-xs text-gray-700 outline-hidden transition-colors placeholder:text-gray-300 focus:border-blue-400 dark:border-white/[0.04] dark:bg-white/[0.03] dark:text-gray-300 dark:placeholder:text-gray-700 dark:focus:border-blue-500'; const textareaClass = @@ -74,7 +75,7 @@ }; const updateOAuthHandler = async () => { - if (!oauthConfig) return true; + if (!oauthConfig || !oauthEditable) return true; const res = await updateOAuthConfig(localStorage.token, oauthConfig).catch((error) => { toast.error(`${error}`); return null; @@ -526,311 +527,327 @@ {#if oauthConfig} - - - - - {#if oauthConfig.ENABLE_OAUTH} -
- - - - - - - -
- -
- - - - - - - -
- -
- - - - - - - -
- -
- - - - - - - -
- -
- - - - - - - -
- - - - - - - - - - - - + + {/if} - - - - - +
- + - {#if oauthConfig.ENABLE_OAUTH_ROLE_MANAGEMENT} + {#if oauthConfig.ENABLE_OAUTH}
- - - - {/if} +
+ + + - - - - + + + +
+ +
+ + + + + + + +
+ +
+ + + + + + + +
+ +
+ + + + + + + +
- {#if oauthConfig.ENABLE_OAUTH_GROUP_MANAGEMENT} + + + + -
- - - + + + + + + + + + + + + + + {#if oauthConfig.ENABLE_OAUTH_ROLE_MANAGEMENT} +
+ + + + + + + +
-
+ {/if} + + + + + + + {#if oauthConfig.ENABLE_OAUTH_GROUP_MANAGEMENT} + + + + +
+ + + + + + + +
+ {/if} + + + + + + + + + + + + {/if} - - - - - - - - - - - - - {/if} +
{/if} diff --git a/src/lib/components/common/Switch.svelte b/src/lib/components/common/Switch.svelte index ebf66b9b72..6e36ea94fe 100644 --- a/src/lib/components/common/Switch.svelte +++ b/src/lib/components/common/Switch.svelte @@ -36,7 +36,7 @@ {id} aria-labelledby={ariaLabelledbyId || undefined} aria-label={ariaLabel || undefined} - class="relative h-4 min-h-4 w-7 shrink-0 cursor-pointer rounded-full mx-[0.0625rem] transition-colors duration-150 {($settings?.highContrastMode ?? + class="relative h-4 min-h-4 w-7 shrink-0 cursor-pointer rounded-full mx-[0.0625rem] transition-colors duration-150 disabled:cursor-not-allowed {($settings?.highContrastMode ?? false) ? 'focus:outline focus:outline-2 focus:outline-gray-800 focus:dark:outline-gray-200' : 'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gray-400 dark:focus-visible:outline-gray-500'} {state