secure-web-token 1.2.10 → 1.2.12

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.
Files changed (2) hide show
  1. package/README.md +290 -113
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,47 +1,80 @@
1
- # secure-web-token (SWT)
2
-
3
- > **The secure alternative to JWT** — encrypted, device-bound, and built for production security.
4
-
5
- [![npm total downloads](https://img.shields.io/npm/dt/secure-web-token?color=orange&logo=npm&label=total%20downloads)](https://www.npmjs.com/package/secure-web-token)
6
- [![GitHub stars](https://img.shields.io/github/stars/your-username/secure-web-token?style=flat&logo=github&color=yellow)](https://github.com/your-username/secure-web-token/stargazers)
7
- [![Node.js version](https://img.shields.io/node/v/secure-web-token?logo=node.js&color=green)](https://www.npmjs.com/package/secure-web-token)
8
- [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-3178C6?logo=typescript)](https://www.npmjs.com/package/secure-web-token)
9
- [![Encryption](https://img.shields.io/badge/Encryption-AES--256--GCM-brightgreen)](https://github.com/your-username/secure-web-token)
10
- [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen)](https://github.com/your-username/secure-web-token/pulls)
11
- [![Snyk Vulnerabilities](https://snyk.io/test/github/your-username/secure-web-token/badge.svg)](https://snyk.io/test/github/your-username/secure-web-token)
12
-
13
- ```bash
14
- npm install secure-web-token
15
- ```
1
+ <p align="center">
2
+ <img src="https://res.cloudinary.com/dch9wfmjd/image/upload/v1778127677/varient-1-circle_wykez9.png" alt="Secure Web Token Logo" width="48" align="center" />
3
+ &nbsp;&nbsp;<strong>secure-web-token (SWT)</strong>
4
+ </p>
5
+
6
+ <p align="center">
7
+ <strong>The secure, encrypted, device-bound alternative to JWT — built for Node.js</strong>
8
+ </p>
9
+
10
+ <p align="center">
11
+ <img src="https://res.cloudinary.com/dch9wfmjd/image/upload/v1778126974/downloads-badge_vyp6px.svg" alt="50K+ Downloads" width="560" />
12
+ </p>
13
+
14
+ <p align="center">
15
+ <a href="https://www.npmjs.com/package/secure-web-token">
16
+ <img src="https://img.shields.io/badge/downloads-50k%2B-orange?logo=npm" alt="Downloads" />
17
+ </a>
18
+ <a href="https://github.com/MintuSingh07/node-securewebtoken/stargazers">
19
+ <img src="https://img.shields.io/github/stars/MintuSingh07/node-securewebtoken?style=flat&logo=github&color=yellow" alt="GitHub Stars" />
20
+ </a>
21
+ <a href="https://www.npmjs.com/package/secure-web-token">
22
+ <img src="https://img.shields.io/badge/node-%3E%3D25.5.0-green?logo=node.js" alt="Node.js Version" />
23
+ </a>
24
+ <a href="https://www.npmjs.com/package/secure-web-token">
25
+ <img src="https://img.shields.io/badge/TypeScript-Ready-3178C6?logo=typescript" alt="TypeScript Ready" />
26
+ </a>
27
+ <a href="https://github.com/MintuSingh07/node-securewebtoken">
28
+ <img src="https://img.shields.io/badge/Encryption-AES--256--GCM-brightgreen" alt="AES-256-GCM" />
29
+ </a>
30
+ <a href="https://github.com/MintuSingh07/node-securewebtoken/pulls">
31
+ <img src="https://img.shields.io/badge/PRs-welcome-brightgreen" alt="PRs Welcome" />
32
+ </a>
33
+ <a href="https://snyk.io/test/github/MintuSingh07/node-securewebtoken">
34
+ <img src="https://snyk.io/test/github/MintuSingh07/node-securewebtoken/badge.svg" alt="Known Vulnerabilities" />
35
+ </a>
36
+ </p>
37
+
38
+ <p align="center">
39
+ <a href="#why-swt">Why SWT?</a> •
40
+ <a href="#installation">Installation</a> •
41
+ <a href="#quick-start">Quick Start</a> •
42
+ <a href="#full-expressjs-example">Full Example</a> •
43
+ <a href="#swt-vs-jwt--deep-comparison">SWT vs JWT</a> •
44
+ <a href="#faq">FAQ</a> •
45
+ <a href="#roadmap">Roadmap</a>
46
+ </p>
16
47
 
17
48
  ---
18
49
 
19
- ## Why SWT? (The JWT Problem)
50
+ ## Why SWT?
20
51
 
21
- **JWT has well-known, unfixed security flaws.** If you are using JWT in a security-critical app and have not thought about these, you should stop and read this:
52
+ **JWT has well-known, unfixed security problems.** If you're running a security-critical app — admin panel, SaaS dashboard, fintech, healthcare — and you haven't thought about these, stop and read this.
22
53
 
23
- | Problem | JWT | SWT (Secure Web Token) |
24
- | ----------------------- | ------------------------------------- | -------------------------------------------- |
25
- | Payload encryption | ❌ Base64 only (readable by anyone) | ✅ AES-256-GCM encrypted |
26
- | Device binding | ❌ Token works on any device | ✅ Bound to one device/session |
27
- | True logout | ❌ Tokens stay valid after logout | ✅ Server-side revocation |
28
- | Token theft impact | ❌ Stolen token = full account access | ✅ Stolen token is useless on another device |
29
- | Sensitive data in token | ❌ Visible in browser devtools | ✅ Encrypted, never exposed |
54
+ | Problem | JWT | SWT |
55
+ |---|---|---|
56
+ | Payload encryption | ❌ Base64 only readable by anyone | ✅ AES-256-GCM encrypted |
57
+ | Device binding | ❌ Token works on any device, anywhere | ✅ Bound to the original device/session |
58
+ | True logout | ❌ Tokens stay valid after logout | ✅ Instant server-side revocation |
59
+ | Token theft impact | ❌ Stolen token = full account access | ✅ Stolen token is useless on another device |
60
+ | Sensitive data in token | ❌ Visible in browser devtools | ✅ Encrypted, never exposed |
30
61
 
31
- > **If you are storing user roles, permissions, or any sensitive identifiers in a JWT — they are readable by anyone with the token.** SWT fixes this.
62
+ > **If you're storing user roles, permissions, or any sensitive identifiers in a JWT — they're readable by anyone who gets that token.** SWT fixes this at the architecture level.
32
63
 
33
64
  ---
34
65
 
35
- ## What is Secure Web Token (SWT)?
66
+ ## What is Secure Web Token?
67
+
68
+ **Secure Web Token (SWT)** is a Node.js authentication library that replaces JWT with a system that is fundamentally more secure by design. It solves all four of JWT's critical weaknesses in one package.
36
69
 
37
- **Secure Web Token (SWT)** is a Node.js authentication library that replaces JWT with a system that is fundamentally more secure by design:
70
+ **How it works:**
38
71
 
39
- 1. **AES-256-GCM Encryption** — Your token payload is fully encrypted, not just encoded.
40
- 2. **Device Binding** — Each token is tied to the exact device it was issued to. A stolen token cannot be used from a different device.
41
- 3. **Server-Side Session Management** — Sessions live on the server. Logout actually works.
42
- 4. **HttpOnly Cookie + Token Dual Guard** — Combines the security of HttpOnly cookies with encrypted bearer tokens.
72
+ - 🔐 **AES-256-GCM Encryption** — Your token payload is fully encrypted, not just Base64 encoded. No one can read it without the server secret.
73
+ - 📱 **Device Binding** — Each token is tied to the exact device it was issued to via a server-stored fingerprint. A stolen token cannot be replayed from a different device.
74
+ - 🗄️ **Server-Side Session Management** — Sessions live on the server. Logout actually works — revocation is instant and permanent.
75
+ - 🍪 **HttpOnly Cookie + Token Dual Guard** — The session ID lives in an HttpOnly cookie (XSS-proof), the encrypted payload travels via Authorization header. Neither alone is enough.
43
76
 
44
- **Best suited for:** Admin dashboards, SaaS apps, course platforms, internal tools, healthcare apps, fintech, and any application where a stolen session is unacceptable.
77
+ **Best suited for:** Admin panels, SaaS dashboards, course platforms, internal tools, healthcare apps, fintech APIs, and any application where a stolen session is unacceptable.
45
78
 
46
79
  ---
47
80
 
@@ -70,13 +103,18 @@ import { sign } from "secure-web-token";
70
103
 
71
104
  const SECRET = "your-256-bit-secret";
72
105
 
73
- const { token, sessionId } = sign({ userId: 1, role: "admin" }, SECRET, {
74
- fingerprint: true, // bind to device
75
- store: "memory", // server-side session store
76
- expiresIn: 3600, // 1 hour
77
- });
106
+ const { token, sessionId } = sign(
107
+ { userId: 1, role: "admin" },
108
+ SECRET,
109
+ {
110
+ fingerprint: true, // bind to this device
111
+ store: "memory", // server-side session store
112
+ expiresIn: 3600, // expires in 1 hour
113
+ }
114
+ );
78
115
 
79
- // Send `token` to client, store `sessionId` in HttpOnly cookie
116
+ // Send `token` to client
117
+ // → Store `sessionId` in an HttpOnly cookie (never send to client directly)
80
118
  ```
81
119
 
82
120
  ### 2. Verify a Token (Protected Route)
@@ -85,15 +123,23 @@ const { token, sessionId } = sign({ userId: 1, role: "admin" }, SECRET, {
85
123
  import { verify, getStore } from "secure-web-token";
86
124
 
87
125
  const store = getStore("memory");
88
- const session = store.getSession(sessionId); // from HttpOnly cookie
126
+ const session = store.getSession(sessionId); // retrieved from HttpOnly cookie
89
127
 
90
128
  const payload = verify(token, SECRET, {
91
129
  sessionId,
92
- fingerprint: session.fingerprint,
130
+ fingerprint: session.fingerprint, // must match original device
93
131
  store: "memory",
94
132
  });
95
133
 
96
- // payload.data => { userId: 1, role: "admin" }
134
+ // payload.data { userId: 1, role: "admin" }
135
+ ```
136
+
137
+ ### 3. Logout (True Revocation)
138
+
139
+ ```ts
140
+ // Session is deleted server-side — token is immediately dead
141
+ store.deleteSession(sessionId);
142
+ res.clearCookie("swt_session");
97
143
  ```
98
144
 
99
145
  ---
@@ -103,17 +149,22 @@ const payload = verify(token, SECRET, {
103
149
  ```ts
104
150
  import express from "express";
105
151
  import cookieParser from "cookie-parser";
152
+ import cors from "cors";
106
153
  import { sign, verify, getStore } from "secure-web-token";
107
154
 
108
155
  const app = express();
109
- app.use(express.json());
156
+ app.use(cors({ origin: true, credentials: true }));
110
157
  app.use(cookieParser());
158
+ app.use(express.json());
111
159
 
112
160
  const SECRET = process.env.SWT_SECRET!;
113
161
  const store = getStore("memory");
114
162
 
115
- // Login — issue SWT
163
+ // ──────────────────────────────────────────
164
+ // POST /login — Issue a secure session
165
+ // ──────────────────────────────────────────
116
166
  app.post("/login", (req, res) => {
167
+ // Authenticate user here (DB lookup, password check, etc.)
117
168
  const user = { userId: 1, name: "Alice", role: "admin" };
118
169
 
119
170
  const { token, sessionId } = sign(user, SECRET, {
@@ -122,14 +173,20 @@ app.post("/login", (req, res) => {
122
173
  expiresIn: 3600,
123
174
  });
124
175
 
125
- // sessionId goes in an HttpOnly cookie never accessible to JS
126
- res.cookie("swt_session", sessionId, { httpOnly: true, secure: true });
176
+ // sessionId HttpOnly cookie (invisible to JavaScript, XSS-proof)
177
+ res.cookie("swt_session", sessionId, {
178
+ httpOnly: true,
179
+ secure: true,
180
+ sameSite: "strict",
181
+ });
127
182
 
128
- // Encrypted token goes to client
183
+ // Encrypted token client (localStorage or memory)
129
184
  res.json({ token });
130
185
  });
131
186
 
132
- // Protected route — verify SWT
187
+ // ──────────────────────────────────────────
188
+ // GET /profile — Protected route
189
+ // ──────────────────────────────────────────
133
190
  app.get("/profile", (req, res) => {
134
191
  try {
135
192
  const sessionId = req.cookies.swt_session;
@@ -148,10 +205,12 @@ app.get("/profile", (req, res) => {
148
205
  }
149
206
  });
150
207
 
151
- // Logout — truly invalidates the session
208
+ // ──────────────────────────────────────────
209
+ // POST /logout — True session revocation
210
+ // ──────────────────────────────────────────
152
211
  app.post("/logout", (req, res) => {
153
212
  const sessionId = req.cookies.swt_session;
154
- store.deleteSession(sessionId);
213
+ store.deleteSession(sessionId); // token is dead immediately
155
214
  res.clearCookie("swt_session");
156
215
  res.json({ success: true });
157
216
  });
@@ -159,11 +218,60 @@ app.post("/logout", (req, res) => {
159
218
  app.listen(4000);
160
219
  ```
161
220
 
221
+ ### Frontend (React)
222
+
223
+ ```tsx
224
+ import { useState } from "react";
225
+
226
+ function App() {
227
+ const [user, setUser] = useState(null);
228
+
229
+ const login = async () => {
230
+ const res = await fetch("http://localhost:4000/login", {
231
+ method: "POST",
232
+ credentials: "include", // sends/receives the HttpOnly cookie
233
+ });
234
+ const { token } = await res.json();
235
+ localStorage.setItem("swt_token", token);
236
+ };
237
+
238
+ const getProfile = async () => {
239
+ const token = localStorage.getItem("swt_token");
240
+ const res = await fetch("http://localhost:4000/profile", {
241
+ credentials: "include",
242
+ headers: { Authorization: `Bearer ${token}` },
243
+ });
244
+ const data = await res.json();
245
+ setUser(data.user);
246
+ };
247
+
248
+ const logout = async () => {
249
+ await fetch("http://localhost:4000/logout", {
250
+ method: "POST",
251
+ credentials: "include",
252
+ });
253
+ localStorage.removeItem("swt_token");
254
+ setUser(null);
255
+ };
256
+
257
+ return (
258
+ <>
259
+ <button onClick={login}>Login</button>
260
+ <button onClick={getProfile}>View Profile</button>
261
+ <button onClick={logout}>Logout</button>
262
+ {user && <pre>{JSON.stringify(user, null, 2)}</pre>}
263
+ </>
264
+ );
265
+ }
266
+
267
+ export default App;
268
+ ```
269
+
162
270
  ---
163
271
 
164
272
  ## Token Payload Structure
165
273
 
166
- The payload sent to the client is **fully AES-256-GCM encrypted**. Internally it looks like:
274
+ The payload delivered to the client is **fully AES-256-GCM encrypted**. What lives inside (server-side only):
167
275
 
168
276
  ```json
169
277
  {
@@ -177,88 +285,145 @@ The payload sent to the client is **fully AES-256-GCM encrypted**. Internally it
177
285
  }
178
286
  ```
179
287
 
180
- Unlike JWT, **this is not readable** by decoding the token in the browser or on another server.
288
+ Unlike JWT, this structure **cannot be decoded in the browser**. There is no `atob()` trick. Without the server secret, it is ciphertext.
181
289
 
182
290
  ---
183
291
 
184
292
  ## SWT vs JWT — Deep Comparison
185
293
 
186
- ### JWT Security Flaws (Why You Should Replace JWT)
294
+ ### The 4 Security Problems with JWT
295
+
296
+ **1. Payloads are not encrypted**
297
+
298
+ JWT uses Base64URL encoding — not encryption. Anyone with the token can decode the payload instantly:
299
+
300
+ ```js
301
+ // This works on ANY JWT right now — no key required
302
+ JSON.parse(atob(token.split('.')[1]));
303
+ // → { userId: 1, role: "admin", email: "alice@example.com" }
304
+ ```
305
+
306
+ If your JWT payload leaks (XSS, logs, network interception), all your user data is exposed in plaintext.
307
+
308
+ **2. No device binding**
309
+
310
+ A JWT issued in one country works equally from any other device or server. There is no native way to say "this token belongs to this device." A stolen token is a valid credential — period.
187
311
 
188
- **1. Payloads are not encrypted.**
189
- JWT payloads are Base64URL encoded — not encrypted. Anyone who intercepts or steals the token can read the payload. If you store `role: "admin"` in a JWT, an attacker can see it.
312
+ **3. Logout is not real**
190
313
 
191
- **2. No device binding.**
192
- A JWT issued to a user in New York can be used from a server in Russia. There is no native mechanism in JWT to prevent this.
314
+ JWT is stateless by design. Once issued, a token remains cryptographically valid until it expires — regardless of what you do on the server. Client-side logout (clearing cookies/localStorage) doesn't invalidate the token. An attacker who stole it before logout still has access.
193
315
 
194
- **3. Logout does not work (by design).**
195
- JWT is stateless. Once issued, a JWT is valid until it expires — even after the user logs out. The only fix (token blocklist) defeats the purpose of being stateless.
316
+ **4. Token theft = full session compromise**
196
317
 
197
- **4. Token theft = full session compromise.**
198
- If a JWT is stolen via XSS or network interception, the attacker has full access for the token's entire lifetime.
318
+ There is no fallback. A stolen JWT gives the attacker the same access as the legitimate user for the token's entire lifetime, with no way to tell them apart.
199
319
 
200
- ### How SWT Fixes Every One of These
320
+ ### How SWT Fixes All Four
201
321
 
202
- | JWT Flaw | SWT Solution |
203
- | ------------------- | --------------------------------------------------------------------------------- |
204
- | Readable payload | AES-256-GCM encryption payload is unreadable without the server secret |
205
- | No device binding | Device fingerprint stored in server session — token only valid on original device |
206
- | Logout doesn't work | Server-side session deletion revocation is instant and permanent |
207
- | Token theft | Stolen token cannot be used without matching device fingerprint + server session |
322
+ | JWT Flaw | SWT Solution |
323
+ |---|---|
324
+ | Readable payload | AES-256-GCM — unreadable without the server secret |
325
+ | No device binding | Device fingerprint stored in server session — wrong device = rejected |
326
+ | Logout doesn't work | `store.deleteSession()` immediate, permanent revocation |
327
+ | Token theft | Stolen token fails fingerprint check on any other device |
328
+
329
+ ### Attack Surface Comparison
330
+
331
+ ```
332
+ JWT Attack Model:
333
+ Attacker steals token via XSS
334
+ → Token is valid anywhere
335
+ → Full account access until expiry
336
+ → Nothing you can do
337
+
338
+ SWT Attack Model:
339
+ Attacker steals token via XSS
340
+ → Token requires matching HttpOnly cookie (not stealable via XSS)
341
+ → Even with both, device fingerprint must match
342
+ → Session can be revoked server-side instantly
343
+ ```
208
344
 
209
345
  ---
210
346
 
211
- ## Frequently Asked Questions
347
+ ## Security Architecture
348
+
349
+ ```
350
+ Client Server
351
+ │ │
352
+ │ POST /login │
353
+ ├──────────────────────────────────►│
354
+ │ │ sign(payload, secret, { fingerprint: true })
355
+ │ │ ┌───────────────────────────────────┐
356
+ │ │ │ 1. Encrypt payload (AES-256-GCM) │
357
+ │ │ │ 2. Generate device fingerprint │
358
+ │ │ │ 3. Store session server-side │
359
+ │ │ └───────────────────────────────────┘
360
+ │ { token } + Cookie: sessionId │
361
+ │◄──────────────────────────────────┤
362
+ │ │
363
+ │ GET /profile │
364
+ │ Authorization: Bearer <token> │
365
+ │ Cookie: swt_session=<id> │
366
+ ├──────────────────────────────────►│
367
+ │ │ verify(token, secret, { sessionId, fingerprint })
368
+ │ │ ┌───────────────────────────────────┐
369
+ │ │ │ 1. Decrypt token │
370
+ │ │ │ 2. Match device fingerprint │
371
+ │ │ │ 3. Validate active server session │
372
+ │ │ └───────────────────────────────────┘
373
+ │ { user: { ... } } │
374
+ │◄──────────────────────────────────┤
375
+ │ │
376
+ │ POST /logout │
377
+ ├──────────────────────────────────►│
378
+ │ │ store.deleteSession(sessionId)
379
+ │ │ → Token is dead. Immediately.
380
+ │ { success: true } │
381
+ │◄──────────────────────────────────┤
382
+ ```
383
+
384
+ ---
385
+
386
+ ## FAQ
212
387
 
213
388
  **Q: Is SWT a drop-in replacement for JWT?**
214
- A: The API is simple and migration is straightforward. Instead of `jwt.sign()` use `swt.sign()`. The main addition is server-side session storage and device fingerprinting.
215
389
 
216
- **Q: What encryption does SWT use?**
217
- A: AES-256-GCM — the gold standard for symmetric authenticated encryption. The same algorithm used by TLS 1.3.
390
+ Migration is straightforward. Replace `jwt.sign()` with `sign()` from SWT and `jwt.verify()` with `verify()`. The main additions are server-side session storage and device fingerprinting — both handled automatically when you pass `fingerprint: true`.
391
+
392
+ ---
393
+
394
+ **Q: What encryption algorithm does SWT use?**
395
+
396
+ AES-256-GCM — the gold standard for symmetric authenticated encryption, recommended by NIST, and the same cipher used in TLS 1.3. It provides both confidentiality and integrity (tamper detection) in a single pass.
397
+
398
+ ---
218
399
 
219
- **Q: Does SWT support Redis?**
220
- A: The architecture is Redis-ready. The store interface is designed to plug in Redis for production distributed systems.
400
+ **Q: Does SWT support Redis for distributed systems?**
221
401
 
222
- **Q: Does using server-side sessions make SWT stateful?**
223
- A: Yes — intentionally. The "stateless = good" assumption of JWT trades security for scalability. SWT recovers security while maintaining a minimal server-side footprint. For most applications, this is the correct tradeoff.
402
+ The architecture is Redis-ready by design. The session store interface is built to accept pluggable adapters — Redis support is on the roadmap and can be integrated without changing your application code.
403
+
404
+ ---
405
+
406
+ **Q: SWT is stateful. Isn't stateless better?**
407
+
408
+ Stateless JWT trades security for scalability. That tradeoff made sense for internal microservices, but not for user-facing auth. SWT uses a minimal server-side footprint — one small session record per active user — which is manageable at any production scale. The security gains far outweigh the overhead.
409
+
410
+ ---
224
411
 
225
412
  **Q: When should I still use JWT?**
226
- A: JWT is acceptable for low-security, public-data, short-lived tokens between internal microservices where token interception risk is low. For anything user-facing, SWT is the better choice.
413
+
414
+ JWT is fine for short-lived, low-sensitivity tokens between internal services where interception risk is low and logout/device binding don't matter. For any user-facing session, SWT is the better choice.
415
+
416
+ ---
227
417
 
228
418
  **Q: What Node.js version is required?**
229
- A: Node.js 16+ (uses native `crypto` module for AES-256-GCM).
419
+
420
+ Node.js `>=25.5.0`. SWT uses the native `crypto` module for AES-256-GCM — no external cryptography dependencies.
230
421
 
231
422
  ---
232
423
 
233
- ## Security Architecture
424
+ **Q: Does SWT prevent XSS attacks entirely?**
234
425
 
235
- ```
236
- Client Server
237
- │ │
238
- │ POST /login │
239
- ├──────────────────────────────►│
240
- │ │ sign(payload, secret, { fingerprint: true })
241
- │ │ ┌─────────────────────────────────┐
242
- │ │ │ 1. Encrypt payload (AES-256-GCM)│
243
- │ │ │ 2. Generate device fingerprint │
244
- │ │ │ 3. Store session server-side │
245
- │ │ └─────────────────────────────────┘
246
- │ { token } + [HttpOnly Cookie: sessionId]
247
- │◄──────────────────────────────┤
248
- │ │
249
- │ GET /profile │
250
- │ Authorization: Bearer <token>│
251
- │ Cookie: swt_session=<id> │
252
- ├──────────────────────────────►│
253
- │ │ verify(token, secret, { sessionId, fingerprint })
254
- │ │ ┌─────────────────────────────────┐
255
- │ │ │ 1. Decrypt token │
256
- │ │ │ 2. Match device fingerprint │
257
- │ │ │ 3. Validate server session │
258
- │ │ └─────────────────────────────────┘
259
- │ { user: { ... } } │
260
- │◄──────────────────────────────┤
261
- ```
426
+ SWT significantly reduces the impact of XSS. Because the session ID lives in an HttpOnly cookie, XSS cannot steal it via `document.cookie`. An attacker who steals only the bearer token still can't authenticate without the cookie — and even if they somehow get both, the device fingerprint check provides a third layer of validation.
262
427
 
263
428
  ---
264
429
 
@@ -266,27 +431,39 @@ Client Server
266
431
 
267
432
  - [x] AES-256-GCM payload encryption
268
433
  - [x] Device fingerprint binding
269
- - [x] Memory session store
434
+ - [x] In-memory session store
270
435
  - [x] Token expiry (`iat`, `exp`)
271
436
  - [ ] Redis session store adapter
272
- - [ ] Token rotation / refresh
273
- - [ ] TypeScript types (strict)
274
- - [ ] Express.js middleware helper
437
+ - [ ] Token rotation / silent refresh
438
+ - [ ] Strict TypeScript types
439
+ - [ ] Express.js middleware helper (`swtMiddleware()`)
275
440
  - [ ] Audit log support
441
+ - [ ] React hooks (`useSWT`)
276
442
 
277
443
  ---
278
444
 
279
445
  ## Contributing
280
446
 
281
- PRs and issues welcome. If you find a security vulnerability, please open a private security advisory rather than a public issue.
447
+ PRs and issues are welcome. For security vulnerabilities, please open a **private security advisory** on GitHub rather than a public issue.
448
+
449
+ ```bash
450
+ git clone https://github.com/MintuSingh07/node-securewebtoken.git
451
+ cd node-securewebtoken
452
+ npm install
453
+ npm run build
454
+ ```
282
455
 
283
456
  ---
284
457
 
285
458
  ## License
286
459
 
287
- MIT
460
+ [MIT](./LICENSE) © [MintuSingh07](https://github.com/MintuSingh07)
288
461
 
289
462
  ---
290
463
 
291
- > **Stop using JWT for sensitive user sessions. Your users deserve better.**
292
- > `npm install secure-web-token`
464
+ <p align="center">
465
+ <strong>Stop using JWT for sensitive user sessions.</strong><br/>
466
+ Your users deserve encrypted, device-bound, truly revocable auth.
467
+ <br/><br/>
468
+ <code>npm install secure-web-token</code>
469
+ </p>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "secure-web-token",
3
- "version": "1.2.10",
3
+ "version": "1.2.12",
4
4
  "description": "A secure web token utility",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",