chenhg5/cc-connect · error
unauthorized
Error message
unauthorized
What it means
HTTP 401 response from the webhook handler: the request failed the server's authenticate check (missing, malformed, or wrong shared secret/token), so the inbound prompt/exec request is rejected before decoding.
Source
Thrown at core/webhook.go:93
}()
}
func (ws *WebhookServer) Stop() {
if ws.server != nil {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
_ = ws.server.Shutdown(ctx)
}
}
func (ws *WebhookServer) handleHook(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "POST only", http.StatusMethodNotAllowed)
return
}
if !ws.authenticate(r) {
http.Error(w, "unauthorized", http.StatusUnauthorized)
return
}
var req WebhookRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, "invalid JSON: "+err.Error(), http.StatusBadRequest)
return
}
if req.SessionKey == "" {
http.Error(w, "session_key is required", http.StatusBadRequest)
return
}
if req.Prompt == "" && req.Exec == "" {
http.Error(w, "either prompt or exec is required", http.StatusBadRequest)
return
}
if req.Prompt != "" && req.Exec != "" {View on GitHub (pinned to 4000b2338a)
Solutions
- Add the correct Authorization header (Bearer <webhook-token>) matching the server's configured secret.
- Re-copy the token from config.toml after any change and restart/refresh the caller.
- Check for stray whitespace/quotes in the token in both config and client.
- Confirm the token actually reached the server (log headers server-side at debug level).
Example fix
// before
curl -X POST http://127.0.0.1:8849/hook -d '{"prompt":"hi"}'
// after
curl -X POST http://127.0.0.1:8849/hook -H "Authorization: Bearer $WEBHOOK_TOKEN" -d '{"session_key":"s1","prompt":"hi"}' Defensive patterns
Strategy: validation
Validate before calling
func webhookPayload(url, token string) error {
if token == "" { return errors.New("missing webhook token") }
req, _ := http.NewRequest(http.MethodPost, url, nil)
req.Header.Set("Authorization", "Bearer "+token)
return nil // inspect req before send
} Type guard
func isUnauthorized(resp *http.Response) bool { return resp != nil && resp.StatusCode == http.StatusUnauthorized } Try / catch
resp, err := client.Do(req)
if err == nil && resp.StatusCode == 401 {
return fmt.Errorf("webhook auth failed: token mismatch with WebhookServer secret")
} Prevention
- Keep the webhook token in a single config source read by all senders
- Trim whitespace/quotes when copying tokens
- Rotate the token and the sender together in one deploy
- Log (redacted) presence of the Authorization header server-side at debug level
When it happens
Trigger: POSTing to the hook endpoint without an Authorization header, with a wrong Bearer token, or with a token that does not match the WebhookServer's configured secret.
Common situations: Secret rotated in config but the calling service still uses the old one; curl test forgot the auth header; webhook sender configured without credentials; token copy-pasted with whitespace or quotes.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- webex: unauthorized (401) — check bot token
- unauthorized
- acp: authenticate (%s): %w
- remote returned non-zero code
- code=%d msg=%s
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/18584e46f7d16f89.
Report an issue: GitHub.