Signing in Node.js
This guide demonstrates how to sign HTTP messages in Node.js using the native crypto
library.
Signer
In Node.js, you can create a Signer
object using the native crypto
library. The following example shows how to create a HmacSigner
class that implements the required properties and methods for a Signer
.
import crypto from 'crypto';
class HmacSigner {
alg = 'hmac-sha256'
constructor(key, keyid = 'test-key') {
this.key = key;
this.keyid = keyid;
this.alg = alg;
}
sign(data) {
const hmac = crypto.createHmac('sha256', this.key);
hmac.update(data);
return new Uint8Array(hmac.digest());
}
}
const signer = new HmacSigner('your-secret-key');
Now you have a signer
object that can be used with the sign()
function to sign HTTP messages.
Signing a message
To sign a request or response in Node.js, use the sign()
function with the HmacSigner
created above.
import { sign } from '@ltonetwork/http-message-signatures';
const request = {
method: 'GET',
url: 'https://example.com/api/data',
};
(async () => {
const signedRequest = await sign(request, { signer });
// ... Send the signed request to the server
})();
The signed request will now have the following headers:
Signature-Input: sig1=("@method","@target-uri"); keyid="test-key"; created=1625653823
Signature: sig1=:4VYMyeX0tNLQ7opuAJeMECP3HgfLswAG3n+IqQprO0Q=:
You can specify the components to sign using the components
option. For more information, see Signing Components.
Digest
To secure the integrity of the HTTP request or response body, you can use the Digest
header or Content-Digest
header. This header contains a hash of the message body.
Before signing the HTTP message, you’ll need to create the digest and add it to the headers. To create a Digest header using the SHA-256 hashing algorithm and the crypto
library:
- Calculate the SHA-256 hash of the response body.
- Encode the hash in Base64 format.
- Add the Digest header to the response headers with the format
Digest: SHA-256=<Base64EncodedHash>
.
Here is an example of how to create a digest for an HTTP response with Content-Type: application/json
and body {"hello":"world"}
.
import crypto from 'crypto';
const responseBody = JSON.stringify({ hello: 'world' });
const hash = crypto.createHash('sha256');
hash.update(responseBody);
const digest = hash.digest('base64');
const response = {
status: 200,
headers: {
'Content-Type': 'application/json',
'Digest': `SHA-256=${digest}`,
},
body: responseBody,
};
After adding the Digest header to the HTTP response, include the digest component when signing the response. The default response components are [‘@status’, ‘content-type’, ‘digest’].
const components = ['@status', 'content-type', 'digest'];
(async () => {
const signedResponse = await sign(response, { signer, components });
// ... Send the signed response to the client
})();
This chapter demonstrates how to create a digest for an HTTP response and sign the response using the specified components.