UPS API OAuth 令牌请求失败

Con*_*ver 18 ups oauth oauth-2.0

UPS 开发人员门户中,我创建了一个具有客户端 ID 和客户端密钥的应用程序。接下来,我想获取 OAuth 令牌,以便可以使用它来访问他们的其他 API。我正在根据规范创建令牌请求创建令牌请求,但收到以下错误:

\n
{"response":{"errors":[{"code":"10400","message":"Invalid/Missing Authorization Header"}]}}\n
Run Code Online (Sandbox Code Playgroud)\n

该规范具有“试用”功能,您可以在其中获取测试令牌。它提示用户填写x-merchant-id参数和grant_type表单变量,并创建一个如下所示的curl 请求:

\n
curl -X POST "https://wwwcie.ups.com/security/v1/oauth/token" \n     -H "accept: application/json" \n     -H "x-merchant-id: {My_Client_Id_Goes_Here}" \n     -H "Content-Type: application/x-www-form-urlencoded" \n     -d "grant_type=client_credentials"\n
Run Code Online (Sandbox Code Playgroud)\n

对于 x-merchant_id,我使用了我的 app\xe2\x80\x99s 客户端 ID。不清楚 grant_type 的值是否应为短语client_credentials(该页面看起来这是唯一有效的值)还是 my app\xe2\x80\x99s 实际的客户端密钥。我都尝试过,但每次都出现相同的错误。

\n

有上百万个关于如何使用其(旧式)API 密钥的示例,但除了上面链接的说明之外,几乎没有任何关于如何获取 OAuth 令牌的示例!

\n

was*_*tme 19

你的卷曲对我来说看起来不错,只是缺少Authorization标题,这是base64(id:secret)

curl -X POST "https://wwwcie.ups.com/security/v1/oauth/token" 
     -H "Authorization: Basic {id}:{secret}" 
     -H "accept: application/json" 
     -H "x-merchant-id: {My_Client_Id_Goes_Here}" 
     -H "Content-Type: application/x-www-form-urlencoded" 
     -d "grant_type=client_credentials"
Run Code Online (Sandbox Code Playgroud)

如果您使用“试用”功能,请选择Authorize顶部的按钮并输入客户端 ID 和密码,这就是用于设置授权标头的位置。需要注意的一件事是,“试用”功能仅适用于分配给您的应用的测试产品

附加信息

UPS 有 2 个环境

  • 测试:wwwcie.ups.com
  • 制作:onlinetools.ups.com

测试环境仅接受测试产品,因此请记下添加到您的应用程序中的产品

  • 哈,应该仔细阅读你的回复!他们的文档页面正在引导人们走上错误的道路。它对 ups.com 用户名/密码组合进行编码并将其放入标头中。它实际上应该是应该被编码的客户端 ID/秘密组合。一旦我这样做了,我就得到了一个令牌。 (7认同)

小智 9

我被这个问题困扰了很长时间。

您的评论最终确实对我有所帮助。但我想让以后读到这篇文章的人更清楚......

而不是在授权标头中使用 UPS 用户名和密码。您需要使用冒号对 clientId 和机密进行编码并发送。

对于 PHP:

$clientID = base64_encode("{clientID}:{clientSecret}");

$headers = array();
$headers[] = "Authorization: Basic $clientID";
$headers[] = 'Accept: application/json';
$headers[] = "X-Merchant-Id: {clientID}";
$headers[] = 'Content-Type: application/x-www-form-urlencoded';
Run Code Online (Sandbox Code Playgroud)


Sha*_*ilS 5

以防万一具有 .NET/C# 背景的人会寻找类似的主题 - 这里的 UPS RESTFul API 授权和跟踪信息处理解决方案对我来说使用此处建议的方法效果很好:

#define TEST_MODE

using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Text.Json.Nodes;

...

if (!ServicePointManager.Expect100Continue)
{
    ServicePointManager.Expect100Continue = true;
    ServicePointManager.SecurityProtocol = (SecurityProtocolType)(3072); // SecurityProtocolType.Tls;
    ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, errors) => true;
}

var myClientID = "{Type your ClientId here}";
var mySecretID = "{Type your SecretID here}";

#if TEST_MODE
var baseAddress = "https://wwwcie.ups.com";         // testing
#else
var baseAddress = "https://onlinetools.ups.com";  // production
#endif

var accessID = $"{myClientID}:{mySecretID}";
var base64AccessID = Convert.ToBase64String(Encoding.ASCII.GetBytes(accessID));

using (var client = new HttpClient())
{
    // Get Access Token
    var request = new HttpRequestMessage()
    {
        Method = HttpMethod.Post,
        RequestUri = new Uri($"{baseAddress}/security/v1/oauth/token"),
        Content = new FormUrlEncodedContent(new[]
        {
            new KeyValuePair<string, string>("grant_type", "client_credentials")
        })
    };
    request.Headers.Add("Authorization", $"Basic {base64AccessID}");

    var response = await client.SendAsync(request);

    var jsonResult = await response.Content.ReadAsStringAsync();
    var result = JsonSerializer.Deserialize<JsonObject>(jsonResult);

    var access_token = result?["access_token"]?.ToString();

    // Get Tracking Info
    var trackingNumber = "1Z5338FF0107231059";  // provided by UPS for testing

    request = new HttpRequestMessage()
    {
        Method = HttpMethod.Get,
        RequestUri = new Uri($"{baseAddress}/api/track/v1/details/{trackingNumber}")
    };
    request.Headers.Add("Authorization", $"Bearer {access_token}");
    request.Headers.Add("transId", $"{DateTime.Now.Ticks}");
#if TEST_MODE
    request.Headers.Add("transactionSrc", $"testing");
#else
    request.Headers.Add("transactionSrc", $"{App Name and version}");
#endif

    response = await client.SendAsync(request);
    jsonResult = await response.Content.ReadAsStringAsync();

    Console.WriteLine(jsonResult);
}
Run Code Online (Sandbox Code Playgroud)

[更新]

正如Nick最近在对此解决方案的评论中指出的那样,“我必须在代码顶部添加 TLS1.2 声明,否则它会抛出有关无法建立安全连接/通道的错误”,原始代码必须通过在其顶部添加以下代码行来更正:

if (!ServicePointManager.Expect100Continue)
{
    ServicePointManager.Expect100Continue = true;
    ServicePointManager.SecurityProtocol = (SecurityProtocolType)(3072); // SecurityProtocolType.Tls;
    ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, errors) => true;
}
Run Code Online (Sandbox Code Playgroud)

我还要注意的是,要在 .NET Framework 4.7.x/4.8 下编译解决方案代码,请使用Package Manager's 命令

  Install-Package System.Text.Json
Run Code Online (Sandbox Code Playgroud)

必须在 中执行,Package Manager Console或者您可以代替System.Text.Json使用Newtonsoft.Json NuGet的包,但在后一种情况下,您可能需要进行一些小的代码编辑。