Apple SSO:为什么会出现“ unsupported_grant_type”错误?

时间:2019-09-09 21:33:08

标签: ios macos oauth single-sign-on

问题

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

docsunsupported_grant_type将在我The authenticated client is not authorized to use the grant type.在应用程序ID,服务ID上启用Apple SSO并甚至已验证我的支持电子邮件域时返回。我想念什么?要获得授权,我还需要完成其他批准步骤吗?

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

详细信息

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请求中提交的“服务ID”,@ key_id是从Apple Key仪表板下载的私钥的ID,@ team_id是我们的Apple Team ID。 retrieve_secret_cert只是获取用于生成客户端机密的cert文件主体。

鉴于所有这些,我希望得到一个TokenResponse,但会不断收到相同的错误{"error"=>"unsupported_grant_type"},而无需其他说明。

1 个答案:

答案 0 :(得分:0)

令牌验证请求需要使用 form 编码,而不是 json 编码。另外,当我在JWT中包含一个alg头时,该请求无法正确验证,但是在删除请求后,该请求就可以正常工作。

这是更新的代码:

    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指出编码错误。