secure-web-token 1.2.3 โ 1.2.4
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 +120 -103
- 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,123 +52,141 @@ 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
|
-
|
|
54
|
-
|
|
55
|
-
- Can auto-generate a device ID
|
|
56
|
-
- Optional server-side session management
|
|
63
|
+
## 4. Boiler Code (Core Usage)
|
|
64
|
+
|
|
65
|
+
### `sign()` function
|
|
57
66
|
|
|
58
67
|
```ts
|
|
59
68
|
import { sign } from "secure-web-token";
|
|
60
69
|
|
|
61
|
-
const
|
|
70
|
+
const SECRET = "super-secret-key";
|
|
62
71
|
|
|
63
|
-
// Auto device registration + server session
|
|
64
72
|
const { token, sessionId } = sign(
|
|
65
73
|
{ userId: 1, role: "admin" },
|
|
66
|
-
|
|
67
|
-
{
|
|
74
|
+
SECRET,
|
|
75
|
+
{
|
|
76
|
+
fingerprint: true,
|
|
77
|
+
store: "memory",
|
|
78
|
+
expiresIn: 3600,
|
|
79
|
+
}
|
|
68
80
|
);
|
|
69
|
-
|
|
70
|
-
console.log("TOKEN:", token);
|
|
71
|
-
console.log("SESSION ID (internal, not exposed to browser):", sessionId);
|
|
72
81
|
```
|
|
73
82
|
|
|
74
83
|
---
|
|
75
84
|
|
|
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
|
|
85
|
+
### `verify()` function
|
|
86
86
|
|
|
87
87
|
```ts
|
|
88
88
|
import { verify, getStore } from "secure-web-token";
|
|
89
89
|
|
|
90
|
-
// Get the store instance (MemoryStore / Redis)
|
|
91
90
|
const store = getStore("memory");
|
|
91
|
+
const session = store.getSession(sessionId);
|
|
92
92
|
|
|
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
|
-
}
|
|
93
|
+
const payload = verify(token, SECRET, {
|
|
94
|
+
sessionId,
|
|
95
|
+
fingerprint: session.fingerprint,
|
|
96
|
+
store: "memory",
|
|
97
|
+
});
|
|
104
98
|
```
|
|
105
99
|
|
|
106
100
|
---
|
|
107
101
|
|
|
108
|
-
##
|
|
102
|
+
## 5. Demo App
|
|
109
103
|
|
|
110
|
-
|
|
111
|
-
> This prevents attackers from copying tokens and device IDs from one browser to another.
|
|
104
|
+
### Backend (Express.js + Node.js)
|
|
112
105
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
4. **verify()**** checks session + fingerprint internally** โ ensures single-device access
|
|
119
|
-
5. **Session revocation** automatically prevents token reuse
|
|
120
|
-
|
|
121
|
-
**Example Express backend:**
|
|
122
|
-
|
|
123
|
-
```ts
|
|
124
|
-
import express from "express";
|
|
125
|
-
import cookieParser from "cookie-parser";
|
|
126
|
-
import cors from "cors";
|
|
127
|
-
import { sign, verify, getStore } from "secure-web-token";
|
|
106
|
+
```js
|
|
107
|
+
const express = require("express");
|
|
108
|
+
const cookieParser = require("cookie-parser");
|
|
109
|
+
const cors = require("cors");
|
|
110
|
+
const { sign, verify, getStore } = require("secure-web-token");
|
|
128
111
|
|
|
129
112
|
const app = express();
|
|
130
113
|
app.use(cors({ origin: true, credentials: true }));
|
|
131
114
|
app.use(cookieParser());
|
|
132
|
-
app.use(express.json());
|
|
133
115
|
|
|
134
116
|
const SECRET = "super-secret-key";
|
|
135
117
|
const store = getStore("memory");
|
|
136
118
|
|
|
137
|
-
// LOGIN
|
|
138
119
|
app.post("/login", (req, res) => {
|
|
139
|
-
const user = { userId: 1, name: "
|
|
140
|
-
|
|
120
|
+
const user = { userId: 1, name: "Mintu" };
|
|
121
|
+
|
|
122
|
+
const { token, sessionId } = sign(user, SECRET, {
|
|
123
|
+
fingerprint: true,
|
|
124
|
+
store: "memory",
|
|
125
|
+
});
|
|
141
126
|
|
|
142
|
-
res.cookie("swt_session", sessionId, { httpOnly: true
|
|
127
|
+
res.cookie("swt_session", sessionId, { httpOnly: true });
|
|
143
128
|
res.json({ token });
|
|
144
129
|
});
|
|
145
130
|
|
|
146
|
-
// PROFILE
|
|
147
131
|
app.get("/profile", (req, res) => {
|
|
148
132
|
try {
|
|
149
133
|
const sessionId = req.cookies.swt_session;
|
|
150
134
|
const session = store.getSession(sessionId);
|
|
151
|
-
if (!session) throw new Error("Unauthorized or session expired");
|
|
152
|
-
|
|
153
135
|
const token = req.headers.authorization?.split(" ")[1];
|
|
154
|
-
|
|
136
|
+
|
|
137
|
+
const payload = verify(token, SECRET, {
|
|
138
|
+
sessionId,
|
|
139
|
+
fingerprint: session.fingerprint,
|
|
140
|
+
store: "memory",
|
|
141
|
+
});
|
|
142
|
+
|
|
155
143
|
res.json({ user: payload.data });
|
|
156
|
-
} catch
|
|
157
|
-
res.status(401).json({ error:
|
|
144
|
+
} catch {
|
|
145
|
+
res.status(401).json({ error: "Unauthorized" });
|
|
158
146
|
}
|
|
159
147
|
});
|
|
148
|
+
|
|
149
|
+
app.listen(4000);
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
### Frontend (React.js)
|
|
155
|
+
|
|
156
|
+
```js
|
|
157
|
+
function App() {
|
|
158
|
+
const login = async () => {
|
|
159
|
+
const res = await fetch("http://localhost:4000/login", {
|
|
160
|
+
method: "POST",
|
|
161
|
+
credentials: "include",
|
|
162
|
+
});
|
|
163
|
+
const data = await res.json();
|
|
164
|
+
localStorage.setItem("token", data.token);
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
const profile = async () => {
|
|
168
|
+
const token = localStorage.getItem("token");
|
|
169
|
+
const res = await fetch("http://localhost:4000/profile", {
|
|
170
|
+
credentials: "include",
|
|
171
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
172
|
+
});
|
|
173
|
+
console.log(await res.json());
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
return (
|
|
177
|
+
<>
|
|
178
|
+
<button onClick={login}>Login</button>
|
|
179
|
+
<button onClick={profile}>View Profile</button>
|
|
180
|
+
</>
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export default App;
|
|
160
185
|
```
|
|
161
186
|
|
|
162
187
|
---
|
|
163
188
|
|
|
164
|
-
##
|
|
189
|
+
## 6. Payload Structure
|
|
165
190
|
|
|
166
191
|
```json
|
|
167
192
|
{
|
|
@@ -171,15 +196,13 @@ app.get("/profile", (req, res) => {
|
|
|
171
196
|
},
|
|
172
197
|
"iat": 1768368114,
|
|
173
198
|
"exp": 1768369014,
|
|
174
|
-
"fp": "device-
|
|
199
|
+
"fp": "device-id"
|
|
175
200
|
}
|
|
176
201
|
```
|
|
177
202
|
|
|
178
|
-
> Note: The `fp` (fingerprint) and session ID are **not exposed to the browser**, making token copying attacks impossible.
|
|
179
|
-
|
|
180
203
|
---
|
|
181
204
|
|
|
182
|
-
##
|
|
205
|
+
## Installation
|
|
183
206
|
|
|
184
207
|
```bash
|
|
185
208
|
npm install secure-web-token
|
|
@@ -187,7 +210,7 @@ npm install secure-web-token
|
|
|
187
210
|
|
|
188
211
|
---
|
|
189
212
|
|
|
190
|
-
##
|
|
213
|
+
## Importing
|
|
191
214
|
|
|
192
215
|
```ts
|
|
193
216
|
// ESM
|
|
@@ -199,13 +222,7 @@ const { sign, verify, getStore } = require("secure-web-token");
|
|
|
199
222
|
|
|
200
223
|
---
|
|
201
224
|
|
|
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
|
|
225
|
+
### Final Note
|
|
211
226
|
|
|
227
|
+
If you need **encrypted tokens**, **single-device login**, and **true logout**,
|
|
228
|
+
**Secure Web Token (SWT)** is built for you.
|