secure-web-token 1.0.1 → 1.0.3

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/README.md CHANGED
@@ -1,178 +1,148 @@
1
- # 🔐 Secure Web Token (Fingerprint Based)
1
+ # 🔐 Secure Web Token (SWT)
2
2
 
3
- A lightweight Node.js authentication package that allows you to **sign and verify tokens using one or more device fingerprints**.
3
+ ## 1. About the Package
4
4
 
5
- This helps prevent token misuse across different devices.
5
+ **Secure Web Token (SWT)** is a Node.js authentication package that provides a more secure alternative to JWT by **encrypting token payloads** and **binding tokens to specific devices** using fingerprints.
6
6
 
7
- ---
8
-
9
- ## ✨ Features
10
-
11
- - Supports **single or multiple fingerprints**
12
- - Simple `sign()` and `verify()` API
13
- - CommonJS compatible
14
- - Editor IntelliSense support
15
- - No heavy dependencies
7
+ It is designed for applications where security and device-level access control matter.
16
8
 
17
9
  ---
18
10
 
19
- ## 📦 Installation
11
+ ## 2. What Problem Does It Solve?
20
12
 
21
- ```bash
22
- npm install secure-web-token
23
- ```
13
+ Traditional JWT has some well-known issues:
24
14
 
25
- ---
15
+ - JWT payloads are **Base64 encoded**, not encrypted
16
+ - Anyone can decode the payload using online tools without the secret
17
+ - If a token leaks, it can be reused on **any device**
18
+ - No built-in way to restrict tokens to a specific device
26
19
 
27
- ## 📥 Import
20
+ **Secure Web Token (SWT)** solves these problems by:
28
21
 
29
- ```js
30
- const { sign, verify } = require("secure-web-token");
31
- ```
32
-
33
- ---
22
+ - Encrypting the payload using **AES-256-GCM**
23
+ - Making payload data **completely unreadable without the secret**
24
+ - Allowing tokens to be bound to **one or more device fingerprints**
25
+ - Preventing token reuse from unauthorized devices
26
+ - Supporting auto-generated device IDs for stronger protection
34
27
 
35
- ## 🧠 What is Fingerprint?
36
-
37
- A fingerprint is any unique identifier of a device, for example:
38
- - Browser + OS (`Chrome-Linux`)
39
- - Device name
40
- - IP address
41
- - Custom string
42
-
43
- You can pass **one or multiple fingerprints**.
28
+ This makes SWT especially useful for:
29
+ - Course platforms (anti-piracy)
30
+ - SaaS dashboards
31
+ - Admin panels
32
+ - Device-restricted systems
44
33
 
45
34
  ---
46
35
 
47
- ## ✍️ sign()
48
-
49
- Creates a secure token with fingerprint validation.
36
+ ## 3. Available Functions
50
37
 
51
- ### Syntax
38
+ ### `sign()`
39
+ Creates an encrypted and signed token.
52
40
 
53
- ```js
54
- sign(payload, secret, options)
55
- ```
56
-
57
- ### Parameters
58
-
59
- | Parameter | Type | Description |
60
- |---------|-----|-------------|
61
- | payload | Object | Data you want inside token |
62
- | secret | String | Secret key |
63
- | options.expiresIn | Number | Expiry time (seconds) |
64
- | options.fingerprint | String \| String[] | Allowed fingerprint(s) |
41
+ **Features:**
42
+ - Encrypts payload
43
+ - Adds expiry (`iat`, `exp`)
44
+ - Supports device fingerprint binding
45
+ - Can auto-generate a device ID
65
46
 
66
47
  ---
67
48
 
68
- ### Example: Single Fingerprint
49
+ ### `verify()`
50
+ Verifies and decrypts a token.
69
51
 
70
- ```js
71
- const token = sign(
72
- { userId: 1 },
73
- "my-secret",
74
- {
75
- expiresIn: 60,
76
- fingerprint: "Chrome-Linux"
77
- }
78
- );
79
-
80
- console.log("TOKEN:", token);
81
- ```
52
+ **Checks performed:**
53
+ - Token format
54
+ - Signature integrity
55
+ - Token expiry
56
+ - Device fingerprint validation
82
57
 
83
58
  ---
84
59
 
85
- ### Example: Multiple Fingerprints
60
+ ## 4. Sample Code
86
61
 
87
- ```js
88
- const token = sign(
89
- { userId: 1 },
90
- "my-secret",
91
- {
92
- expiresIn: 60,
93
- fingerprint: ["Chrome-Linux", "Windows"]
94
- }
95
- );
62
+ ### Installation
63
+
64
+ ```bash
65
+ npm install secure-web-token
96
66
  ```
97
67
 
98
68
  ---
99
69
 
100
- ## ✅ verify()
101
-
102
- Verifies the token and checks whether the fingerprint is valid.
103
-
104
- ### Syntax
70
+ ### Import
105
71
 
106
72
  ```js
107
- verify(token, secret, options)
73
+ const { sign, verify } = require("secure-web-token");
108
74
  ```
109
75
 
110
- ### Parameters
111
-
112
- | Parameter | Type | Description |
113
- |---------|-----|-------------|
114
- | token | String | Token to verify |
115
- | secret | String | Same secret used while signing |
116
- | options.fingerprint | String \| String[] | Current device fingerprint |
117
-
118
76
  ---
119
77
 
120
- ### Example: Successful Verification
78
+ ### Signing a Token (Auto Device Registration)
121
79
 
122
80
  ```js
123
- const payload = verify(token, "my-secret", {
124
- fingerprint: "Chrome-Linux"
125
- });
81
+ const secret = "my-super-secret";
126
82
 
127
- console.log("PAYLOAD:", payload);
128
- ```
129
-
130
- ---
131
-
132
- ### Example: Multiple Fingerprints Verification
83
+ const { token, deviceId } = sign(
84
+ { userId: 1, role: "admin" },
85
+ secret,
86
+ { fingerprint: true }
87
+ );
133
88
 
134
- ```js
135
- const payload = verify(token, "my-secret", {
136
- fingerprint: ["Chrome-Linux", "monjal"]
137
- });
89
+ console.log("TOKEN:", token);
90
+ console.log("DEVICE ID:", deviceId);
138
91
  ```
139
92
 
140
93
  ---
141
94
 
142
- ## Invalid Fingerprint Example
95
+ ### Verifying the Token
143
96
 
144
97
  ```js
145
98
  try {
146
- verify(token, "my-secret", {
147
- fingerprint: "Unknown-Device"
99
+ const payload = verify(token, secret, {
100
+ fingerprint: deviceId
148
101
  });
102
+
103
+ console.log("USER DATA:", payload.data);
149
104
  } catch (err) {
150
- console.error(err.message);
105
+ console.error("AUTH ERROR:", err.message);
151
106
  }
152
107
  ```
153
108
 
154
109
  ---
155
110
 
156
- ## Token Expiry Example
111
+ ### Using Custom Fingerprints
157
112
 
158
113
  ```js
159
- const token = sign(
160
- { role: "admin" },
161
- "secret-key",
114
+ const { token } = sign(
115
+ { userId: 2 },
116
+ secret,
162
117
  {
163
- expiresIn: 5,
164
- fingerprint: "Chrome-Linux"
118
+ expiresIn: 60,
119
+ fingerprint: ["Chrome-Linux", "192.168.1.10"]
165
120
  }
166
121
  );
167
122
 
168
- // After 5 seconds
169
- verify(token, "secret-key", {
123
+ verify(token, secret, {
170
124
  fingerprint: "Chrome-Linux"
171
125
  });
172
126
  ```
173
127
 
174
128
  ---
175
129
 
176
- ## 📜 License
130
+ ## Payload Structure (Internal)
131
+
132
+ ```js
133
+ {
134
+ data: {
135
+ userId: 1,
136
+ role: "admin"
137
+ },
138
+ iat: 1768368114,
139
+ exp: 1768369014,
140
+ fp: ["device-id"]
141
+ }
142
+ ```
143
+
144
+ ---
145
+
146
+ ## License
177
147
 
178
148
  MIT License
package/dist/decrypt.d.ts CHANGED
@@ -1,2 +1,9 @@
1
+ /**
2
+ * Decrypts an encrypted SWT payload.
3
+ *
4
+ * @param encryptedPayload - Encrypted Base64URL payload
5
+ * @param secret - Secret key
6
+ * @returns Decrypted payload object
7
+ */
1
8
  export default function decrypt(encryptedPayload: string, secret: string): Record<string, any>;
2
9
  //# sourceMappingURL=decrypt.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"decrypt.d.ts","sourceRoot":"","sources":["../src/decrypt.ts"],"names":[],"mappings":"AAGA,MAAM,CAAC,OAAO,UAAU,OAAO,CAC3B,gBAAgB,EAAE,MAAM,EACxB,MAAM,EAAE,MAAM,GACf,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CA0BrB"}
1
+ {"version":3,"file":"decrypt.d.ts","sourceRoot":"","sources":["../src/decrypt.ts"],"names":[],"mappings":"AAGA;;;;;;GAMG;AACH,MAAM,CAAC,OAAO,UAAU,OAAO,CAC7B,gBAAgB,EAAE,MAAM,EACxB,MAAM,EAAE,MAAM,GACb,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAqBrB"}
package/dist/decrypt.js CHANGED
@@ -36,6 +36,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.default = decrypt;
37
37
  const crypto = __importStar(require("crypto"));
38
38
  const utils_1 = require("./utils");
39
+ /**
40
+ * Decrypts an encrypted SWT payload.
41
+ *
42
+ * @param encryptedPayload - Encrypted Base64URL payload
43
+ * @param secret - Secret key
44
+ * @returns Decrypted payload object
45
+ */
39
46
  function decrypt(encryptedPayload, secret) {
40
47
  const data = (0, utils_1.base64urlDecode)(encryptedPayload);
41
48
  const iv = data.subarray(0, 12);
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Generate a secure, random device ID.
3
+ * Used for Device Registration Model.
4
+ *
5
+ * @returns UUID v4 string
6
+ */
7
+ export declare function generateDeviceId(): string;
8
+ //# sourceMappingURL=device.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"device.d.ts","sourceRoot":"","sources":["../src/device.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC"}
package/dist/device.js ADDED
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.generateDeviceId = generateDeviceId;
37
+ const crypto = __importStar(require("crypto"));
38
+ /**
39
+ * Generate a secure, random device ID.
40
+ * Used for Device Registration Model.
41
+ *
42
+ * @returns UUID v4 string
43
+ */
44
+ function generateDeviceId() {
45
+ return crypto.randomUUID();
46
+ }
package/dist/encrypt.d.ts CHANGED
@@ -1,2 +1,10 @@
1
+ /**
2
+ * Encrypts payload using AES-256-GCM.
3
+ * Payload is fully encrypted (unlike JWT).
4
+ *
5
+ * @param payload - Object to encrypt
6
+ * @param secret - Secret key
7
+ * @returns Encrypted Base64URL string
8
+ */
1
9
  export default function encrypt(payload: Record<string, any>, secret: string): string;
2
10
  //# sourceMappingURL=encrypt.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"encrypt.d.ts","sourceRoot":"","sources":["../src/encrypt.ts"],"names":[],"mappings":"AAGA,MAAM,CAAC,OAAO,UAAU,OAAO,CAC3B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC5B,MAAM,EAAE,MAAM,GACf,MAAM,CAoBR"}
1
+ {"version":3,"file":"encrypt.d.ts","sourceRoot":"","sources":["../src/encrypt.ts"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AACH,MAAM,CAAC,OAAO,UAAU,OAAO,CAC7B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC5B,MAAM,EAAE,MAAM,GACb,MAAM,CAkBR"}
package/dist/encrypt.js CHANGED
@@ -36,6 +36,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.default = encrypt;
37
37
  const crypto = __importStar(require("crypto"));
38
38
  const utils_1 = require("./utils");
39
+ /**
40
+ * Encrypts payload using AES-256-GCM.
41
+ * Payload is fully encrypted (unlike JWT).
42
+ *
43
+ * @param payload - Object to encrypt
44
+ * @param secret - Secret key
45
+ * @returns Encrypted Base64URL string
46
+ */
39
47
  function encrypt(payload, secret) {
40
48
  const iv = crypto.randomBytes(12);
41
49
  const key = crypto
package/dist/index.d.ts CHANGED
@@ -1,3 +1,7 @@
1
+ /**
2
+ * Secure Web Token (SWT)
3
+ * Encrypted, device-bound alternative to JWT
4
+ */
1
5
  export { default as sign } from "./sign";
2
6
  export { default as verify } from "./verify";
3
7
  export type { SignOptions } from "./sign";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,QAAQ,CAAC;AACzC,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,UAAU,CAAC;AAE7C,YAAY,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AAC1C,YAAY,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,QAAQ,CAAC;AACzC,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,UAAU,CAAC;AAE7C,YAAY,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AAC1C,YAAY,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC"}
package/dist/index.js CHANGED
@@ -1,4 +1,8 @@
1
1
  "use strict";
2
+ /**
3
+ * Secure Web Token (SWT)
4
+ * Encrypted, device-bound alternative to JWT
5
+ */
2
6
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
7
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
8
  };
package/dist/sign.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Options for signing a secure token
2
+ * Options for signing a Secure Web Token (SWT)
3
3
  */
4
4
  export interface SignOptions {
5
5
  /**
@@ -8,22 +8,17 @@ export interface SignOptions {
8
8
  */
9
9
  expiresIn?: number;
10
10
  /**
11
- * One or more fingerprints allowed to use this token
12
- * Example: device hash, IP hash, browser hash
11
+ * true auto-generate device ID
12
+ * string | string[] custom fingerprints
13
13
  */
14
- fingerprint?: string | string[];
14
+ fingerprint?: true | string | string[];
15
15
  }
16
16
  /**
17
- * Creates a secure encrypted token.
18
- *
19
- * @param payload - Data you want to store inside the token
20
- * @param secret - Secret key used for encryption & signature
21
- * @param options - Optional token settings (expiry, fingerprint)
22
- *
23
- * @returns Encrypted and signed token string
24
- *
25
- * @example
26
- * sign({ userId: 1 }, "secret", { expiresIn: 60 })
17
+ * Creates a Secure Web Token (SWT).
18
+ * User data is stored inside `payload.data`.
27
19
  */
28
- export default function sign(payload: Record<string, any>, secret: string, options?: SignOptions): string;
20
+ export default function sign(data: Record<string, any>, secret: string, options?: SignOptions): {
21
+ token: string;
22
+ deviceId?: string;
23
+ };
29
24
  //# sourceMappingURL=sign.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sign.d.ts","sourceRoot":"","sources":["../src/sign.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;CACjC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,OAAO,UAAU,IAAI,CAC1B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC5B,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,WAAgB,GACxB,MAAM,CA0BR"}
1
+ {"version":3,"file":"sign.d.ts","sourceRoot":"","sources":["../src/sign.ts"],"names":[],"mappings":"AAKA;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,WAAW,CAAC,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,EAAE,CAAC;CACxC;AAED;;;GAGG;AACH,MAAM,CAAC,OAAO,UAAU,IAAI,CAC1B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACzB,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,WAAgB,GACxB;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,CAgDtC"}
package/dist/sign.js CHANGED
@@ -40,31 +40,39 @@ exports.default = sign;
40
40
  const crypto = __importStar(require("crypto"));
41
41
  const encrypt_1 = __importDefault(require("./encrypt"));
42
42
  const utils_1 = require("./utils");
43
+ const device_1 = require("./device");
43
44
  /**
44
- * Creates a secure encrypted token.
45
- *
46
- * @param payload - Data you want to store inside the token
47
- * @param secret - Secret key used for encryption & signature
48
- * @param options - Optional token settings (expiry, fingerprint)
49
- *
50
- * @returns Encrypted and signed token string
51
- *
52
- * @example
53
- * sign({ userId: 1 }, "secret", { expiresIn: 60 })
45
+ * Creates a Secure Web Token (SWT).
46
+ * User data is stored inside `payload.data`.
54
47
  */
55
- function sign(payload, secret, options = {}) {
56
- const header = {
57
- alg: "AES-256-GCM+HMAC",
58
- typ: "STK",
59
- };
48
+ function sign(data, secret, options = {}) {
49
+ if (!secret || typeof secret !== "string") {
50
+ throw new Error("Secret must be a non-empty string");
51
+ }
52
+ if (!data || typeof data !== "object") {
53
+ throw new Error("Data must be an object");
54
+ }
60
55
  const now = Math.floor(Date.now() / 1000);
61
- payload.iat = now;
62
- payload.exp = now + (options.expiresIn ?? 900);
63
- if (options.fingerprint) {
56
+ const payload = {
57
+ data, // 👈 user data lives here
58
+ iat: now,
59
+ exp: now + (options.expiresIn ?? 900),
60
+ };
61
+ let deviceId;
62
+ // 🔐 Device Registration Model
63
+ if (options.fingerprint === true) {
64
+ deviceId = (0, device_1.generateDeviceId)();
65
+ payload.fp = [deviceId];
66
+ }
67
+ else if (options.fingerprint) {
64
68
  payload.fp = Array.isArray(options.fingerprint)
65
69
  ? options.fingerprint
66
70
  : [options.fingerprint];
67
71
  }
72
+ const header = {
73
+ alg: "AES-256-GCM+HMAC",
74
+ typ: "SWT",
75
+ };
68
76
  const encodedHeader = (0, utils_1.base64urlEncode)(JSON.stringify(header));
69
77
  const encryptedPayload = (0, encrypt_1.default)(payload, secret);
70
78
  const dataToSign = `${encodedHeader}.${encryptedPayload}`;
@@ -72,5 +80,8 @@ function sign(payload, secret, options = {}) {
72
80
  .createHmac("sha256", secret)
73
81
  .update(dataToSign)
74
82
  .digest("base64url");
75
- return `${dataToSign}.${signature}`;
83
+ return {
84
+ token: `${dataToSign}.${signature}`,
85
+ deviceId,
86
+ };
76
87
  }
package/dist/utils.d.ts CHANGED
@@ -1,5 +1,33 @@
1
+ /**
2
+ * Encode data into Base64URL format.
3
+ * Used to make tokens URL-safe.
4
+ *
5
+ * @param input - Buffer or string to encode
6
+ * @returns Base64URL encoded string
7
+ */
1
8
  export declare function base64urlEncode(input: Buffer | string): string;
9
+ /**
10
+ * Decode Base64URL encoded data back into Buffer.
11
+ *
12
+ * @param input - Base64URL string
13
+ * @returns Decoded Buffer
14
+ */
2
15
  export declare function base64urlDecode(input: string): Buffer;
16
+ /**
17
+ * Create a SHA-256 hash.
18
+ * Useful for hashing fingerprints or secrets.
19
+ *
20
+ * @param data - String or Buffer to hash
21
+ * @returns SHA-256 hash Buffer
22
+ */
3
23
  export declare function hash(data: string | Buffer): Buffer;
24
+ /**
25
+ * Compare two buffers in constant time.
26
+ * Prevents timing attacks.
27
+ *
28
+ * @param a - First buffer
29
+ * @param b - Second buffer
30
+ * @returns True if equal, false otherwise
31
+ */
4
32
  export declare function timingSafeEqual(a: Buffer, b: Buffer): boolean;
5
33
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAEA,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAE9D;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAErD;AAED,wBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAElD;AAED,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAG7D"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAE9D;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAErD;AAED;;;;;;GAMG;AACH,wBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAElD;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAG7D"}
package/dist/utils.js CHANGED
@@ -38,15 +38,43 @@ exports.base64urlDecode = base64urlDecode;
38
38
  exports.hash = hash;
39
39
  exports.timingSafeEqual = timingSafeEqual;
40
40
  const crypto = __importStar(require("crypto"));
41
+ /**
42
+ * Encode data into Base64URL format.
43
+ * Used to make tokens URL-safe.
44
+ *
45
+ * @param input - Buffer or string to encode
46
+ * @returns Base64URL encoded string
47
+ */
41
48
  function base64urlEncode(input) {
42
49
  return Buffer.from(input).toString("base64url");
43
50
  }
51
+ /**
52
+ * Decode Base64URL encoded data back into Buffer.
53
+ *
54
+ * @param input - Base64URL string
55
+ * @returns Decoded Buffer
56
+ */
44
57
  function base64urlDecode(input) {
45
58
  return Buffer.from(input, "base64url");
46
59
  }
60
+ /**
61
+ * Create a SHA-256 hash.
62
+ * Useful for hashing fingerprints or secrets.
63
+ *
64
+ * @param data - String or Buffer to hash
65
+ * @returns SHA-256 hash Buffer
66
+ */
47
67
  function hash(data) {
48
68
  return crypto.createHash("sha256").update(data).digest();
49
69
  }
70
+ /**
71
+ * Compare two buffers in constant time.
72
+ * Prevents timing attacks.
73
+ *
74
+ * @param a - First buffer
75
+ * @param b - Second buffer
76
+ * @returns True if equal, false otherwise
77
+ */
50
78
  function timingSafeEqual(a, b) {
51
79
  if (a.length !== b.length)
52
80
  return false;
package/dist/verify.d.ts CHANGED
@@ -1,5 +1,14 @@
1
+ /**
2
+ * Options for verifying a Secure Web Token
3
+ */
1
4
  export interface VerifyOptions {
2
- fingerprint?: string | string[];
5
+ /**
6
+ * Device fingerprint(s) allowed to verify token
7
+ */
8
+ fingerprint?: string;
3
9
  }
10
+ /**
11
+ * Verifies and decrypts a Secure Web Token.
12
+ */
4
13
  export default function verify(token: string, secret: string, options?: VerifyOptions): Record<string, any>;
5
14
  //# sourceMappingURL=verify.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../src/verify.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,aAAa;IAC1B,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;CACnC;AAED,MAAM,CAAC,OAAO,UAAU,MAAM,CAC1B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,aAAkB,GAC5B,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAiDrB"}
1
+ {"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../src/verify.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,CAAC,OAAO,UAAU,MAAM,CAC5B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,aAAkB,GAC1B,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAmDrB"}
package/dist/verify.js CHANGED
@@ -40,7 +40,13 @@ exports.default = verify;
40
40
  const crypto = __importStar(require("crypto"));
41
41
  const decrypt_1 = __importDefault(require("./decrypt"));
42
42
  const utils_1 = require("./utils");
43
+ /**
44
+ * Verifies and decrypts a Secure Web Token.
45
+ */
43
46
  function verify(token, secret, options = {}) {
47
+ if (!token || typeof token !== "string") {
48
+ throw new Error("Token must be a string");
49
+ }
44
50
  const parts = token.split(".");
45
51
  if (parts.length !== 3) {
46
52
  throw new Error("Invalid token format");
@@ -59,17 +65,16 @@ function verify(token, secret, options = {}) {
59
65
  if (payload.exp < now) {
60
66
  throw new Error("Token expired");
61
67
  }
68
+ if (!payload.data || typeof payload.data !== "object") {
69
+ throw new Error("Invalid payload structure");
70
+ }
62
71
  if (options.fingerprint) {
63
- const provided = Array.isArray(options.fingerprint)
64
- ? options.fingerprint
65
- : [options.fingerprint];
66
- const stored = Array.isArray(payload.fp)
67
- ? payload.fp
68
- : [];
69
- const matched = provided.some(fp => stored.includes(fp));
72
+ const provided = options.fingerprint;
73
+ const stored = payload.fp;
74
+ const matched = provided === stored;
70
75
  if (!matched) {
71
76
  throw new Error("Fingerprint mismatch");
72
77
  }
73
78
  }
74
- return payload;
79
+ return payload; // { data, iat, exp, fp }
75
80
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "secure-web-token",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "A secure web token utility",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",