secure-web-token 1.2.3 โ 1.2.5
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 +115 -102
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,43 +1,50 @@
|
|
|
1
1
|
# ๐ Secure Web Token (SWT)
|
|
2
2
|
|
|
3
|
+
A **secure, device-bound authentication token system** for Node.js applications.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
3
7
|
## 1. About the Package
|
|
4
8
|
|
|
5
|
-
Secure Web Token (SWT) is a
|
|
9
|
+
**Secure Web Token (SWT)** is a next-generation alternative to JWT, built for **security-critical applications** where token leakage, device hijacking, or session reuse must be prevented.
|
|
6
10
|
|
|
7
|
-
|
|
11
|
+
Unlike JWTs (which are only Base64 encoded), SWT uses **full encryption + server-side session binding**, making stolen tokens useless on other devices.
|
|
8
12
|
|
|
9
|
-
|
|
10
|
-
- **Device fingerprint binding**: Tokens are locked to a device (or session) to prevent unauthorized reuse.
|
|
11
|
-
- **Server-side session store**: Device IDs and sessions are managed securely on the backend, never exposed to the browser.
|
|
12
|
-
- **Simple developer experience**: Easily integrate into Node.js applications with `sign` and `verify` functions.
|
|
13
|
+
### Key Highlights โจ
|
|
13
14
|
|
|
14
|
-
|
|
15
|
+
- ๐ **AES-256-GCM encrypted payloads**
|
|
16
|
+
- ๐งท **Device-bound tokens (single-device login)**
|
|
17
|
+
- ๐ **Server-side session management**
|
|
18
|
+
- ๐ช **HttpOnly session cookies**
|
|
19
|
+
- โฑ **Expiry support (`iat`, `exp`)**
|
|
20
|
+
- โก Simple API: `sign()` and `verify()`
|
|
21
|
+
- ๐ง Memory store (Redis-ready design)
|
|
15
22
|
|
|
16
23
|
---
|
|
17
24
|
|
|
18
25
|
## 2. What Problem Does It Solve?
|
|
19
26
|
|
|
20
|
-
|
|
27
|
+
### Problems with JWT โ
|
|
21
28
|
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
- No
|
|
25
|
-
-
|
|
29
|
+
- Payloads are readable (Base64 โ encryption)
|
|
30
|
+
- Tokens can be reused on any device
|
|
31
|
+
- No native device binding
|
|
32
|
+
- Logout does not truly invalidate tokens
|
|
26
33
|
|
|
27
|
-
|
|
34
|
+
### How SWT Solves This โ
|
|
28
35
|
|
|
29
|
-
-
|
|
30
|
-
-
|
|
31
|
-
-
|
|
32
|
-
-
|
|
33
|
-
-
|
|
36
|
+
- Encrypts payload using **AES-256-GCM**
|
|
37
|
+
- Binds tokens to **server-managed device sessions**
|
|
38
|
+
- Prevents token reuse across devices
|
|
39
|
+
- Supports true logout via session revocation
|
|
40
|
+
- Sensitive identifiers never reach the browser
|
|
34
41
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
- Course platforms with anti-piracy requirements
|
|
42
|
+
**Best suited for:**
|
|
43
|
+
- Admin panels
|
|
38
44
|
- SaaS dashboards
|
|
39
|
-
-
|
|
40
|
-
-
|
|
45
|
+
- Course platforms
|
|
46
|
+
- Internal tools
|
|
47
|
+
- High-security APIs
|
|
41
48
|
|
|
42
49
|
---
|
|
43
50
|
|
|
@@ -45,81 +52,54 @@ Use cases:
|
|
|
45
52
|
|
|
46
53
|
### `sign()`
|
|
47
54
|
|
|
48
|
-
Creates a **secure, encrypted token**.
|
|
55
|
+
Creates a **secure, encrypted token** and optionally registers a **server-side device session**.
|
|
56
|
+
|
|
57
|
+
### `verify()`
|
|
58
|
+
|
|
59
|
+
Validates and decrypts the token, ensuring the request comes from the **correct device and active session**.
|
|
49
60
|
|
|
50
|
-
|
|
61
|
+
---
|
|
51
62
|
|
|
52
|
-
|
|
53
|
-
- Adds `iat` (issued at) and `exp` (expiry) timestamps
|
|
54
|
-
- Supports **device fingerprint binding**
|
|
55
|
-
- Can auto-generate a device ID
|
|
56
|
-
- Optional server-side session management
|
|
63
|
+
## 4. Boiler Code (Core Usage)
|
|
57
64
|
|
|
65
|
+
### `sign()` function
|
|
58
66
|
```ts
|
|
59
67
|
import { sign } from "secure-web-token";
|
|
60
68
|
|
|
61
|
-
const
|
|
69
|
+
const SECRET = "super-secret-key";
|
|
62
70
|
|
|
63
|
-
// Auto device registration + server session
|
|
64
71
|
const { token, sessionId } = sign(
|
|
65
72
|
{ userId: 1, role: "admin" },
|
|
66
|
-
|
|
67
|
-
{
|
|
73
|
+
SECRET,
|
|
74
|
+
{
|
|
75
|
+
fingerprint: true,
|
|
76
|
+
store: "memory",
|
|
77
|
+
expiresIn: 3600,
|
|
78
|
+
}
|
|
68
79
|
);
|
|
69
|
-
|
|
70
|
-
console.log("TOKEN:", token);
|
|
71
|
-
console.log("SESSION ID (internal, not exposed to browser):", sessionId);
|
|
72
80
|
```
|
|
73
81
|
|
|
74
82
|
---
|
|
75
83
|
|
|
76
|
-
### `verify()`
|
|
77
|
-
|
|
78
|
-
Verifies and decrypts a token.
|
|
79
|
-
|
|
80
|
-
**Checks performed:**
|
|
81
|
-
|
|
82
|
-
- Token format integrity
|
|
83
|
-
- Signature correctness
|
|
84
|
-
- Expiry check
|
|
85
|
-
- Device fingerprint / session validation
|
|
86
|
-
|
|
84
|
+
### `verify()` function
|
|
87
85
|
```ts
|
|
88
86
|
import { verify, getStore } from "secure-web-token";
|
|
89
87
|
|
|
90
|
-
// Get the store instance (MemoryStore / Redis)
|
|
91
88
|
const store = getStore("memory");
|
|
89
|
+
const session = store.getSession(sessionId);
|
|
92
90
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
console.log("USER DATA:", payload.data);
|
|
101
|
-
} catch (err) {
|
|
102
|
-
console.error("AUTH ERROR:", err.message);
|
|
103
|
-
}
|
|
91
|
+
const payload = verify(token, SECRET, {
|
|
92
|
+
sessionId,
|
|
93
|
+
fingerprint: session.fingerprint,
|
|
94
|
+
store: "memory",
|
|
95
|
+
});
|
|
104
96
|
```
|
|
105
97
|
|
|
106
98
|
---
|
|
107
99
|
|
|
108
|
-
##
|
|
109
|
-
|
|
110
|
-
> In SWT v2+, **device verification is entirely server-side**.\
|
|
111
|
-
> This prevents attackers from copying tokens and device IDs from one browser to another.
|
|
112
|
-
|
|
113
|
-
**Workflow:**
|
|
114
|
-
|
|
115
|
-
1. **User logs in** โ `sign()` generates token + server session
|
|
116
|
-
2. **Server stores session** internally (deviceId, fingerprint)
|
|
117
|
-
3. **Browser receives token + HttpOnly cookie** โ cannot read device ID
|
|
118
|
-
4. **verify()**** checks session + fingerprint internally** โ ensures single-device access
|
|
119
|
-
5. **Session revocation** automatically prevents token reuse
|
|
120
|
-
|
|
121
|
-
**Example Express backend:**
|
|
100
|
+
## 5. Demo App
|
|
122
101
|
|
|
102
|
+
### Backend (Express.js + Node.js)
|
|
123
103
|
```ts
|
|
124
104
|
import express from "express";
|
|
125
105
|
import cookieParser from "cookie-parser";
|
|
@@ -134,35 +114,78 @@ app.use(express.json());
|
|
|
134
114
|
const SECRET = "super-secret-key";
|
|
135
115
|
const store = getStore("memory");
|
|
136
116
|
|
|
137
|
-
// LOGIN
|
|
138
117
|
app.post("/login", (req, res) => {
|
|
139
|
-
const user = { userId: 1, name: "
|
|
140
|
-
|
|
118
|
+
const user = { userId: 1, name: "Mintu" };
|
|
119
|
+
|
|
120
|
+
const { token, sessionId } = sign(user, SECRET, {
|
|
121
|
+
fingerprint: true,
|
|
122
|
+
store: "memory",
|
|
123
|
+
});
|
|
141
124
|
|
|
142
|
-
res.cookie("swt_session", sessionId, { httpOnly: true
|
|
125
|
+
res.cookie("swt_session", sessionId, { httpOnly: true });
|
|
143
126
|
res.json({ token });
|
|
144
127
|
});
|
|
145
128
|
|
|
146
|
-
// PROFILE
|
|
147
129
|
app.get("/profile", (req, res) => {
|
|
148
130
|
try {
|
|
149
131
|
const sessionId = req.cookies.swt_session;
|
|
150
132
|
const session = store.getSession(sessionId);
|
|
151
|
-
if (!session) throw new Error("Unauthorized or session expired");
|
|
152
|
-
|
|
153
133
|
const token = req.headers.authorization?.split(" ")[1];
|
|
154
|
-
|
|
134
|
+
|
|
135
|
+
const payload = verify(token, SECRET, {
|
|
136
|
+
sessionId,
|
|
137
|
+
fingerprint: session.fingerprint,
|
|
138
|
+
store: "memory",
|
|
139
|
+
});
|
|
140
|
+
|
|
155
141
|
res.json({ user: payload.data });
|
|
156
|
-
} catch
|
|
157
|
-
res.status(401).json({ error:
|
|
142
|
+
} catch {
|
|
143
|
+
res.status(401).json({ error: "Unauthorized" });
|
|
158
144
|
}
|
|
159
145
|
});
|
|
146
|
+
|
|
147
|
+
app.listen(4000);
|
|
160
148
|
```
|
|
161
149
|
|
|
162
|
-
|
|
150
|
+
### Frontend (React.js)
|
|
151
|
+
```tsx
|
|
152
|
+
import { useState } from "react";
|
|
153
|
+
|
|
154
|
+
function App() {
|
|
155
|
+
const [user, setUser] = useState(null);
|
|
156
|
+
|
|
157
|
+
const login = async () => {
|
|
158
|
+
const res = await fetch("http://localhost:4000/login", {
|
|
159
|
+
method: "POST",
|
|
160
|
+
credentials: "include",
|
|
161
|
+
});
|
|
162
|
+
const data = await res.json();
|
|
163
|
+
localStorage.setItem("token", data.token);
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
const profile = async () => {
|
|
167
|
+
const token = localStorage.getItem("token");
|
|
168
|
+
const res = await fetch("http://localhost:4000/profile", {
|
|
169
|
+
credentials: "include",
|
|
170
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
171
|
+
});
|
|
172
|
+
console.log(await res.json());
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
return (
|
|
176
|
+
<>
|
|
177
|
+
<button onClick={login}>Login</button>
|
|
178
|
+
<button onClick={profile}>View Profile</button>
|
|
179
|
+
</>
|
|
180
|
+
);
|
|
181
|
+
}
|
|
163
182
|
|
|
164
|
-
|
|
183
|
+
export default App;
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
---
|
|
165
187
|
|
|
188
|
+
## 6. Payload Structure
|
|
166
189
|
```json
|
|
167
190
|
{
|
|
168
191
|
"data": {
|
|
@@ -171,24 +194,20 @@ app.get("/profile", (req, res) => {
|
|
|
171
194
|
},
|
|
172
195
|
"iat": 1768368114,
|
|
173
196
|
"exp": 1768369014,
|
|
174
|
-
"fp": "device-
|
|
197
|
+
"fp": "device-id"
|
|
175
198
|
}
|
|
176
199
|
```
|
|
177
200
|
|
|
178
|
-
> Note: The `fp` (fingerprint) and session ID are **not exposed to the browser**, making token copying attacks impossible.
|
|
179
|
-
|
|
180
201
|
---
|
|
181
202
|
|
|
182
|
-
##
|
|
183
|
-
|
|
203
|
+
## 7. Installation
|
|
184
204
|
```bash
|
|
185
205
|
npm install secure-web-token
|
|
186
206
|
```
|
|
187
207
|
|
|
188
208
|
---
|
|
189
209
|
|
|
190
|
-
##
|
|
191
|
-
|
|
210
|
+
## 8. Importing
|
|
192
211
|
```ts
|
|
193
212
|
// ESM
|
|
194
213
|
import { sign, verify, getStore } from "secure-web-token";
|
|
@@ -199,13 +218,7 @@ const { sign, verify, getStore } = require("secure-web-token");
|
|
|
199
218
|
|
|
200
219
|
---
|
|
201
220
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
- ๐ AES-256-GCM encryption
|
|
205
|
-
- ๐ Server-side session + device binding
|
|
206
|
-
- โฑ Expiry (`iat` + `exp`)
|
|
207
|
-
- ๐ก Prevents token reuse on unauthorized devices
|
|
208
|
-
- โก Easy integration with Node.js / Express
|
|
209
|
-
- โ
Auto-generated device IDs
|
|
210
|
-
- โ
Fully optional server-side memory store
|
|
221
|
+
### Final Note
|
|
211
222
|
|
|
223
|
+
If you need **encrypted tokens**, **single-device login**, and **true logout**,
|
|
224
|
+
**Secure Web Token (SWT)** is built for you.
|