From d8c6bfe24f15fa527c45774b9f079f512ae2ee04 Mon Sep 17 00:00:00 2001 From: multipleof4 Date: Sun, 15 Mar 2026 13:08:21 -0700 Subject: [PATCH] Feat: Kalshi RSA auth signing for API requests --- lib/kalshi/auth.js | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 lib/kalshi/auth.js diff --git a/lib/kalshi/auth.js b/lib/kalshi/auth.js new file mode 100644 index 0000000..546bc07 --- /dev/null +++ b/lib/kalshi/auth.js @@ -0,0 +1,34 @@ +import crypto from 'crypto'; + +const KALSHI_API_BASE = 'https://api.elections.kalshi.com'; + +/** + * Signs a Kalshi API request using RSA-PSS with SHA-256. + * Returns headers needed for authenticated requests. + */ +export function signRequest(method, path, timestampMs = Date.now()) { + const keyId = process.env.KALSHI_API_KEY_ID; + const privateKeyPem = process.env.KALSHI_RSA_PRIVATE_KEY?.replace(/\\n/g, '\n'); + + if (!keyId || !privateKeyPem) { + throw new Error('Missing KALSHI_API_KEY_ID or KALSHI_RSA_PRIVATE_KEY'); + } + + const ts = String(timestampMs); + const message = `${ts}${method.toUpperCase()}${path}`; + + const signature = crypto.sign('sha256', Buffer.from(message), { + key: privateKeyPem, + padding: crypto.constants.RSA_PKCS1_PSS_PADDING, + saltLength: crypto.constants.RSA_PSS_SALTLEN_DIGEST + }); + + return { + 'KALSHI-ACCESS-KEY': keyId, + 'KALSHI-ACCESS-SIGNATURE': signature.toString('base64'), + 'KALSHI-ACCESS-TIMESTAMP': ts, + 'Content-Type': 'application/json' + }; +} + +export { KALSHI_API_BASE };