This commit is contained in:
Timothy Jaeryang Baek
2026-04-24 16:17:46 +09:00
parent 5cc55e2278
commit 678c44c7cd
12 changed files with 268 additions and 76 deletions
+30
View File
@@ -712,3 +712,33 @@ export const deleteAPIKey = async (token: string) => {
}
return res;
};
export const deleteOAuthSession = async (token: string, provider: string) => {
let error = null;
const res = await fetch(
`${WEBUI_API_BASE_URL}/auths/oauth/sessions/${encodeURIComponent(provider)}`,
{
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${token}`
}
}
)
.then(async (res) => {
if (!res.ok) throw await res.json();
return res.json();
})
.catch((err) => {
console.error(err);
error = err.detail;
return null;
});
if (error) {
throw error;
}
return res;
};
+1
View File
@@ -647,3 +647,4 @@ export const setBanners = async (token: string, banners: Banner[]) => {
return res;
};
+1
View File
@@ -483,3 +483,4 @@ export const updateUserValvesById = async (token: string, id: string, valves: ob
return res;
};
+1
View File
@@ -550,3 +550,4 @@ export const getUserGroupsById = async (token: string, userId: string) => {
return res;
};
@@ -13,8 +13,11 @@
} from '$lib/stores';
import { getOAuthClientAuthorizationUrl } from '$lib/apis/configs';
import { deleteOAuthSession } from '$lib/apis/auths';
import { getTools } from '$lib/apis/tools';
import { toast } from 'svelte-sonner';
import Knobs from '$lib/components/icons/Knobs.svelte';
import Dropdown from '$lib/components/common/Dropdown.svelte';
import Tooltip from '$lib/components/common/Tooltip.svelte';
@@ -27,6 +30,7 @@
import Terminal from '$lib/components/icons/Terminal.svelte';
import ChevronRight from '$lib/components/icons/ChevronRight.svelte';
import ChevronLeft from '$lib/components/icons/ChevronLeft.svelte';
import LinkSlash from '$lib/components/icons/LinkSlash.svelte';
const i18n = getContext('i18n');
@@ -375,6 +379,40 @@
</div>
</div>
{#if (tools[toolId]?.authenticated ?? true) && toolId.startsWith('server:mcp:')}
<div class="shrink-0">
<Tooltip content={$i18n.t('Disconnect OAuth')}>
<button
class="self-center w-fit text-sm text-gray-600 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 transition rounded-full"
type="button"
on:click={async (e) => {
e.stopPropagation();
e.preventDefault();
const parts = toolId.split(':');
const serverId = parts.at(-1) ?? toolId;
const provider = `mcp:${serverId}`;
try {
await deleteOAuthSession(localStorage.token, provider);
toast.success($i18n.t('OAuth session disconnected'));
// Refresh tools to update authenticated state
_tools.set(await getTools(localStorage.token));
// Remove from selected if it was selected
selectedToolIds = selectedToolIds.filter((id) => id !== toolId);
} catch (err) {
toast.error(err ?? $i18n.t('Failed to disconnect'));
}
}}
>
<LinkSlash className="size-3.5" />
</button>
</Tooltip>
</div>
{/if}
{#if tools[toolId]?.has_user_valves && ($user?.role === 'admin' || ($user?.permissions?.chat?.valves ?? true))}
<div class=" shrink-0">
<Tooltip content={$i18n.t('Valves')}>