sipeed/picoclaw · error

provider %q does not support browser oauth

Error message

provider %q does not support browser oauth

What it means

Returned as HTTP 400 by POST /api/oauth/login (browser method) via oauthConfigForProvider: only "openai" and "google-antigravity" have browser OAuth configs (auth.OpenAIOAuthConfig / auth.GoogleAntigravityOAuthConfig); the default branch of the switch produces this message. With the current method matrix it is effectively a defensive guard, because isOAuthMethodSupported already rejects browser login for anthropic earlier with error 961 — you can only reach 965 if the matrix and the config switch have drifted (e.g. browser was added to anthropic's methods without adding a config).

Source

Thrown at web/backend/api/oauth.go:273

		h.storeOAuthFlow(flow)

		w.Header().Set("Content-Type", "application/json")
		_ = json.NewEncoder(w).Encode(map[string]any{
			"status":     "ok",
			"provider":   provider,
			"method":     method,
			"flow_id":    flow.ID,
			"user_code":  flow.UserCode,
			"verify_url": flow.VerifyURL,
			"interval":   flow.Interval,
			"expires_at": flow.ExpiresAt.Format(time.RFC3339),
		})
		return

	case oauthMethodBrowser:
		cfg, err := oauthConfigForProvider(provider)
		if err != nil {
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}

		pkce, err := oauthGeneratePKCE()
		if err != nil {
			http.Error(w, fmt.Sprintf("failed to generate PKCE: %v", err), http.StatusInternalServerError)
			return
		}
		state, err := oauthGenerateState()
		if err != nil {
			http.Error(w, fmt.Sprintf("failed to generate state: %v", err), http.StatusInternalServerError)
			return
		}

		redirectURI := buildOAuthRedirectURI(r)
		authURL := oauthBuildAuthorizeURL(cfg, pkce, state, redirectURI)

		now := oauthNow()

View on GitHub (pinned to 49183d7e8d)

Solutions

  1. If you are a caller: this should normally be unreachable — first check that the method matrix really allows browser for the provider, then upgrade/redeploy the backend so matrix and config agree.
  2. If you are modifying the backend: every provider you add to oauthProviderMethods[provider] with "browser" must also get a case in oauthConfigForProvider returning an auth.OAuthProviderConfig.
  3. Add a unit test asserting each provider in oauthProviderMethods with browser support passes oauthConfigForProvider without error, so the drift is caught at build time.

Example fix

// before (web/backend/api/oauth.go)
var oauthProviderMethods = map[string][]string{
    oauthProviderAnthropic: {oauthMethodBrowser, oauthMethodToken}, // browser advertised...
}
func oauthConfigForProvider(provider string) (auth.OAuthProviderConfig, error) {
    switch provider {
    case oauthProviderOpenAI: return auth.OpenAIOAuthConfig(), nil
    case oauthProviderGoogleAntigravity: return auth.GoogleAntigravityOAuthConfig(), nil
    default: return auth.OAuthProviderConfig{}, fmt.Errorf("provider %q does not support browser oauth", provider) // ...but no config
    }
}

// after: add the matching case
func oauthConfigForProvider(provider string) (auth.OAuthProviderConfig, error) {
    switch provider {
    case oauthProviderOpenAI: return auth.OpenAIOAuthConfig(), nil
    case oauthProviderGoogleAntigravity: return auth.GoogleAntigravityOAuthConfig(), nil
    case oauthProviderAnthropic: return auth.AnthropicOAuthConfig(), nil
    default: return auth.OAuthProviderConfig{}, fmt.Errorf("provider %q does not support browser oauth", provider)
    }
}
Defensive patterns

Strategy: validation

Validate before calling

const BROWSER_CAPABLE = new Set(['openai', 'google-antigravity']);
function assertBrowserSupported(provider) {
  if (!BROWSER_CAPABLE.has(provider)) throw new Error(`provider ${JSON.stringify(provider)} does not support browser oauth`);
}

Type guard

function supportsBrowserOauth(provider) {
  return ['openai', 'google-antigravity'].includes(provider);
}

Prevention

When it happens

Trigger: POST /api/oauth/login {"provider":"anthropic","method":"browser"} in a build where oauthProviderMethods lists browser for anthropic but oauthConfigForProvider still has no anthropic case; or any new provider added to the methods map with browser support but no branch in oauthConfigForProvider.

Common situations: Local fork or PR that adds a provider's browser method but forgets the config switch; regression after refactoring oauthProviderMethods; hitting an older backend with a newer frontend that assumes a method exists.

Related errors


AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15). Data as JSON: /api/errors/bec44c8fa19c1103. Report an issue: GitHub.