You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ruby on Rails集成Xero API获取Token Set时遇invalid_client错误求助

Xero API集成Ruby on Rails时get_token_set_from_callback返回invalid_client错误排查

错误现象

调用get_token_set_from_callback获取Token Set时触发XeroRuby::ApiError,HTTP状态码400,响应体为{"error":"invalid_client"},完整错误详情:

*** XeroRuby::ApiError Exception: Error message: the server returns an error

HTTP status code: 400

Response headers: {"content-type"=>"application/json; charset=UTF-8", "server"=>"nginx", "xero-origin-id"=>"IdentityServer.Web", "xero-causation-id"=>"63c9c7b03d7f435aa5dd801d96e8c152", "xero-message-id"=>"9e6951801da040ac94f61ab3392e3feb", "xero-activity-id"=>"adbfa8002310478c9d223f71e47b5b17", "xero-correlation-id"=>"6069553f3b9843f992e54f59f7bde8c0", "content-length"=>"26", "expires"=>"Wed, 01 Feb 2023 12:40:41 GMT", "cache-control"=>"max-age=0, no-cache, no-store", "pragma"=>"no-cache", "date"=>"Wed, 01 Feb 2023 12:40:41 GMT", "connection"=>"close", "set-cookie"=>"Device=961bc311701f4e20a0a2a7c0b6900dad; expires=Tue, 01 Feb 2028 12:40:41 GMT; path=/; samesite=none; httponly, _abck=CF3C26F9436304BF37101493FFAD83AF~-1~YAAQscNQaDKxnNKFAQAAPFz+DAnlKYqiZGnjCEbMvoyet1jSR8zH92SopvoLwB4qij7m04HY3vz38HatmtYuYAgN43HShtEj4miB94A9kiGQvrTNgMw9fNcpXV5sZ7JVNARjYdFjRYo0hU/n+qpWeEFH5OgBb8gzYVcOP5KqhPLgOd2ctiJrhmWiEmaeNZVbKj/spi60wt24oTv4jeWSplHq+i1LIzvPWLsVSU8RGKddmx+w7QnmtuWgbogouQljdvXS2Hrp9jDQsQXbvC9cWLy7A4AINQy7DLKP53mRgbqhdl7rG4Zyy8Bkv8nuxJvboM1MmdmorDngUVMNKkxpfdrWfJB5dv1Dbs3BOxJS2s9lRN56ugyI~-1~-1~-1; Domain=.xero.com; Path=/; Expires=Thu, 01 Feb 2024 12:40:41 GMT; Max-Age=31536000; Secure, bm_sz=D5B91089FE0B5C15AAF78A78C3DC4631~YAAQscNQaDOxnNKFAQAAPFz+DBKO2MjN+su/jV34lpo0F8Da/HIe1gG6gWfP7mzR6F7LwAPpRmm2lbXSjxw8/92CaTTcdsebzypKwiiowvOYOOI5/2TdwwcrU2bLSe9jN9YgUIS5izdAcysuz8S4pjx5OnNVe1HvhmUOeX8P/njVXeF7sQbFwmoAz3HyAO2AbJK0FGybHT8Spbfujl91GJ8+8YUf8voUQObj8r7o3K3GbWCycMG0lp6yupNoF7qfkPEuIl2vzMNCF0m2ZLH9a+akzpzc14KqjSwuz3k+++NK~3551286~3225656; Domain=.xero.com; Path=/; Expires=Wed, 01 Feb 2023 16:40:41 GMT; Max-Age=14400"}

Response body: {"error":"invalid_client"}

相关代码

Token获取调用代码

@token_set = @xero_client.get_token_set_from_callback(params[:code])

HomeController代码

class HomeController < ApplicationController
  def index
    require 'xero-ruby'
    require 'httparty'
    creds = {
      client_id: '...',
      client_secret: '...',
      redirect_uri: 'http://localhost:3000/login',
      scopes: 'accounting.attachments',
      state: "Optional value to pass through auth flow"
    }
    config = { timeout: 30, debugging: true }
    @xero_client ||= XeroRuby::ApiClient.new(credentials: creds, config: config)
    @authorization_url = @xero_client.authorization_url
  end
end

LoginController代码

class LoginController < ApplicationController
  def index
    require 'xero-ruby'
    creds = {
      client_id: '...',
      client_secret: '...',
      redirect_uri: 'http://localhost:3000/login',
      scopes: 'accounting.attachments',
      state: "Optional value to pass through auth flow"
    }
    config = { timeout: 30, debugging: true }
    @xero_client ||= XeroRuby::ApiClient.new(credentials: creds, config: config)
    byebug
    @token_set = @xero_client.get_token_set_from_callback(params[:code])
  end
end

排查原因

invalid_client错误本质是Xero身份服务无法识别你的客户端凭证,常见原因包括:

  • Client ID或Client Secret填写错误,存在多余空格、换行或大小写差异
  • 代码中的redirect_uri与Xero开发者后台配置的地址不完全匹配(包括协议、端口、路径)
  • 客户端实例重复初始化导致配置不一致
  • 敏感凭证硬编码时出现复制错误

解决方案

  1. 核对客户端凭证
    登录Xero开发者门户,进入应用详情页面,复制精确的Client ID和Client Secret,替换代码中的占位符,确保无多余字符。

  2. 验证Redirect URI匹配
    在Xero应用的「Authentication」设置页,检查「Redirect URIs」列表是否包含http://localhost:3000/login,必须完全一致(协议、端口、路径均不能有差异),若缺失则添加该地址。

  3. 统一客户端实例配置
    避免在多个控制器中重复初始化Xero客户端,可将配置抽成初始化器:
    创建config/initializers/xero.rb:

    require 'xero-ruby'
    
    XERO_CREDENTIALS = {
      client_id: ENV['XERO_CLIENT_ID'],
      client_secret: ENV['XERO_CLIENT_SECRET'],
      redirect_uri: 'http://localhost:3000/login',
      scopes: 'accounting.attachments'
    }
    
    XERO_CONFIG = { timeout: 30, debugging: true }
    
    def xero_client
      @xero_client ||= XeroRuby::ApiClient.new(credentials: XERO_CREDENTIALS, config: XERO_CONFIG)
    end
    

    之后在控制器中直接调用xero_client即可,减少配置不一致风险。

  4. 使用环境变量存储敏感信息
    不要将Client ID和Secret硬编码在代码中,使用dotenv gem管理环境变量,创建.env文件:

    XERO_CLIENT_ID=你的ClientID
    XERO_CLIENT_SECRET=你的ClientSecret
    

    确保.env文件被添加到.gitignore中,避免凭证泄露。

内容的提问来源于stack exchange,提问作者Jack Dawson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 05:50:28