【问题标题】:TDAmeritrade API Authentication Error: Failed to resolve API Key variable request.header.unTDAmeritrade API 身份验证错误:无法解析 API 密钥变量 request.header.un
【发布时间】:2020-06-04 16:53:55
【问题描述】:

我在使用 PHP (https://developer.tdameritrade.com/authentication/apis/post/token-0) 从令牌端点获取访问令牌时遇到困难

特别是,我收到以下错误:

{ "error":"无法解析 API Key 变量 request.header.un" }

我使用 PHP 的请求是:

  $url = 'https://api.tdameritrade.com/v1/oauth2/token';

  $client_id = $customer_key ;

   $redirect_uri = $redirect_URL;
  $myvars = array("grant_type" => "authorization_code"
                  , "access_type" => "offline"
                  , "client_id" => $client_id
                   , "redirect_uri" => $redirect_URL
                  , "code" => "$code");

  $ch = curl_init( $url );
  curl_setopt( $ch, CURLOPT_POST, 1);
  curl_setopt( $ch, CURLOPT_POSTFIELDS, $myvars);
  curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, 1);
  curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1);
  curl_setopt( $ch, CURLOPT_VERBOSE, 1);
  curl_setopt( $ch, CURLOPT_HTTPHEADER, array(
    'Content-Type: application/x-www-form-urlencoded; charset=utf-8'

          ));

  $response = curl_exec( $ch );
  echo "<br>token = '$response'\n";

}

谢谢!

【问题讨论】:

标签: php api oauth


【解决方案1】:

当我收到完全相同的错误消息时,我找到了这个页面。经过多次尝试并离开几次后,我终于弄明白了。与您发布的内容相比,最大的变化是当您使用标题时: "Content-Type: application/x-www-form-urlencoded" TD 想要这个 API,你需要将 $myvars 数组变成一个字符串,如下所示:

$myvars = "grant_type=authorization_code&access_type=offline&code=".$code."&client_id=".$client_id."&redirect_uri=".urlencode($redirect_uri);

这里的另一个注意事项是 urlencode 函数,用于帮助对字符串进行 url 编码。它在此页面的“注释”部分中谈到了这一点:

https://www.php.net/manual/en/function.curl-setopt.php

【讨论】:

  • 感谢您的建议!如您所见,我已经为此苦苦挣扎了一段时间。我试过你建议的修改,现在我收到以下错误:“错误”:“invalid_grant”有什么建议吗?当我尝试使用 TD 的沙箱时,我也收到此错误:developer.tdameritrade.com/authentication/apis/post/token-0
  • 哦,抱歉,请仔细检查您的 $code 变量是否也是 URL 编码的。我忘记了。如果您按照developer.tdameritrade.com/content/simple-auth-local-apps 的指南进行操作,他们会谈到需要对您在 URL 中返回的代码参数进行 URL 解码,以便在您刚刚链接到的页面上的 TD 表单中使用,但您需要对其进行编码在您进行 API 调用时的字符串中。当您手动执行时,工作量会更大(与我第一次执行的方式相同)。
  • 是的,我有:$code = urldecode($code); $code = str_replace("", "+", $code);我仍然遇到同样的错误。如果我私信你我的代码,你能运行它吗?我的TD账户可能有问题。他们早些时候关闭了我的帐户,因为它处于休眠状态。我重新打开了一个新的。所以我不确定这是否是他们的目的。
  • 好的,这行得通。我的另一个想法是,您可能必须返回并从本地应用程序的简单身份验证页面的第 1 步获取新的身份验证代码,然后在这些 PHP 代码更改后再次尝试 TD 令牌表单/您的脚本?我只是尝试使用我拥有的最后一个代码运行该 TD 令牌 Web 表单,但我也收到了“invalid_grant”错误。但是,我的 PHP 代码可以很好地使用我拥有的有效刷新令牌从多个 API 中提取,然后获取访问令牌。
  • 我认为我的问题在于标题。现在我有: curl_setopt($ch,CURLOPT_HTTPHEADER,array ('Authorization: Bearer $code' ));我收到错误“源变量:基本身份验证解码策略的 request.header.Authorization 无效”
【解决方案2】:

好的,我终于得到了一个有效的 PHP 脚本,它通过 TD API 进行身份验证并获取帐户信息。我想与大家分享它,因为在将近三个月后我无法弄清楚如何让它工作。特别感谢 Ninet3 帮助我。您可以将问题直接发送到他的 Fiverr 个人资料 (https://www.fiverr.com/ninety3)

$redirect_URL = 'https://YourURL.com';
$redirect_URL = urlencode($redirect_URL);
$customer_key = 'XXXXXXXXXXXXXXXXXXXX';
$account_number = '1234567890';

$url_endpoint = 'https://auth.tdameritrade.com/auth?response_type=code&redirect_uri='.$redirect_URL. '&client_id='.$customer_key.'%40AMER.OAUTHAP';

if(NULL === @$_GET['code']) {
    header("Location: $url_endpoint");//open TD website to get tokens
}


if($_GET['code'] !== '') {
    $code = $_GET['code'];

    $code = urlencode($code);
    if($code){
        $curl = curl_init();

        curl_setopt_array($curl, array(
            CURLOPT_URL => 'https://api.tdameritrade.com/v1/oauth2/token',
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_MAXREDIRS => 10,
            CURLOPT_TIMEOUT => 0, CURLOPT_HEADER  => false,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_CUSTOMREQUEST => 'POST',
            CURLOPT_HTTPHEADER => array('Content-Type: application/x-www-form-urlencoded',
            ),
            CURLOPT_POSTFIELDS => 'grant_type=authorization_code&refresh_token=&access_type=offline&code='.$code.'&client_id='.$customer_key.'&redirect_uri='.$redirect_URL,
        ));

        $response = curl_exec($curl);

        curl_close($curl);
        $response = (json_decode($response, true));
                echo '<pre>';
                echo 'access_token: <br>';
                print_r($response );


 //Get account information      
        if(@$response['access_token'] !== null){
            $acc = $account_number;
            $curl = curl_init();

            curl_setopt_array($curl, array(
                CURLOPT_URL => 'https://api.tdameritrade.com/v1/accounts/'.$acc,
                CURLOPT_RETURNTRANSFER => true,
                CURLOPT_ENCODING => "",
                CURLOPT_MAXREDIRS => 10,
                CURLOPT_TIMEOUT => 0,
                CURLOPT_FOLLOWLOCATION => true,
                CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
                CURLOPT_CUSTOMREQUEST => 'GET',
                CURLOPT_HTTPHEADER => array(
                    'Authorization: Bearer '.$response['access_token'],
                ),
            ));

            $response = curl_exec($curl);

            curl_close($curl);
            echo '<pre>'.$response;

        }else{
            echo 'unable to get access token'; exit;
        }
    }
    else{
        echo 'No Code Found'; exit;
    }
}else{
    echo 'No Code Found'; exit;
}

您需要将令牌存储在数据库中,并在时间到期后刷新以获取新令牌。

【讨论】:

  • 感谢发帖,我完全明白了。除了,我对 $code、access_token 和刷新令牌感到困惑吗?因此,当我的 access_token 到期(通常在 30 分钟内)时,我是否必须再次执行整个 $url_endpoint / 代码过程? TD 文档在 refresh_token 上并不是很清楚,我已经厌倦了使用它,但随后无缘无故过期。同样在您的 $url_endpoint 上,这不需要您通过用户界面登录还是您已经在另一个浏览器选项卡中登录?
  • 伙计,非常感谢你。我实际上已经尝试了一个月来让它工作,这是我发现的第一个工作代码示例。我不知道这与他们自己为我生成的手动 CURL 命令有何不同,每次都因“无效授权”而失败,但确实如此。我填写了我的详细信息,它无需修改即可工作。甜!
猜你喜欢
  • 2016-01-29
  • 1970-01-01
  • 2020-06-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-20
  • 2019-09-04
相关资源
最近更新 更多