[英]How to sign oauth signature for request token with etrade api?
我正在嘗試為一個項目連接到 eTrade 的 API。 他們使用 OAuth v1 流程。 我在流程的第一步遇到了錯誤 - 獲取請求令牌。 他們的文檔中的信息可以在這里找到。
我得到的錯誤是 401-無效簽名。
我一直在閱讀這里的 OAuth 流程,並且已經熟悉了這個過程。 過去,我使用 PassportJS 進行 3rd 方集成。
所以 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);
}
}
}
我遵循了互聯網上的一些指南來幫助我了解簽署請求的過程,但我似乎無法得到有效的回復。
您的代碼針對的是 etrade 生產 URL。 嘗試調用沙箱 URL。
Production https://api.etrade.com/v1/{module}/{endpoint}
Sandbox https://apisb.etrade.com/v1/{module}/{endpoint}
我不知道您是否仍在尋找有關此問題的答案,但我認為以下內容可能會有所幫助。 我在嘗試與他們的 API 集成時遇到了類似的問題(雖然我使用的是 java)。 查看他們的示例代碼,我意識到對 baseString 進行簽名的密鑰需要在 request_token API 的末尾添加一個額外的“&”。 從他們的示例應用程序中查看以下代碼 -
if( token != null){
// not applicable for request_token API call
key = StringUtils.isEmpty(token.getOauth_token_secret()) ? context.getResouces().getSharedSecret() +"&" :
context.getResouces().getSharedSecret()+"&" + OAuth1Template.encode(token.getOauth_token_secret());
}else{
// applicable for request_token API call
key = context.getResouces().getSharedSecret() +"&";
}
AFAIK,這不是 oAuth 標准或任何東西。 這似乎與他們的實施非常具體。 無論如何,我更新了我的代碼以在末尾包含額外的“&”並開始工作。
private String signBaseString(String httpMethod, String url) {
StringBuilder baseString = new StringBuilder();
baseString.append(encode(httpMethod)).append("&").append(encode(url)).append("&");
baseString.append(encode(normalizeParams(url)));
// the extra & is added here.
SecretKeySpec signingKey = new SecretKeySpec((this.apiSecret + "&").getBytes(), SIGN_ALG);
Mac mac = null;
try {
mac = Mac.getInstance(SIGN_ALG);
mac.init(signingKey);
return new String(Base64.encodeBase64(
mac.doFinal(baseString.toString().getBytes(
StandardCharsets.UTF_8))));
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
logger.error("Error during signing headers", e);
return null;
}
}
讓我知道這是否適合您。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.