Authentication
API keys
Create an API key from the user dashboard. Save the secret in a secure place and never share it anywhere. If it gets leaked or compromised, rotate your API key immediately.
Signatures
The API secret is used to crypotgraphically sign every request using the HMAC-SHA256 algorithm. The backend uses the same secret to sign the same request. If the signatures match, the backend confidently authenticates the request knowing that it was sent by a clien that has access to the secret.
The secret is never communicated.
The HMAC is digested from the following data, in the respective order:
- Current timestamp (UNIX milliseconds)
- HTTP method in uppercase format:
GET, POST, ... - Request path, excluding the query string:
/users, /transactions/send - Query string, if present. Including the
?symbol:?amount=5&status=pending - HTTP body
Make sure the HTTP body is the actual body you send to our backend and it doesn't change shape after signing. If you're using JSON for example, use the final JSON when signing.
Example
An example implementation in Node.js, using Axios and interceptors. Store the secret values securely instead of hardcoding them in the codebase. This is just an example.
const key = '1c823a83606216c4f205331594cf01c2';
const secret = Buffer.from('acd67fbfc3b25e0171af9bb2957a99ba');
const client = axios.create({
headers: {
Authorization: `Bearer ${key}`,
},
});
client.interceptors.request.use((config) => {
// Remove trailing slashes, otherwise signatures might drift
const ts = Date.now().toString();
const method = config.method?.toUpperCase() ?? '';
const baseURL = (config.baseURL || '').replace(/\/+$/g, '');
const { pathname, search } = new URL(baseURL + config.url);
let body = config.data || '';
const transformers = [
config.transformRequest || axios.defaults.transformRequest,
];
transformers.flat().forEach((transform) => {
if (transform) {
body = transform.call(config, body, config.headers);
}
});
const data = `${ts}${method}${pathname}${search}${body}`;
const signature = createHmac('sha256', secret).update(data).digest('hex');
config.headers['X-Timestamp'] = ts;
config.headers['X-Signature'] = signature;
// Freeze the request transformation from this point onward to lock down the signature.
config.data = body;
config.transformRequest = (data) => data;
return config;
});
// Use the client
const res = await client.get(...);