Skip to content

Instantly share code, notes, and snippets.

@simlevesque
Created September 25, 2019 21:52
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save simlevesque/58ecb8477188f903fef72a5601f0a069 to your computer and use it in GitHub Desktop.
Save simlevesque/58ecb8477188f903fef72a5601f0a069 to your computer and use it in GitHub Desktop.
aws v4 signature in modern js (sigv4.js)
'use strict';
const crypto = require('crypto');
module.exports = function (accessKey, secretKey, requestHeaders, httpMethod, path, payload, region, service, timestamp) {
const signedHeaders = createSignedHeaders(requestHeaders);
const canonicalRequest = createCanonicalRequest(httpMethod, path, requestHeaders, payload);
const stringToSign = createStringToSign(timestamp, region, service, canonicalRequest);
const signature = createSignature(secretKey, timestamp, region, service, stringToSign);
const authorizationHeader = createAuthorizationHeaders(timestamp, accessKey, region, service, signedHeaders, signature);
return authorizationHeader;
}
function createAuthorizationHeaders (timestamp, accessKey, region, service, signedHeaders, signature) {
return `AWS4-HMAC-SHA256 Credential=${accessKey}/${createCredentialScope(timestamp, region, service)} SignedHeaders=${signedHeaders} Signature=${signature}`;
}
function createCanonicalRequest (method, pathname, headers, payload) {
const payloadJson = JSON.stringify(payload);
return `${method.toUpperCase()}
${pathname}
${createCanonicalHeaders(headers)}
${createSignedHeaders(headers)}
${hexEncodedHash(payloadJson)}`;
}
function createCanonicalHeaders (headers) {
return Object.keys(headers)
.sort()
.map(name => name.toLowerCase().trim() + ':' + headers[name].toString().trim() + '\n')
.join('');
}
function createSignedHeaders (headers) {
return Object.keys(headers)
.sort()
.map(name => name.toLowerCase().trim())
.join(';');
}
function createCredentialScope (time, region, service) {
return `${toDate(time)}/${region}/${service}/aws4_request`;
}
function createStringToSign (time, region, service, request) {
return `AWS4-HMAC-SHA256
${toTime(time)}
${createCredentialScope(time, region, service)}
${hexEncodedHash(request)}`;
}
function createSignature (secret, time, region, service, stringToSign) {
const h1 = hmac(`AWS4${secret}`, toDate(time)).digest(); // date-key
const h2 = hmac(h1, region).digest(); // region-key
const h3 = hmac(h2, service).digest(); // service-key
const h4 = hmac(h3, 'aws4_request').digest(); // signing-key
return hmac(h4, stringToSign).digest('hex');
}
function toTime(time) {
return new Date(time).toISOString().replace(/[:\-]|\.\d{3}/g, '');
}
function toDate(time) {
return toTime(time).substring(0, 8);
}
function hmac(key, data) {
return crypto.createHmac('sha256', key).update(data);
}
function hexEncodedHash(data) {
return crypto.createHash('sha256').update(data).digest('hex');
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment