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)
returnView on GitHub (pinned to 78f0c4079e)
Solutions
- Ensure the callback is reached via a plain browser GET redirect (standard authorization-code flow)
- Test with curl without -X (defaults to GET) or curl -X GET "http://127.0.0.1:PORT/callback?code=x&state=y"
- 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
- Keep IdP response_mode as query (redirect), not form_post
- Health-check a different endpoint than the OAuth callback
- curl the callback without -X flags
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
- callback_timeout
- OAuth error: %s
- No authorization code received
- Method not allowed
- fetch Claude OAuth %s: HTTP client is nil
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/a4e62d9ffb3ccc82.
Report an issue: GitHub.