fix: avoid oauth auto-close on non-oauth popups
Treating any state query parameter as OAuth caused generic popups to be misclassified and closed by the OAuth safety timer. Remove state= from OAuth request heuristics and add regression tests for non-OAuth state URLs and real authorize URLs.
- commit
- 64a59d7185b5e6cda14ae8d24f6b72109726c2a9
- author
- brice · · 2026-02-16 14:37 UTC
- parent
- 14868d8
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
2 files · +12 -1
M internal/ui/coordinator/oauth.go +0 -1
| @@ -48,7 +48,6 @@ var oauthRequestPatterns = []string{ | |||
| 48 | 48 | "client_id=", | |
| 49 | 49 | "redirect_uri=", | |
| 50 | 50 | "scope=", | |
| 51 | - | "state=", | |
| 52 | 51 | "nonce=", | |
| 53 | 52 | } | |
| 54 | 53 | ||
| @@ -48,7 +48,6 @@ var oauthRequestPatterns = []string{ | |||||
| 48 | "client_id=", | 48 | "client_id=", | ||
| 49 | "redirect_uri=", | 49 | "redirect_uri=", | ||
| 50 | "scope=", | 50 | "scope=", | ||
| 51 | - | "state=", | |||
| 52 | "nonce=", | 51 | "nonce=", | ||
| 53 | } | 52 | } | ||
| 54 | 53 | ||||
M internal/ui/coordinator/oauth_test.go +12 -0
| @@ -96,6 +96,18 @@ func TestHandlePopupOAuthClose_ErrorDoesNotScheduleParentRefresh(t *testing.T) { | |||
| 96 | 96 | assert.Nil(t, c.popupRefresh[parentPaneID], "oauth errors should not refresh parent pane") | |
| 97 | 97 | } | |
| 98 | 98 | ||
| 99 | + | func TestIsOAuthURL_DoesNotTreatGenericStateParamAsOAuth(t *testing.T) { | |
| 100 | + | url := "https://github.com/apps/linear/installations/new?state=Ar4EJk1ao3eyEDgSbYOtG8Cr4" | |
| 101 | + | ||
| 102 | + | assert.False(t, IsOAuthURL(url)) | |
| 103 | + | } | |
| 104 | + | ||
| 105 | + | func TestIsOAuthURL_DetectsOAuthAuthorizeRequest(t *testing.T) { | |
| 106 | + | url := "https://auth.openai.com/oauth/authorize?response_type=code&client_id=app_123&redirect_uri=http%3A%2F%2Flocalhost%3A1455%2Fauth%2Fcallback&scope=openid+profile+email+offline_access&state=abc" | |
| 107 | + | ||
| 108 | + | assert.True(t, IsOAuthURL(url)) | |
| 109 | + | } | |
| 110 | + | ||
| 99 | 111 | func waitFor(t *testing.T, timeout time.Duration, condition func() bool) { | |
| 100 | 112 | t.Helper() | |
| 101 | 113 | ||
| @@ -96,6 +96,18 @@ func TestHandlePopupOAuthClose_ErrorDoesNotScheduleParentRefresh(t *testing.T) { | |||||
| 96 | assert.Nil(t, c.popupRefresh[parentPaneID], "oauth errors should not refresh parent pane") | 96 | assert.Nil(t, c.popupRefresh[parentPaneID], "oauth errors should not refresh parent pane") | ||
| 97 | } | 97 | } | ||
| 98 | 98 | ||||
| 99 | + | func TestIsOAuthURL_DoesNotTreatGenericStateParamAsOAuth(t *testing.T) { | |||
| 100 | + | url := "https://github.com/apps/linear/installations/new?state=Ar4EJk1ao3eyEDgSbYOtG8Cr4" | |||
| 101 | + | ||||
| 102 | + | assert.False(t, IsOAuthURL(url)) | |||
| 103 | + | } | |||
| 104 | + | ||||
| 105 | + | func TestIsOAuthURL_DetectsOAuthAuthorizeRequest(t *testing.T) { | |||
| 106 | + | url := "https://auth.openai.com/oauth/authorize?response_type=code&client_id=app_123&redirect_uri=http%3A%2F%2Flocalhost%3A1455%2Fauth%2Fcallback&scope=openid+profile+email+offline_access&state=abc" | |||
| 107 | + | ||||
| 108 | + | assert.True(t, IsOAuthURL(url)) | |||
| 109 | + | } | |||
| 110 | + | ||||
| 99 | func waitFor(t *testing.T, timeout time.Duration, condition func() bool) { | 111 | func waitFor(t *testing.T, timeout time.Duration, condition func() bool) { | ||
| 100 | t.Helper() | 112 | t.Helper() | ||
| 101 | 113 | ||||