Verifying in the Browser
This guide demonstrates how to verify HTTP message signatures in the browser using the SubtleCrypto API.
Verify Callback
To verify signatures in the browser, you can use a callback function with the verify()
method. The following example shows how to create a verifyHmac
function that verifies an HMAC-SHA256 signature.
async function verifyHmac(data, signature, parameters) {
const account = await getAccount(parameters.keyid);
const keyData = new TextEncoder().encode(account.secretKey);
const algorithm = { name: 'HMAC', hash: 'SHA-256' };
const key = await crypto.subtle.importKey('raw', keyData, algorithm, false, ['verify']);
const encodedData = new TextEncoder().encode(data);
const valid = await crypto.subtle.verify('HMAC', key, signature, encodedData);
if (!valid) throw new Error('Invalid signature');
return account;
}
Now you have a verifyHmac
callback function that can be used with the verify()
function to verify signed HTTP messages.
Verifying a Message
To verify a signed HTTP message in the browser, use the verify()
function with the verifyHmac
callback function.
import { verify } from '@ltonetwork/http-message-signatures';
(async () => {
const response = await fetch('https://example.com/api/data');
try {
const account = await verify(response, verifyHmac);
// ... The signature is valid
} catch (error) {
// ... The signature is invalid
}
})();
The verify()
function will return a promise that resolves to the account associated with the key used to sign the message if the signature is valid. If the signature is invalid or verification fails for any reason, the promise will be rejected.
Verifying the Digest
When the Digest
or Content-Digest
header is present in an HTTP message, it’s crucial to verify it to ensure the integrity of the message body. The following example shows how to verify the Digest
header of an HTTP response using the SHA-256 hashing algorithm.
import { base64 } from '@ltonetwork/http-message-signatures';
(async () => {
const receivedBody = '{"hello":"world"}';
const receivedDigestHeader = 'SHA-256=sGb8nTkaRMkAaN1MwoyfztzCOkUo8rwSlzSFNt6aA74=';
const [algorithm, receivedDigest] = digestHeader.split('=');
if (algorithm !== 'SHA-256') throw new Error('Unsupported digest algorithm');
const hashBuffer = await crypto.subtle.digest('SHA-256', receivedBody);
const calculatedDigest = base64.encode(hashBuffer);
if (receivedDigest !== calculatedDigest) throw new Error('Invalid digest');
})();