From a5176f4cdac144b45d8515978568c67ca77d0214 Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Wed, 30 Sep 2026 17:49:25 +0200 Subject: [PATCH] fix: Google MCP connections drop about an hour after signing in (#31395) MCP tool servers that sign in through Google, such as Google's hosted Gmail, Drive and Calendar servers, never got a refresh token, because Google only issues one when the sign-in explicitly asks for offline access. When the one-hour access token ran out the refresh failed and the connection was removed, so every user had to sign in again every hour. When the server's sign-in page is Google's, the sign-in now asks for offline access and a fresh consent, so the token renews on its own. Other providers get the same sign-in request as before, and existing Google connections pick this up the next time the user signs in. Fixes #28319 --- backend/open_webui/utils/oauth.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/backend/open_webui/utils/oauth.py b/backend/open_webui/utils/oauth.py index 281d352716..fd4a046ba0 100644 --- a/backend/open_webui/utils/oauth.py +++ b/backend/open_webui/utils/oauth.py @@ -789,6 +789,11 @@ def should_send_oauth_resource(client_info: OAuthClientInformationFull | None) - return not scope_has_resource_indicator(client_info.scope) +def uses_google_authorization_server(client_info: OAuthClientInformationFull) -> bool: + server_metadata = client_info.server_metadata + return server_metadata is not None and server_metadata.authorization_endpoint.host == 'accounts.google.com' + + def build_oauth_request_params(client_info: OAuthClientInformationFull | None) -> dict: if not client_info: return {} @@ -798,6 +803,10 @@ def build_oauth_request_params(client_info: OAuthClientInformationFull | None) - params['scope'] = client_info.scope if should_send_oauth_resource(client_info): params['resource'] = client_info.resource + # Google only issues a refresh token for offline access, and only re-issues it on a fresh consent. + if uses_google_authorization_server(client_info): + params['access_type'] = 'offline' + params['prompt'] = 'consent' return params