From 789cf15afd7d9f6b579f8351ee441a5b1a03e1e3 Mon Sep 17 00:00:00 2001 From: Arthur Breitman Date: Thu, 18 Jun 2026 21:34:56 +0000 Subject: [PATCH] feat(web): surface OAuth callback URL on the settings page Operators hitting "Error 400: redirect_uri_mismatch" on Google's consent screen have no easy way to discover what URL Sieve actually sends as the OAuth redirect_uri. The Settings page lets them configure public_base_url but never tells them the resulting callback URL to register on the provider side. Compute and display the callback URL right under the public_base_url input. The displayed value is derived via the same s.publicBaseURL(r) helper that googleOAuthConfig.RedirectURL uses, so it's byte-for-byte what the OAuth flow will send. The block carries select-all styling so the operator can copy-paste it directly into Google Cloud Console (Authorized redirect URIs), a Slack App, or a GitHub App config. Same template change benefits Slack and GitHub OAuth flows that share the /oauth/callback path. Co-Authored-By: Claude Opus 4.7 (1M context) --- internal/web/server.go | 6 ++++++ internal/web/templates/settings.html | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/internal/web/server.go b/internal/web/server.go index 41e4c68..0f3d97c 100644 --- a/internal/web/server.go +++ b/internal/web/server.go @@ -2154,6 +2154,12 @@ func (s *Server) handleSettings(w http.ResponseWriter, r *http.Request) { "LLMModel": allSettings[settings.KeyLLMModel], "LLMMaxTokens": maxTokens, "PublicBaseURL": allSettings[settings.KeyPublicBaseURL], + // Derived from PublicBaseURL via the same publicBaseURL() helper + // used by googleOAuthConfig.RedirectURL, so what the operator sees + // here is byte-for-byte the URL Sieve will send to OAuth providers. + // Surfacing it on the settings page is the lowest-friction way to + // avoid Error 400: redirect_uri_mismatch on the provider side. + "OAuthCallbackURL": s.publicBaseURL(r) + "/oauth/callback", "CommandAllowlist": allSettings[settings.KeyCommandAllowlist], "AdminTLSCertPath": allSettings[settings.KeyAdminTLSCertPath], "AdminTLSKeyPath": allSettings[settings.KeyAdminTLSKeyPath], diff --git a/internal/web/templates/settings.html b/internal/web/templates/settings.html index b7f2ddf..341891f 100644 --- a/internal/web/templates/settings.html +++ b/internal/web/templates/settings.html @@ -126,6 +126,11 @@

LLM Co placeholder="http://127.0.0.1:19816" class="w-full rounded-lg bg-slate-700 border border-slate-600 text-white px-3 py-2.5 text-sm placeholder-slate-400 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent">

Externally-visible base URL used when Sieve constructs OAuth callback / redirect / setup URLs (GitHub App manifest, Google OAuth, Slack install). Default http://127.0.0.1:19816 matches the documented loopback production binding. Set this to your reverse-proxy URL if the admin UI is reached at a different address — never relied on inbound Host headers.

+
+

OAuth callback URL Sieve will send

+

Register this URL in your Google Cloud Console OAuth client (Authorized redirect URIs), your Slack App config, and any other OAuth provider you use. A mismatch produces Error 400: redirect_uri_mismatch on the provider's consent screen and the user cannot complete authentication.

+ {{.OAuthCallbackURL}} +