修复:`xurl` OAuth 2.0 在 X API 上因 'unauthorized_client' 失败

发布: (2026年2月23日 GMT+8 20:22)
6 分钟阅读
原文: Dev.to

Source: Dev.to

如果你正在使用 xurl 对 X API 进行身份验证,并且看到以下错误:

OAuth2 authentication failed: Auth Error: TokenExchangeError
(cause: oauth2: "unauthorized_client" "Missing valid authorization header")

解决办法只需在 X 开发者门户中进行一次设置。

为什么会发生

xurl 使用 OAuth 2.0 PKCE 流程,该流程面向 公共客户端(移动应用、CLI、SPA)。公共客户端在令牌交换时在请求体中发送凭证。

X API 应用默认被创建为 机密客户端。机密客户端必须通过 Authorization: Basic 头部发送凭证——而 xurl 并未使用此机制。当 xurl 在没有该头部的情况下发送令牌交换请求时,X 会以 unauthorized_client 拒绝。

您可以通过对客户端 ID 进行 base64 解码来确认应用类型:

echo "YOUR_CLIENT_ID" | base64 -d
  • 如果解码后的值以 :ci 结尾,则为机密客户端。
  • 如果以 :na 结尾,则为本地(公共)客户端。

修复方案

  1. 将您的 X 应用类型Web App 更改为 Native App,在开发者门户中。

  2. 在门户中:
    选择您的应用 → User authentication settingsEdit

    • App type 设置为 Native App
    • Callback URI 设置为 http://localhost:8080/callback
    • 保存
  3. 重新注册全新凭证 并使用 xurl 进行身份验证:

    # 在门户中重新生成凭证后,使用新凭证重新注册
    xurl auth apps add my-app \
      --client-id YOUR_NEW_CLIENT_ID \
      --client-secret YOUR_NEW_CLIENT_SECRET
    
    # 存储 bearer token 和 OAuth 1.0a 凭证(可选)
    xurl auth app --bearer-token YOUR_BEARER_TOKEN
    xurl auth oauth1 \
      --consumer-key YOUR_CONSUMER_KEY \
      --consumer-secret YOUR_CONSUMER_SECRET \
      --access-token YOUR_ACCESS_TOKEN \
      --token-secret YOUR_ACCESS_TOKEN_SECRET
    
    # 设置为默认应用
    xurl auth default my-app
    
    # 运行 PKCE 流程
    xurl --app my-app auth oauth2
  4. 完成基于浏览器的授权流程后,验证一切是否正常:

    xurl auth status
    xurl --auth oauth2 /2/users/me          # 用户上下文
    xurl --auth oauth1 /2/users/me          # 同样可用
    xurl --auth app "/2/tweets/search/recent?query=hello&max_results=5"  # 应用专用

额外:更改应用类型后重新生成凭证

当您切换应用类型时,X 会颁发一个带有 :na 后缀的新 Client ID。旧的 :ci ID 在 PKCE 流程中将失效,因此请在使用 xurl 重新注册之前,从 Keys and Tokens 选项卡复制新的值。

TL;DR

应用类型客户端 ID 后缀是否兼容 xurl OAuth 2.0?
Web 应用 / Bot:ci(机密)
本地应用 / SPA:na(公开)

将 X 开发者门户中的 Native App 更改为本地应用,重新生成凭据,xurl 的 OAuth 2.0 流程即可正常工作。

Web 应用程序支持 OAuth 2.0 吗?

Web App/Bot 应用确实支持 OAuth 2.0,但不是通过 xurl,因为 xurl 只实现了公共客户端的 PKCE 流程。机密客户端在令牌交换步骤需要 Authorization: Basic 头,而大多数 CLI 工具(包括 xurl)都不处理 X 的这种情况。

使用 curl 手动进行 OAuth 2.0

步骤 1 – 构建授权 URL 并在浏览器中打开:

# Generate a code verifier + challenge (PKCE is optional but recommended)
VERIFIER=$(openssl rand -base64 32 | tr -d '=+/' | cut -c1-43)
CHALLENGE=$(echo -n "$VERIFIER" | openssl dgst -sha256 -binary | base64 | tr '+/' '-_' | tr -d '=')
STATE=$(openssl rand -hex 16)

CLIENT_ID="YOUR_CLIENT_ID"
REDIRECT="http://localhost:8080/callback"

echo "https://x.com/i/oauth2/authorize?response_type=code&client_id=${CLIENT_ID}&redirect_uri=${REDIRECT}&scope=tweet.read%20users.read%20offline.access&state=${STATE}&code_challenge=${CHALLENGE}&code_challenge_method=S256"

在浏览器中打开打印出的 URL,进行授权,然后从重定向 URL 中复制 code=… 的值。

步骤 2 – 使用 Basic Auth 交换代码:

CLIENT_ID="YOUR_CLIENT_ID"
CLIENT_SECRET="YOUR_CLIENT_SECRET"
CODE="CODE_FROM_REDIRECT"
VERIFIER="THE_VERIFIER_FROM_STEP_1"

curl -X POST https://api.x.com/2/oauth2/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -H "Authorization: Basic $(echo -n "${CLIENT_ID}:${CLIENT_SECRET}" | base64 -w 0)" \
  -d "grant_type=authorization_code&code=${CODE}&redirect_uri=${REDIRECT}&code_verifier=${VERIFIER}"

响应中包含一个 access_token,可以直接在 xurl 中使用:

xurl -H "Authorization: Bearer ACCESS_TOKEN" /2/users/me

何时使用哪种方式

使用场景应用类型认证方式
CLI / 本地开发Native Appxurl oauth2 (PKCE, no secret)
服务器端应用Web App / BotOAuth 2.0 confidential (Basic Auth, secret stays on server)
以自己身份发布AnyOAuth 1.0a (simplest for personal use)
只读公共数据AnyBearer token (app‑only)

Web App/Bot + OAuth 2.0 旨在用于服务器端应用程序,客户端密钥永不离开您的服务器。对于本地 CLI 使用,Native App 是正确的选择。OAuth 1.0a 适用于任何应用类型,通常是个人或开发使用时阻力最小的方案。

0 浏览
Back to Blog

相关文章

阅读更多 »