Learn how to sign requests
To securely interact with Withings APIs, partners must sign some of their requests using HMAC SHA-256.
This ensures that requests are properly authenticated and tamper-proof.
The signature mechanism requires two distinct steps:
- Obtaining a nonce (a one-time token) to ensure request uniqueness.
- Signing the actual API request using the nonce and a hash-based signature.
Step 1: Obtaining a Nonce
The first step in signing a request is acquiring a nonce — a cryptographically unique value used to prevent replay attacks.
This is done by invoking the Signature v2 - Getnonce endpoint.
The nonce is a transient token, and every request requires a fresh one. The process is as follows:
- Prepare the following parameters:
action:getnonce.client_id: Your unique client identifier.timestamp: A UNIX timestamp of the current time.
-
Concatenate the parameter values in the following order:
action,client_id, andtimestamp, separating them with commas (,). -
Use the
HMAC SHA-256algorithm to hash this concatenated string.
The secret key for the HMAC function is your client secret (found in your Withings Developer Dashboard). -
Send the request to the
getnonceAPI endpoint, appending the generated hash as thesignature.
See the code snippet for a complete implementation example.
Step 2: Signing the Actual API Request
Once you have the nonce, you can proceed to sign the actual API request. Here’s how it works:
- Generate the signature using the following parameters:
action: The specific API action you are calling.client_id: Your unique client identifier.nonce: The nonce obtained from Step 1.
-
Concatenate the sorted values (alphabetically by key name) of these parameters, separated by commas.
-
Compute the
HMAC SHA-256hash using your client secret as the key.
See the code snippet for an implementation example.
Snippets
Here is an example of a function that allows us to sign request and handle the timestamp (to get a nonce), or the nonce parameter to sign requests later on.
const axios = require('axios');
const crypto = require('crypto');
// Constants
const API_ENDPOINT = 'https://wbsapi.withings.net';
const OAUTH2_GRANT_TYPE_AUTHORIZATION_CODE = 'authorization_code';
const REDIRECT_URI = 'localhost:3000';
const CLIENT_ID = 'yourclientid';
const CLIENT_SECRET = 'yourclientsecret';
function sign(params, client_secret) {
const params_to_sign = {
action: params.action,
client_id: params.client_id
}
if (params.timestamp) {
params_to_sign.timestamp = params.timestamp;
}
if (params.nonce) {
params_to_sign.nonce = params.nonce;
}
const sorted_values = Object.values(params_to_sign).join(',');
const hmac = crypto.createHmac('sha256', client_secret);
hmac.update(sorted_values);
return hmac.digest("hex");
}
async function getNonce(timestamp) {
const params = {
action: 'getnonce',
client_id: CLIENT_ID,
timestamp //timestamp should be in unix form
};
params.signature = sign(params, CLIENT_SECRET);
const { data } = await axios.post(API_ENDPOINT + '/v2/signature', params);
return data.body.nonce;
}
async function main() {
const now = Math.round((Date.now() / 1000));
const nonce = await getNonce(now);
console.log(nonce);
}