Apple SSO:为什么我收到 'unsupported_grant_type' 错误?

Apple SSO: Why I am getting a 'unsupported_grant_type' error?

问题

当我尝试验证从 Apple SSO 客户端流程返回的 code 时,我不断收到 unsupported_grant_type 400 错误。

docs 说当 The authenticated client is not authorized to use the grant type. 我在应用程序 ID、服务 ID 上启用了 Apple SSO,甚至验证了我的支持电子邮件时,将返回 unsupported_grant_type域。我错过了什么?我需要完成其他批准步骤才能获得授权吗?

我已经尝试从我的验证请求中删除参数,但仍然得到相同的错误代码。

详情

SSO 重定向为我提供了一个表单编码的 POST 正文,看起来像这样:{"state"=>"x", "code"=>"y", "id_token"=>"z"}.

然后我尝试通过调用 validate_auth_token.

来验证令牌
   def validate_auth_token(token, is_refresh = false)
      uri = URI.parse('https://appleid.apple.com/auth/token')
      https = Net::HTTP.new(uri.host, uri.port)
      https.use_ssl = true
      headers = { 'Content-Type': 'text/json' }
      request = Net::HTTP::Post.new(uri.path, headers)
      request_body = {
        client_id: @client_id,
        client_secret: retreive_client_secret
      }

      if is_refresh
        request_body[:grant_type] = 'refresh_token'
        request_body[:refresh_token] = token
      else
        request_body[:grant_type] = 'authorization_code'
        request_body[:code] = token
        request_body[:redirect_uri] = "https://#{Rails.application.secrets.backend_host_port}/apple"
      end

      request.body = request_body.to_json
      response = https.request(request)
      p JSON.parse response.body
    end

    def retreive_client_secret
      cert = retreive_secret_cert
      ecdsa_key = OpenSSL::PKey::EC.new cert
      algorithm = 'ES256'

      headers = {
        'alg': algorithm,
        'kid': @key_id
      }

      claims = {
        'iss': @team_id,
        'iat': Time.now.to_i,
        'exp': Time.now.to_i + 5.months.to_i,
        'aud': 'https://appleid.apple.com',
        'sub': @client_id
      }

      token = JWT.encode claims, ecdsa_key, algorithm, headers
      token
    end

其中@client_id是我在初始SSO请求中提交的"Service ID",@key_id是从apple key dashboard下载的私钥id,@team_id 是我们的 apple team id。 retrieve_secret_cert 只是获取用于生成客户端密钥的证书文件主体。

考虑到这一切,我希望得到一个 TokenResponse,但不断收到相同的错误 {"error"=>"unsupported_grant_type"},没有额外的解释。

令牌验证请求需要 form 编码,而不是 json 编码。此外,当我在 JWT 中包含 alg header 时,请求未正确验证,但在我删除它后有效。

这是更新后的代码:

    def validate_auth_token(token, is_refresh = false)
      uri = URI.parse('https://appleid.apple.com/auth/token')
      https = Net::HTTP.new(uri.host, uri.port)
      https.use_ssl = true
      request_body = {
        client_id: @client_id,
        client_secret: retreive_client_secret
      }

      if is_refresh
        request_body[:grant_type] = 'refresh_token'
        request_body[:refresh_token] = token
      else
        request_body[:grant_type] = 'authorization_code'
        request_body[:code] = token
        request_body[:redirect_uri] = "https://#{Rails.application.secrets.backend_host_port}/auth"
      end

      request = Net::HTTP::Post.new(uri.path)
      request.set_form_data(request_body)

      response = https.request(request)
      JSON.parse response.body
    end

    def retreive_client_secret
      cert = retreive_secret_cert
      ecdsa_key = OpenSSL::PKey::EC.new cert
      algorithm = 'ES256'

      headers = {
        'kid': @key_id
      }

      claims = {
        'iss': @team_id,
        'iat': Time.now.to_i,
        'exp': Time.now.to_i + 5.minutes.to_i,
        'aud': 'https://appleid.apple.com',
        'sub': @client_id
      }

      token = JWT.encode claims, ecdsa_key, algorithm, headers
      token
    end

感谢sudhakar19指出编码错误。