TrueLayer沙箱支付创建失败:请求缺失Tl-Signature头
TrueLayer沙箱支付创建失败:Tl-Signature header缺失报错
尝试创建TrueLayer沙箱支付时,明明已添加请求头,却始终收到401错误,提示**"Tl-Signature header value is missing from the request"**。以下是使用truelayer-signing库的NestJS代码及错误响应:
代码实现
import { Injectable } from "@nestjs/common"; const sdk = require('api')('@truelayer/v1.0#7nim1b17lbzalnne'); const sdk1 = require('api')('@truelayer/v1.0#xk1zcylftx71d3'); const tlSigning = require('truelayer-signing'); @Injectable() export class AppService { async getData(){ sdk.server('https://auth.truelayer-sandbox.com'); try{ let data = await sdk.generateAccessToken({ grant_type: 'client_credentials', client_id: 'sandbox-{your id}', client_secret: '{your secret}', scope: 'payments' }); console.log(data.data) const Idempotency = Math.random() * 1000; const tlSignature = tlSigning.sign({ kid: '8ab13f4a-bccc-4c32-b8a8-c1861b377f8e', privateKeyPem: ["-----BEGIN EC PRIVATE KEY-----",{your private key}, "-----END EC PRIVATE KEY-----"].join('\n'), method: "POST", path: "/payments", headers: { "Idempotency-Key": Idempotency }, body: '{"payment_method":{"type":"bank_transfer","provider_selection":{"type":"user_selected","filter":{"release_channel":"general_availability","customer_segments":["retail"]},"scheme_selection":{"type":"instant_only","allow_remitter_fee":false}},"beneficiary":{"type":"merchant_account","verification":{"type":"automated"}}},"amount_in_minor":1,"currency":"GBP"}', }); console.log(tlSignature) let res = await sdk1.createPayment('{"payment_method":{"type":"bank_transfer","provider_selection":{"type":"user_selected","filter":{"release_channel":"general_availability","customer_segments":["retail"]},"scheme_selection":{"type":"instant_only","allow_remitter_fee":false}},"beneficiary":{"type":"merchant_account","verification":{"type":"automated"}}},"amount_in_minor":1,"currency":"GBP"}', { 'Authorization': `Bearer ${data.data.access_token}`, 'idempotency-key': Idempotency, 'Tl-Signature': tlSignature, 'content-type': 'application/json; charset=UTF-8', }); console.log(res) }catch(err){ console.log('error 123') console.log(err) } return { message: "Hello API" }; } }
错误响应
Error: Unauthorized at new FetchError (/Users/laptop/Documents/Projects/app/node_modules/api/dist/core/errors/fetchError.js:21:28) at APICore.<anonymous> (/Users/laptop/Documents/Projects/app/node_modules/api/dist/core/index.js:152:51) at step (/Users/laptop/Documents/Projects/app/node_modules/api/dist/core/index.js:44:23) at Object.next (/Users/laptop/Documents/Projects/app/node_modules/api/dist/core/index.js:25:53) at fulfilled (/Users/laptop/Documents/Projects/app/node_modules/api/dist/core/index.js:16:58) at processTicksAndRejections (node:internal/process/task_queues:95:5) { status: 401, data: { type: 'https://docs.truelayer.com/docs/error-types#unauthenticated', title: 'Unauthenticated', status: 401, detail: 'Tl-Signature header value is missing from the request.', trace_id: '03bf6cb64bb262a2147fc79c15e3a3f6' }, headers: HeadersList { cookies: null, [Symbol(headers map)]: Map(13) { 'date' => [Object], 'content-type' => [Object], 'transfer-encoding' => [Object], 'connection' => [Object], 'tl-trace-id' => [Object], 'referrer-policy' => [Object], 'x-frame-options' => [Object], 'x-content-type-options' => [Object], 'strict-transport-security' => [Object], 'content-security-policy' => [Object], 'cf-cache-status' => [Object], 'server' => [Object], 'cf-ray' => [Object] }, [Symbol(headers map sorted)]: null }, res: Response { [Symbol(realm)]: null, [Symbol(state)]: { aborted: false, rangeRequested: false, timingAllowPassed: true, requestIncludesCredentials: true, type: 'default', status: 401, timingInfo: [Object], cacheState: '', statusText: 'Unauthorized', headersList: [HeadersList], urlList: [Array], body: [Object] }, [Symbol(headers)]: HeadersList { cookies: null, [Symbol(headers map)]: [Map], [Symbol(headers map sorted)]: null } } }
排查与解决办法
1. 修正SDK服务器配置
sdk1未指定沙箱服务器地址,可能默认指向了错误环境,需添加沙箱API地址:
sdk1.server('https://api.truelayer-sandbox.com');
2. 统一签名与请求的参数一致性
签名生成时的参数必须和实际请求完全匹配:
- Idempotency-Key:将数值转为字符串,避免类型差异:
const idempotencyKey = Math.random() * 1000 + ''; // 签名时用字符串值 headers: { "Idempotency-Key": idempotencyKey }, // 请求头也用同一个字符串 'Idempotency-Key': idempotencyKey, - 请求体:将body存为变量,签名和请求复用同一个值,避免字符差异:
const paymentBody = '{"payment_method":{"type":"bank_transfer",...}}'; // 签名时用paymentBody body: paymentBody, // 请求时也用paymentBody body: paymentBody,
3. 检查请求头传递方式
第三方SDK可能对请求头格式有特殊要求,可尝试用原生fetch替代SDK验证:
await fetch('https://api.truelayer-sandbox.com/payments', { method: 'POST', headers: { 'Authorization': `Bearer ${data.data.access_token}`, 'Idempotency-Key': idempotencyKey, 'Tl-Signature': tlSignature, 'Content-Type': 'application/json' }, body: paymentBody });
4. 确认头名称大小写
确保请求头键名是'Tl-Signature',避免客户端自动转为小写(如tl-signature)导致服务端无法识别。
内容的提问来源于stack exchange,提问作者Sathesh Kumar
相关产品推荐
相关产品推荐

