@korala/auth 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/hmac.d.ts +61 -0
- package/dist/hmac.d.ts.map +1 -0
- package/dist/hmac.js +109 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/internal.d.ts +2 -0
- package/dist/internal.d.ts.map +1 -0
- package/dist/internal.js +5 -0
- package/package.json +60 -0
package/dist/hmac.d.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Maximum age of a request signature in seconds (5 minutes)
|
|
3
|
+
*/
|
|
4
|
+
export declare const MAX_TIMESTAMP_AGE_SECONDS = 300;
|
|
5
|
+
/**
|
|
6
|
+
* Request data needed for signature generation/verification
|
|
7
|
+
*/
|
|
8
|
+
export interface SignatureRequest {
|
|
9
|
+
method: string;
|
|
10
|
+
path: string;
|
|
11
|
+
body?: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Build the payload string used for HMAC signing
|
|
15
|
+
*/
|
|
16
|
+
export declare function buildSignaturePayload(request: SignatureRequest, timestamp: string): string;
|
|
17
|
+
/**
|
|
18
|
+
* Compute HMAC-SHA256 signature for a payload
|
|
19
|
+
*/
|
|
20
|
+
export declare function computeSignature(payload: string, secret: string): string;
|
|
21
|
+
/**
|
|
22
|
+
* Verify a signature using timing-safe comparison
|
|
23
|
+
*/
|
|
24
|
+
export declare function verifySignature(provided: string, expected: string): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Check if a timestamp is within the allowed age window
|
|
27
|
+
*/
|
|
28
|
+
export declare function isTimestampValid(timestamp: number, maxAgeSeconds?: number): boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Generate current Unix timestamp in seconds
|
|
31
|
+
*/
|
|
32
|
+
export declare function getTimestamp(): string;
|
|
33
|
+
/**
|
|
34
|
+
* Hash a secret for storage using SHA-256
|
|
35
|
+
*/
|
|
36
|
+
export declare function hashSecret(secret: string): string;
|
|
37
|
+
/**
|
|
38
|
+
* Sign a request and return the headers needed for authentication
|
|
39
|
+
*/
|
|
40
|
+
export declare function signRequest(request: SignatureRequest, keyId: string, secret: string): {
|
|
41
|
+
'x-api-key': string;
|
|
42
|
+
'x-timestamp': string;
|
|
43
|
+
'x-signature': string;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Webhook signature headers
|
|
47
|
+
*/
|
|
48
|
+
export interface WebhookSignatureHeaders {
|
|
49
|
+
'x-webhook-signature': string;
|
|
50
|
+
'x-webhook-timestamp': string;
|
|
51
|
+
'x-webhook-event': string;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Sign a webhook payload and return the headers
|
|
55
|
+
*/
|
|
56
|
+
export declare function signWebhookPayload(payload: string, secret: string, eventType: string): WebhookSignatureHeaders;
|
|
57
|
+
/**
|
|
58
|
+
* Verify a webhook signature
|
|
59
|
+
*/
|
|
60
|
+
export declare function verifyWebhookSignature(payload: string, timestamp: string, signature: string, secret: string, maxAgeSeconds?: number): boolean;
|
|
61
|
+
//# sourceMappingURL=hmac.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hmac.d.ts","sourceRoot":"","sources":["../src/hmac.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,eAAO,MAAM,yBAAyB,MAAM,CAAC;AAE7C;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,gBAAgB,EACzB,SAAS,EAAE,MAAM,GAChB,MAAM,CAMR;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAExE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAa3E;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,MAAM,EACjB,aAAa,GAAE,MAAkC,GAChD,OAAO,CAGT;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED;;GAEG;AACH,wBAAgB,WAAW,CACzB,OAAO,EAAE,gBAAgB,EACzB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GACb;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,CAUvE;AAED;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,qBAAqB,EAAE,MAAM,CAAC;IAC9B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAChB,uBAAuB,CAUzB;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,aAAa,GAAE,MAAkC,GAChD,OAAO,CAgBT"}
|
package/dist/hmac.js
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MAX_TIMESTAMP_AGE_SECONDS = void 0;
|
|
4
|
+
exports.buildSignaturePayload = buildSignaturePayload;
|
|
5
|
+
exports.computeSignature = computeSignature;
|
|
6
|
+
exports.verifySignature = verifySignature;
|
|
7
|
+
exports.isTimestampValid = isTimestampValid;
|
|
8
|
+
exports.getTimestamp = getTimestamp;
|
|
9
|
+
exports.hashSecret = hashSecret;
|
|
10
|
+
exports.signRequest = signRequest;
|
|
11
|
+
exports.signWebhookPayload = signWebhookPayload;
|
|
12
|
+
exports.verifyWebhookSignature = verifyWebhookSignature;
|
|
13
|
+
const crypto_1 = require("crypto");
|
|
14
|
+
/**
|
|
15
|
+
* Maximum age of a request signature in seconds (5 minutes)
|
|
16
|
+
*/
|
|
17
|
+
exports.MAX_TIMESTAMP_AGE_SECONDS = 300;
|
|
18
|
+
/**
|
|
19
|
+
* Build the payload string used for HMAC signing
|
|
20
|
+
*/
|
|
21
|
+
function buildSignaturePayload(request, timestamp) {
|
|
22
|
+
const method = request.method.toUpperCase();
|
|
23
|
+
const path = request.path;
|
|
24
|
+
const body = request.body ?? '';
|
|
25
|
+
return `${timestamp}.${method}.${path}.${body}`;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Compute HMAC-SHA256 signature for a payload
|
|
29
|
+
*/
|
|
30
|
+
function computeSignature(payload, secret) {
|
|
31
|
+
return (0, crypto_1.createHmac)('sha256', secret).update(payload).digest('hex');
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Verify a signature using timing-safe comparison
|
|
35
|
+
*/
|
|
36
|
+
function verifySignature(provided, expected) {
|
|
37
|
+
try {
|
|
38
|
+
const providedBuffer = Buffer.from(provided, 'hex');
|
|
39
|
+
const expectedBuffer = Buffer.from(expected, 'hex');
|
|
40
|
+
if (providedBuffer.length !== expectedBuffer.length) {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
return (0, crypto_1.timingSafeEqual)(providedBuffer, expectedBuffer);
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Check if a timestamp is within the allowed age window
|
|
51
|
+
*/
|
|
52
|
+
function isTimestampValid(timestamp, maxAgeSeconds = exports.MAX_TIMESTAMP_AGE_SECONDS) {
|
|
53
|
+
const now = Math.floor(Date.now() / 1000);
|
|
54
|
+
return Math.abs(now - timestamp) <= maxAgeSeconds;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Generate current Unix timestamp in seconds
|
|
58
|
+
*/
|
|
59
|
+
function getTimestamp() {
|
|
60
|
+
return Math.floor(Date.now() / 1000).toString();
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Hash a secret for storage using SHA-256
|
|
64
|
+
*/
|
|
65
|
+
function hashSecret(secret) {
|
|
66
|
+
return (0, crypto_1.createHash)('sha256').update(secret).digest('hex');
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Sign a request and return the headers needed for authentication
|
|
70
|
+
*/
|
|
71
|
+
function signRequest(request, keyId, secret) {
|
|
72
|
+
const timestamp = getTimestamp();
|
|
73
|
+
const payload = buildSignaturePayload(request, timestamp);
|
|
74
|
+
const signature = computeSignature(payload, secret);
|
|
75
|
+
return {
|
|
76
|
+
'x-api-key': keyId,
|
|
77
|
+
'x-timestamp': timestamp,
|
|
78
|
+
'x-signature': signature,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Sign a webhook payload and return the headers
|
|
83
|
+
*/
|
|
84
|
+
function signWebhookPayload(payload, secret, eventType) {
|
|
85
|
+
const timestamp = getTimestamp();
|
|
86
|
+
const signaturePayload = `${timestamp}.${payload}`;
|
|
87
|
+
const signature = computeSignature(signaturePayload, secret);
|
|
88
|
+
return {
|
|
89
|
+
'x-webhook-signature': signature,
|
|
90
|
+
'x-webhook-timestamp': timestamp,
|
|
91
|
+
'x-webhook-event': eventType,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Verify a webhook signature
|
|
96
|
+
*/
|
|
97
|
+
function verifyWebhookSignature(payload, timestamp, signature, secret, maxAgeSeconds = exports.MAX_TIMESTAMP_AGE_SECONDS) {
|
|
98
|
+
// Check timestamp is valid
|
|
99
|
+
const timestampNum = Number.parseInt(timestamp, 10);
|
|
100
|
+
if (Number.isNaN(timestampNum) ||
|
|
101
|
+
!isTimestampValid(timestampNum, maxAgeSeconds)) {
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
// Compute expected signature
|
|
105
|
+
const signaturePayload = `${timestamp}.${payload}`;
|
|
106
|
+
const expectedSignature = computeSignature(signaturePayload, secret);
|
|
107
|
+
// Timing-safe comparison
|
|
108
|
+
return verifySignature(signature, expectedSignature);
|
|
109
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export { buildSignaturePayload, computeSignature, getTimestamp, isTimestampValid, MAX_TIMESTAMP_AGE_SECONDS, type SignatureRequest, signRequest, signWebhookPayload, verifySignature, verifyWebhookSignature, type WebhookSignatureHeaders, } from './hmac.js';
|
|
2
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,gBAAgB,EAChB,YAAY,EACZ,gBAAgB,EAChB,yBAAyB,EACzB,KAAK,gBAAgB,EACrB,WAAW,EACX,kBAAkB,EAClB,eAAe,EACf,sBAAsB,EACtB,KAAK,uBAAuB,GAC7B,MAAM,WAAW,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.verifyWebhookSignature = exports.verifySignature = exports.signWebhookPayload = exports.signRequest = exports.MAX_TIMESTAMP_AGE_SECONDS = exports.isTimestampValid = exports.getTimestamp = exports.computeSignature = exports.buildSignaturePayload = void 0;
|
|
4
|
+
var hmac_js_1 = require("./hmac.js");
|
|
5
|
+
Object.defineProperty(exports, "buildSignaturePayload", { enumerable: true, get: function () { return hmac_js_1.buildSignaturePayload; } });
|
|
6
|
+
Object.defineProperty(exports, "computeSignature", { enumerable: true, get: function () { return hmac_js_1.computeSignature; } });
|
|
7
|
+
Object.defineProperty(exports, "getTimestamp", { enumerable: true, get: function () { return hmac_js_1.getTimestamp; } });
|
|
8
|
+
Object.defineProperty(exports, "isTimestampValid", { enumerable: true, get: function () { return hmac_js_1.isTimestampValid; } });
|
|
9
|
+
Object.defineProperty(exports, "MAX_TIMESTAMP_AGE_SECONDS", { enumerable: true, get: function () { return hmac_js_1.MAX_TIMESTAMP_AGE_SECONDS; } });
|
|
10
|
+
Object.defineProperty(exports, "signRequest", { enumerable: true, get: function () { return hmac_js_1.signRequest; } });
|
|
11
|
+
Object.defineProperty(exports, "signWebhookPayload", { enumerable: true, get: function () { return hmac_js_1.signWebhookPayload; } });
|
|
12
|
+
Object.defineProperty(exports, "verifySignature", { enumerable: true, get: function () { return hmac_js_1.verifySignature; } });
|
|
13
|
+
Object.defineProperty(exports, "verifyWebhookSignature", { enumerable: true, get: function () { return hmac_js_1.verifyWebhookSignature; } });
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"internal.d.ts","sourceRoot":"","sources":["../src/internal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC"}
|
package/dist/internal.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@korala/auth",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "HMAC authentication utilities for the Korala document signing API",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/korala-ai/korala.git",
|
|
9
|
+
"directory": "packages/auth"
|
|
10
|
+
},
|
|
11
|
+
"main": "./dist/index.js",
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"import": "./dist/index.js",
|
|
17
|
+
"default": "./dist/index.js"
|
|
18
|
+
},
|
|
19
|
+
"./internal": {
|
|
20
|
+
"types": "./dist/internal.d.ts",
|
|
21
|
+
"import": "./dist/internal.js",
|
|
22
|
+
"default": "./dist/internal.js"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"typesVersions": {
|
|
26
|
+
"*": {
|
|
27
|
+
"internal": [
|
|
28
|
+
"./dist/internal.d.ts"
|
|
29
|
+
]
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"files": [
|
|
33
|
+
"dist"
|
|
34
|
+
],
|
|
35
|
+
"publishConfig": {
|
|
36
|
+
"access": "public"
|
|
37
|
+
},
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": ">=20.0"
|
|
40
|
+
},
|
|
41
|
+
"keywords": [
|
|
42
|
+
"korala",
|
|
43
|
+
"hmac",
|
|
44
|
+
"authentication",
|
|
45
|
+
"api-signing",
|
|
46
|
+
"webhook-verification"
|
|
47
|
+
],
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"typescript": "^5.9.3",
|
|
50
|
+
"vitest": "^4.0.17"
|
|
51
|
+
},
|
|
52
|
+
"scripts": {
|
|
53
|
+
"build": "tsc",
|
|
54
|
+
"dev": "tsc --watch",
|
|
55
|
+
"typecheck": "tsc --noEmit",
|
|
56
|
+
"check": "biome check --write .",
|
|
57
|
+
"test": "vitest run",
|
|
58
|
+
"test:watch": "vitest"
|
|
59
|
+
}
|
|
60
|
+
}
|