Skip to content

QQ channel fails with 401 "Authorization参数格式错误" — root cause in botgo v0.2.1 + resty >= v2.17 #3365

Description

@crazysarah

Environment

  • Device: Orange Pi 3B (RK3566, aarch64)
  • picoclaw: nightly build (--version reports 0.3.1), module github.com/sipeed/picoclaw
  • botgo: github.com/tencent-connect/botgo v0.2.1 (latest available)
  • resty: github.com/go-resty/resty/v2 v2.17.1 (indirect dependency)

Symptom

The QQ channel fails to start. The gateway log shows:

failed to get websocket info: HTTP 401
code:11241  err_code:40011005
message: "请求头Authorization参数格式错误"

The credentials are valid — calling POST https://bots.qq.com/app/getAppAccessToken with the same appId/clientSecret returns a valid access_token.

What is actually sent (MITM capture)

Intercepting the real TLS traffic from picoclaw to api.sgroup.qq.com:

GET /gateway/bot HTTP/1.1
User-Agent:    BotGoSDK/v0.0.2
Authorization: Bearer VEf7J-...        <-- WRONG, must be "QQBot"
X-Union-Appid: 1903802227

Cross-check on the same machine/token:

Authorization header Result
QQBot <token> 200, gateway returned
Bearer <token> 401 / 11241 / 40011005
empty 401 / 11241 / 40011005

Root cause (upstream, in botgo)

This is not a bug in picoclaw's own code — picoclaw is a victim of an incompatibility between botgo v0.2.1 and resty v2.17.1.

  1. botgo's token source sets the correct type: TokenType: TypeQQBot ("QQBot").

  2. botgo openapi/v1/openapi.go setupClient() sets the auth scheme inside an OnBeforeRequest hook on the resty Client, and discards the *resty.Request argument:

    OnBeforeRequest(func(c *resty.Client, _ *resty.Request) error {
        tk, err := o.tokenSource.Token()
        ...
        c.SetAuthScheme(tk.TokenType)   // Client-level, set AFTER R() ran
        c.SetAuthToken(tk.AccessToken)
    })
  3. resty >= v2.17 snapshots AuthScheme: c.AuthScheme (default "Bearer") into the Request at Client.R() time, and its addCredentials() now reads only the request-level scheme. The old client-level fallback (else if !IsStringEmpty(c.AuthScheme)) was removed. So the request that was already built keeps "Bearer" regardless of the later c.SetAuthScheme(...).

Full source-level analysis (with the exact resty v2.11.0 vs v2.17.1 diffs) is available if needed.

Impact

Every project that combines botgo v0.2.1 (the only/latest release) with resty >= v2.17.0 has a completely broken QQ channel.

Suggested fixes (for picoclaw maintainers)

  • Pin the indirect dependency to a resty version that still has the client-level AuthScheme fallback (e.g. v2.16.x) — please verify the fallback branch exists in the chosen version — OR

  • replace botgo with a fork that sets the scheme on the *resty.Request:

    OnBeforeRequest(func(_ *resty.Client, req *resty.Request) error {
        tk, err := o.tokenSource.Token()
        ...
        req.SetAuthScheme(tk.TokenType)   // request-level
        req.SetAuthToken(tk.AccessToken)
    })

    This is correct on both old and new resty (request-level SetAuthScheme overrides the client-level one).

I'm also submitting a PR with the 3-line fix to tencent-connect/botgo.

Note: the QQ channel (pkg/channels/qq/) only exists on main/nightly, not in the v0.3.1 tag — worth keeping in mind if anyone tries to reproduce on the tagged release.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions