router-for-me/CLIProxyAPI · warning

Method not allowed

Error message

Method not allowed

What it means

The Claude OAuth callback HTTP handler only accepts GET. Any other method (POST from a misconfigured redirect, HEAD health probe, PUT/DELETE) receives a 405 with body "Method not allowed" and, importantly, no OAuthResult is sent — the waiting exchange is not completed by this path.

Source

Thrown at internal/auth/claude/oauth_server.go:173

		return nil, err
	case <-time.After(timeout):
		return nil, fmt.Errorf("timeout waiting for OAuth callback")
	}
}

// handleCallback handles the OAuth callback endpoint.
// It extracts the authorization code and state from the callback URL,
// validates the parameters, and sends the result to the waiting channel.
//
// Parameters:
//   - w: The HTTP response writer
//   - r: The HTTP request
func (s *OAuthServer) handleCallback(w http.ResponseWriter, r *http.Request) {
	log.Debug("Received OAuth callback")

	// Validate request method
	if r.Method != http.MethodGet {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	// Extract parameters
	query := r.URL.Query()
	code := query.Get("code")
	state := query.Get("state")
	errorParam := query.Get("error")

	// Validate required parameters
	if errorParam != "" {
		log.Errorf("OAuth error received: %s", errorParam)
		result := &OAuthResult{
			Error: errorParam,
		}
		s.sendResult(result)
		http.Error(w, fmt.Sprintf("OAuth error: %s", errorParam), http.StatusBadRequest)
		return

View on GitHub (pinned to 78f0c4079e)

Solutions

  1. Ensure the callback is reached via a plain browser GET redirect (standard authorization-code flow)
  2. Test with curl without -X (defaults to GET) or curl -X GET "http://127.0.0.1:PORT/callback?code=x&state=y"
  3. If your IdP forces form_post response mode, switch it to query (default) so the callback arrives as GET

Example fix

# before
curl -X POST "http://127.0.0.1:1455/auth/callback?code=abc&state=xyz"
# 405 Method not allowed

# after
curl "http://127.0.0.1:1455/auth/callback?code=abc&state=xyz"
Defensive patterns

Strategy: validation

Validate before calling

if r.Method != http.MethodGet {
    w.Header().Set("Allow", http.MethodGet)
    http.Error(w, "GET only", http.StatusMethodNotAllowed)
    return
}
// (when proxying or probing the callback yourself, always issue GET)

Type guard

func isGet(r *http.Request) bool { return r.Method == http.MethodGet }

Try / catch

// Caller side: the channel wait surfaces failures — check the result
result, err := server.WaitForCode(ctx)
if err != nil || result.Error != "" { log.Printf("oauth failed: %v %s", err, result.Error) }

Prevention

When it happens

Trigger: Sending POST /callback?code=... (e.g. an IdP configured with response_mode=form_post), curl -X POST, or a load-balancer health check hitting the callback route with HEAD/POST.

Common situations: Identity providers or proxies that convert the redirect into a form POST; testing the callback with the wrong curl verb; monitoring probes firing during the auth window.

Related errors


AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15). Data as JSON: /api/errors/a4e62d9ffb3ccc82. Report an issue: GitHub.