我正在尝试为一个项目连接eTrade的API。他们使用OAuth v1流。我在流程的第一步--获取请求令牌--遇到了错误。从他们的文档的信息可以找到here。
我得到的错误是401-无效签名。
我一直在阅读关于OAuth流程的文章,并熟悉了这个过程。在过去,我使用PassportJS进行第三方集成。
所以eTrade给我提供了4个密钥- PROD_KEY,PROD_SECRET,SANDBOX_KEY,SANDBOX_SECRET。我现在使用沙盒密钥,因为我的生产密钥仍处于待定状态。
现在我的API上有了一个端点,我将从客户端调用它来获取请求令牌。它的结构是这样的:
router.route('/auth/request').get(controller.request);
字符串
下面的控制器是我生成签名并尝试从eTrade请求令牌的地方。该控制器看起来像这样:
// controllers/auth.js
const axios = require('axios');
const { v1 } = require('uuid');
const crypto = require('crypto');
function generateSignature() {
const method = 'GET',
url = 'http://localhost/',
encodedUrl = encodeURIComponent(url),
paramaters = {
oauth_consumer_key: process.env.ETRADE_SANDBOX_API_KEY,
oauth_signature_method: 'HMAC-SHA1',
oauth_timestamp: Math.floor(Date.now() / 1000),
oauth_nonce: v1(),
oauth_callback: 'oob'
}
var ordered = {};
Object.keys(paramaters).sort().forEach((key) => {
ordered[key] = paramaters[key];
});
var encodedParameters = '';
for(k in ordered) {
const encodedValue = escape(ordered[k]);
const encodedKey = encodeURIComponent(k);
if(encodedParameters === '') {
encodedParameters += encodeURIComponent(`${encodedKey}=${encodedValue}`);
} else {
encodedParameters += encodeURIComponent(`&${encodedKey}=${encodedValue}`);
}
}
encodedParameters = encodeURIComponent(encodedParameters);
const signature_base_string = `${method}&${encodedUrl}&${encodedParameters}`;
const signing_key = `${process.env.ETRADE_SANDBOX_SECRET_KEY}`;
const signature = crypto.createHmac("SHA1", signing_key).update(signature_base_string).digest().toString('base64');
const encodedSignature = encodeURIComponent(signature);
return encodedSignature;
}
module.exports = {
request: async (req, res) => {
console.log('Fetching request token from etrade...');
try {
var response = await axios.get(`https://api.etrade.com/oauth/request_token`, {
params: {
oauth_consumer_key: process.env.ETRADE_SANDBOX_API_KEY,
oauth_signature_method: 'HMAC-SHA1',
oauth_signature: generateSignature(),
oauth_timestamp: Math.floor(Date.now() / 1000),
oauth_nonce: v1(),
oauth_callback: 'oob'
}
});
console.log('Fetched request token...', response.data);
} catch (error) {
console.log('Could not fetch request token...', error.response.data);
}
}
}
型
我已经遵循了互联网上的一些指南,以帮助我了解签署请求的过程,但我似乎不能得到一个有效的回应。
3条答案
按热度按时间13z8s7eq1#
您的代码以etrade生产URL为目标。尝试调用沙盒URL。
字符串
6ojccjat2#
我不知道你是否还在寻找这个问题的答案,但我认为以下内容可能会有所帮助。我遇到了一个类似的问题,而我试图与他们的API集成(我使用Java虽然)。查看他们的示例代码,我意识到用于签名baseString的键需要在request_token API的末尾多加一个'&'。请参阅以下示例应用程序中的代码-
字符串
AFAIK,这不是oAuth标准或任何东西。这似乎是非常具体的实施。无论如何,我更新了我的代码,在最后包含了额外的'&'&它开始工作了。
型
让我知道如果这对你有用。
ghhaqwfi3#
我有一个应用程序使用TDAmeritrade,我已经运行多年,他们是非常缓慢的释放信息过渡到嘉信理财,所以我正在探索的选择。不幸的是,我正在使用 Delphi ,而几乎没有其他人这样做。
Delphi 确实有OAuth 1类,但似乎不起作用。但是HMAC_SHA1的类确实可以工作,所以我尝试直接构建授权字符串,然后对其进行散列。上面的例子基本上就是我正在做的事情。当我传递一个在OAuth文档中找到的字符串时,我会得到正确的哈希值。但是我试着在Etrade中建立这个例子,我不能得到正确的结果,当我试着调用请求令牌时,当然我得到了未经授权的无效签名。
看到上面的例子,我希望我能得到一些调试的BaseString被传递到散列。
我访问了https://oauth.net/core/1.0a/#sig_base_example,找到了一个生成要散列的基本字符串的示例。示例基本字符串为GET&http%3A%2F%2Fphotos.example.net%2Fphotos&file%3Dvacation.jpg% 26 oauth_consumer_key% 3Ddpf43f3p2l4k3l03% 26 oauth_nonce% 3Dkllo 9940 pd 9333 jh % 26 oauth_signature_method%3DHMAC-SHA1% 26 oauth_timestamp% 3D1191242096% 26 oauth_token% 3Dnnch 734 d 00 sl 2 jdk % 26 oauth_version% 3D 1. 0% 26 size %3Doriginal
它表示将此字符串传递给HMAC-SHA1,密钥为kd94hf93k423kf44&pfkkdhi9sl3r4s00,结果签名为tR 3 + Ty 81 lMeYAr/Fid 0 kMTYa/WM=
我的哈希返回正确的哈希。
字符串
如果任何人都可以张贴示例签名字符串被散列,我将不胜感激。