hi-secure 1.0.12 → 1.0.14
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/adapters/ArgonAdapter.js +2 -2
- package/dist/adapters/ArgonAdapter.js.map +1 -1
- package/dist/adapters/BcryptAdapter.js +2 -2
- package/dist/adapters/BcryptAdapter.js.map +1 -1
- package/dist/adapters/ExpressRLAdapter.js +2 -2
- package/dist/adapters/ExpressRLAdapter.js.map +1 -1
- package/dist/adapters/ExpressValidatorAdapter.js +1 -1
- package/dist/adapters/ExpressValidatorAdapter.js.map +1 -1
- package/dist/adapters/GoogleAdapter.js +3 -3
- package/dist/adapters/GoogleAdapter.js.map +1 -1
- package/dist/adapters/JWTAdapter.js +2 -2
- package/dist/adapters/JWTAdapter.js.map +1 -1
- package/dist/adapters/RLFlexibleAdapter.js +2 -2
- package/dist/adapters/RLFlexibleAdapter.js.map +1 -1
- package/dist/adapters/SanitizeHtmlAdapter.js +3 -3
- package/dist/adapters/SanitizeHtmlAdapter.js.map +1 -1
- package/dist/adapters/XSSAdapter.js +3 -3
- package/dist/adapters/XSSAdapter.js.map +1 -1
- package/dist/adapters/ZodAdapter.js +1 -1
- package/dist/adapters/ZodAdapter.js.map +1 -1
- package/dist/core/HiSecure.d.ts.map +1 -1
- package/dist/core/HiSecure.js +9 -8
- package/dist/core/HiSecure.js.map +1 -1
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +0 -7
- package/dist/core/config.js.map +1 -1
- package/dist/core/constants.d.ts.map +1 -1
- package/dist/core/constants.js +0 -27
- package/dist/core/constants.js.map +1 -1
- package/dist/core/errors/AdapterError.js +1 -1
- package/dist/core/errors/AdapterError.js.map +1 -1
- package/dist/core/types/HiSecureConfig.d.ts.map +1 -1
- package/dist/core/types/HiSecureConfig.js.map +1 -1
- package/dist/core/types/SecureOptions.d.ts.map +1 -1
- package/dist/core/types/SecureOptions.js +0 -1
- package/dist/core/types/SecureOptions.js.map +1 -1
- package/dist/core/useSecure.d.ts.map +1 -1
- package/dist/core/useSecure.js +1 -1
- package/dist/core/useSecure.js.map +1 -1
- package/dist/managers/AuthManager.js +2 -2
- package/dist/managers/AuthManager.js.map +1 -1
- package/dist/managers/CorsManager.d.ts.map +1 -1
- package/dist/managers/CorsManager.js +2 -2
- package/dist/managers/CorsManager.js.map +1 -1
- package/dist/managers/HashManager.js +7 -7
- package/dist/managers/HashManager.js.map +1 -1
- package/dist/managers/JsonManager.js +4 -4
- package/dist/managers/JsonManager.js.map +1 -1
- package/dist/managers/RateLimitManager.js +5 -5
- package/dist/managers/RateLimitManager.js.map +1 -1
- package/dist/managers/SanitizerManager.js +5 -5
- package/dist/managers/SanitizerManager.js.map +1 -1
- package/dist/managers/ValidatorManager.js +2 -2
- package/dist/managers/ValidatorManager.js.map +1 -1
- package/dist/middlewares/errorHandler.js +3 -3
- package/dist/middlewares/errorHandler.js.map +1 -1
- package/package.json +1 -1
- package/readme.md +566 -388
- package/src/adapters/ArgonAdapter.ts +2 -2
- package/src/adapters/BcryptAdapter.ts +2 -2
- package/src/adapters/ExpressRLAdapter.ts +2 -2
- package/src/adapters/ExpressValidatorAdapter.ts +1 -1
- package/src/adapters/GoogleAdapter.ts +3 -3
- package/src/adapters/JWTAdapter.ts +2 -2
- package/src/adapters/RLFlexibleAdapter.ts +2 -2
- package/src/adapters/SanitizeHtmlAdapter.ts +3 -3
- package/src/adapters/XSSAdapter.ts +3 -3
- package/src/adapters/ZodAdapter.ts +1 -1
- package/src/core/HiSecure.ts +10 -8
- package/src/core/config.ts +0 -105
- package/src/core/constants.ts +0 -33
- package/src/core/errors/AdapterError.ts +1 -1
- package/src/core/types/HiSecureConfig.ts +0 -1
- package/src/core/types/SecureOptions.ts +0 -27
- package/src/core/useSecure.ts +1 -3
- package/src/managers/AuthManager.ts +2 -2
- package/src/managers/CorsManager.ts +2 -2
- package/src/managers/HashManager.ts +7 -7
- package/src/managers/JsonManager.ts +4 -4
- package/src/managers/RateLimitManager.ts +5 -5
- package/src/managers/SanitizerManager.ts +5 -5
- package/src/managers/ValidatorManager.ts +2 -2
- package/src/middlewares/errorHandler.ts +3 -3
package/readme.md
CHANGED
|
@@ -2,279 +2,445 @@
|
|
|
2
2
|
<p align="center"><strong>One-line security for Express.js</strong></p>
|
|
3
3
|
|
|
4
4
|
<p align="center">
|
|
5
|
-
HiSecure
|
|
6
|
-
|
|
7
|
-
security headers, compression, JSON parsing, query parsing and logging — all in a single layer.
|
|
5
|
+
HiSecure unifies authentication, validation, sanitization, rate-limiting, headers and parsing<br/>
|
|
6
|
+
into a single, consistent security layer for Express applications.
|
|
8
7
|
</p>
|
|
9
8
|
|
|
10
|
-
<
|
|
9
|
+
<hr/>
|
|
11
10
|
|
|
12
|
-
<
|
|
13
|
-
|
|
14
|
-
<h2>🚀 Overview</h2>
|
|
11
|
+
<h2>Overview</h2>
|
|
15
12
|
|
|
16
13
|
<p>
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
Managing
|
|
14
|
+
Modern Express applications require multiple security libraries to handle authentication,
|
|
15
|
+
password hashing, validation, sanitization, rate limiting, headers, compression and parsing.
|
|
16
|
+
Managing these separately leads to duplicated logic, configuration drift and subtle bugs.
|
|
20
17
|
</p>
|
|
21
18
|
|
|
22
|
-
<p
|
|
19
|
+
<p>
|
|
20
|
+
<strong>HiSecure solves this by acting as a single orchestration layer.</strong>
|
|
21
|
+
</p>
|
|
23
22
|
|
|
24
23
|
<ul>
|
|
25
|
-
<li
|
|
26
|
-
<li
|
|
27
|
-
<li
|
|
28
|
-
<li
|
|
29
|
-
<li
|
|
30
|
-
<li
|
|
31
|
-
<li
|
|
32
|
-
<li><code>json/urlencoded</code> — parsers</li>
|
|
33
|
-
<li><code>qs</code> — secure deep query parsing</li>
|
|
24
|
+
<li>Password hashing (Argon2 with bcrypt fallback)</li>
|
|
25
|
+
<li>JWT authentication and route protection</li>
|
|
26
|
+
<li>Google login (ID token verification)</li>
|
|
27
|
+
<li>Request validation and sanitization</li>
|
|
28
|
+
<li>Rate limiting and abuse prevention</li>
|
|
29
|
+
<li>CORS, security headers and compression</li>
|
|
30
|
+
<li>JSON, URL and query parsing</li>
|
|
34
31
|
</ul>
|
|
35
32
|
|
|
36
|
-
<
|
|
37
|
-
|
|
38
|
-
<br/>
|
|
39
|
-
<hr style="border:0; border-top:2px solid #e5e7eb; margin:32px 0"/>
|
|
33
|
+
<hr/>
|
|
40
34
|
|
|
41
|
-
<h2
|
|
42
|
-
|
|
43
|
-
<p>
|
|
44
|
-
A complete list of what HiSecure does.
|
|
45
|
-
Everything is built to work together without configuration.
|
|
46
|
-
</p>
|
|
35
|
+
<h2>Feature Matrix</h2>
|
|
47
36
|
|
|
48
37
|
<table width="100%">
|
|
49
38
|
<tr>
|
|
50
39
|
<th align="left">Capability</th>
|
|
51
40
|
<th align="left">Status</th>
|
|
52
|
-
<th align="left">
|
|
41
|
+
<th align="left">Notes</th>
|
|
53
42
|
</tr>
|
|
54
43
|
|
|
55
44
|
<tr>
|
|
56
|
-
<td
|
|
57
|
-
<td
|
|
58
|
-
<td>
|
|
45
|
+
<td>JWT Authentication</td>
|
|
46
|
+
<td>Stable</td>
|
|
47
|
+
<td>Issuer, audience, expiry and subject supported</td>
|
|
59
48
|
</tr>
|
|
60
49
|
|
|
61
50
|
<tr>
|
|
62
|
-
<td
|
|
63
|
-
<td
|
|
64
|
-
<td>Argon2
|
|
51
|
+
<td>Password Hashing</td>
|
|
52
|
+
<td>Stable</td>
|
|
53
|
+
<td>Argon2 primary with bcrypt fallback</td>
|
|
65
54
|
</tr>
|
|
66
55
|
|
|
67
56
|
<tr>
|
|
68
|
-
<td
|
|
69
|
-
<td
|
|
70
|
-
<td>
|
|
57
|
+
<td>Google Login</td>
|
|
58
|
+
<td>Stable</td>
|
|
59
|
+
<td>ID token verification adapter included</td>
|
|
71
60
|
</tr>
|
|
72
61
|
|
|
73
62
|
<tr>
|
|
74
|
-
<td
|
|
75
|
-
<td
|
|
76
|
-
<td>
|
|
63
|
+
<td>Route Protection (RBAC)</td>
|
|
64
|
+
<td>Stable</td>
|
|
65
|
+
<td>Role-based access via JWT payload</td>
|
|
77
66
|
</tr>
|
|
78
67
|
|
|
79
68
|
<tr>
|
|
80
|
-
<td
|
|
81
|
-
<td
|
|
82
|
-
<td>
|
|
69
|
+
<td>Validation</td>
|
|
70
|
+
<td>Stable</td>
|
|
71
|
+
<td>Zod and express-validator supported</td>
|
|
83
72
|
</tr>
|
|
84
73
|
|
|
85
74
|
<tr>
|
|
86
|
-
<td
|
|
87
|
-
<td
|
|
88
|
-
<td>
|
|
75
|
+
<td>Sanitization</td>
|
|
76
|
+
<td>Stable</td>
|
|
77
|
+
<td>HTML injection and XSS protection</td>
|
|
89
78
|
</tr>
|
|
90
79
|
|
|
91
80
|
<tr>
|
|
92
|
-
<td
|
|
93
|
-
<td
|
|
94
|
-
<td>
|
|
81
|
+
<td>Rate Limiting</td>
|
|
82
|
+
<td>Stable</td>
|
|
83
|
+
<td>Presets and per-route configuration</td>
|
|
95
84
|
</tr>
|
|
96
85
|
|
|
97
86
|
<tr>
|
|
98
|
-
<td
|
|
99
|
-
<td
|
|
100
|
-
<td>
|
|
87
|
+
<td>CORS & Headers</td>
|
|
88
|
+
<td>Stable</td>
|
|
89
|
+
<td>Helmet, HPP and CORS integrated</td>
|
|
101
90
|
</tr>
|
|
102
91
|
|
|
103
92
|
<tr>
|
|
104
|
-
<td
|
|
105
|
-
<td
|
|
106
|
-
<td>
|
|
93
|
+
<td>Compression</td>
|
|
94
|
+
<td>Stable</td>
|
|
95
|
+
<td>gzip via a single flag</td>
|
|
107
96
|
</tr>
|
|
108
97
|
|
|
109
98
|
<tr>
|
|
110
|
-
<td
|
|
111
|
-
<td
|
|
112
|
-
<td>
|
|
99
|
+
<td>Logging</td>
|
|
100
|
+
<td>Beta</td>
|
|
101
|
+
<td>Structured internal logs</td>
|
|
113
102
|
</tr>
|
|
103
|
+
</table>
|
|
114
104
|
|
|
115
|
-
|
|
116
|
-
<td>🌀 Compression</td>
|
|
117
|
-
<td>✅ Stable</td>
|
|
118
|
-
<td>gzip enabled via a single flag.</td>
|
|
119
|
-
</tr>
|
|
105
|
+
<hr/>
|
|
120
106
|
|
|
121
|
-
|
|
122
|
-
<td>📊 Structured Logging</td>
|
|
123
|
-
<td>⚠️ Beta</td>
|
|
124
|
-
<td>Unified log output for debugging & monitoring.</td>
|
|
125
|
-
</tr>
|
|
107
|
+
<h2>Developer Experience</h2>
|
|
126
108
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
</
|
|
132
|
-
</
|
|
109
|
+
<ul>
|
|
110
|
+
<li>Single global middleware for security</li>
|
|
111
|
+
<li>No manual wiring of multiple packages</li>
|
|
112
|
+
<li>Consistent error handling</li>
|
|
113
|
+
<li>Safe defaults with escape hatches</li>
|
|
114
|
+
<li>Beginner-friendly, production-ready</li>
|
|
115
|
+
</ul>
|
|
116
|
+
|
|
117
|
+
<hr/>
|
|
118
|
+
|
|
119
|
+
<h2>Quick Start</h2>
|
|
120
|
+
|
|
121
|
+
<pre><code>npm install hi-secure</code></pre>
|
|
122
|
+
|
|
123
|
+
<pre><code>import express from "express";
|
|
124
|
+
import { HiSecure } from "hi-secure";
|
|
125
|
+
|
|
126
|
+
const app = express();
|
|
127
|
+
|
|
128
|
+
app.use(HiSecure.middleware("api"));
|
|
129
|
+
|
|
130
|
+
app.listen(3000);
|
|
131
|
+
</code></pre>
|
|
133
132
|
|
|
134
|
-
<
|
|
135
|
-
<hr style="border:0; border-top:2px solid #e5e7eb; margin:32px 0"/>
|
|
133
|
+
<hr/>
|
|
136
134
|
|
|
137
|
-
<h2
|
|
135
|
+
<h2>Core Helpers</h2>
|
|
136
|
+
|
|
137
|
+
<h3>Password Hashing</h3>
|
|
138
|
+
|
|
139
|
+
<pre><code>const hash = await HiSecure.hash(password);
|
|
140
|
+
const isValid = await HiSecure.verify(password, hash);
|
|
141
|
+
</code></pre>
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
<h3>Input Validation</h3>
|
|
147
|
+
|
|
148
|
+
<pre><code>router.post(
|
|
149
|
+
"/register",
|
|
150
|
+
HiSecure.validate([...]),
|
|
151
|
+
controller
|
|
152
|
+
);
|
|
153
|
+
</code></pre>
|
|
154
|
+
|
|
155
|
+
<h3>Rate Limiting</h3>
|
|
156
|
+
|
|
157
|
+
<pre><code>HiSecure.rateLimit({ max: 5, windowMs: 15 * 60 * 1000 });
|
|
158
|
+
</code></pre>
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
<hr/>
|
|
163
|
+
|
|
164
|
+
<h2>Global CORS Configuration</h2>
|
|
138
165
|
|
|
139
166
|
<p>
|
|
140
|
-
|
|
141
|
-
|
|
167
|
+
Global CORS defines the baseline access rules for your entire application.
|
|
168
|
+
These rules apply to all routes unless explicitly overridden at the route level.
|
|
142
169
|
</p>
|
|
143
170
|
|
|
144
|
-
<
|
|
145
|
-
|
|
171
|
+
<p>
|
|
172
|
+
This is ideal for standard APIs where most endpoints share the same access policy.
|
|
173
|
+
</p>
|
|
174
|
+
|
|
175
|
+
<hr/>
|
|
176
|
+
|
|
177
|
+
<h3>Basic Global CORS</h3>
|
|
178
|
+
|
|
179
|
+
<p>
|
|
180
|
+
Enable CORS globally using default configuration.
|
|
181
|
+
</p>
|
|
182
|
+
|
|
183
|
+
<pre><code>app.use(
|
|
184
|
+
HiSecure.middleware({
|
|
185
|
+
cors: true
|
|
186
|
+
})
|
|
187
|
+
);
|
|
188
|
+
</code></pre>
|
|
146
189
|
|
|
147
|
-
|
|
148
|
-
<br/>• <code>HiSecure.hash()</code> — secure Argon2 hashing
|
|
149
|
-
<br/>• <code>HiSecure.verify()</code> — easy password comparison
|
|
150
|
-
</li>
|
|
190
|
+
<hr/>
|
|
151
191
|
|
|
152
|
-
|
|
153
|
-
<br/>• <code>HiSecure.jwt.sign()</code> — create tokens
|
|
154
|
-
<br/>• <code>HiSecure.jwt.verify()</code> — verify tokens
|
|
155
|
-
</li>
|
|
192
|
+
<h3>Custom Global CORS</h3>
|
|
156
193
|
|
|
157
|
-
|
|
194
|
+
<p>
|
|
195
|
+
Define explicit CORS rules for all routes.
|
|
196
|
+
</p>
|
|
158
197
|
|
|
159
|
-
|
|
198
|
+
<pre><code>app.use(
|
|
199
|
+
HiSecure.middleware({
|
|
200
|
+
cors: {
|
|
201
|
+
origin: ["https://app.example.com"],
|
|
202
|
+
methods: ["GET", "POST", "PUT", "DELETE"],
|
|
203
|
+
allowedHeaders: ["Content-Type", "Authorization"],
|
|
204
|
+
credentials: true
|
|
205
|
+
}
|
|
206
|
+
})
|
|
207
|
+
);
|
|
208
|
+
</code></pre>
|
|
160
209
|
|
|
161
|
-
|
|
210
|
+
<hr/>
|
|
162
211
|
|
|
163
|
-
|
|
212
|
+
<h3>Multiple Client Applications</h3>
|
|
164
213
|
|
|
165
|
-
|
|
214
|
+
<p>
|
|
215
|
+
Allow multiple frontends (web, admin, mobile) to access the same API.
|
|
216
|
+
</p>
|
|
166
217
|
|
|
167
|
-
|
|
168
|
-
|
|
218
|
+
<pre><code>app.use(
|
|
219
|
+
HiSecure.middleware({
|
|
220
|
+
cors: {
|
|
221
|
+
origin: [
|
|
222
|
+
"https://web.example.com",
|
|
223
|
+
"https://admin.example.com",
|
|
224
|
+
"https://mobile.example.com"
|
|
225
|
+
],
|
|
226
|
+
credentials: true
|
|
227
|
+
}
|
|
228
|
+
})
|
|
229
|
+
);
|
|
230
|
+
</code></pre>
|
|
169
231
|
|
|
170
|
-
<
|
|
171
|
-
<hr style="border:0; border-top:2px solid #e5e7eb; margin:32px 0"/>
|
|
232
|
+
<hr/>
|
|
172
233
|
|
|
173
|
-
<
|
|
234
|
+
<h3>Public API (Open Read Access)</h3>
|
|
174
235
|
|
|
175
236
|
<p>
|
|
176
|
-
|
|
237
|
+
Use open CORS rules for public or read-only APIs.
|
|
177
238
|
</p>
|
|
178
239
|
|
|
179
|
-
<
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
</
|
|
240
|
+
<pre><code>app.use(
|
|
241
|
+
HiSecure.middleware({
|
|
242
|
+
cors: {
|
|
243
|
+
origin: "*",
|
|
244
|
+
methods: ["GET"]
|
|
245
|
+
}
|
|
246
|
+
})
|
|
247
|
+
);
|
|
248
|
+
</code></pre>
|
|
188
249
|
|
|
189
|
-
<
|
|
190
|
-
Security without complexity.<br/>
|
|
191
|
-
One dependency — complete Express protection.
|
|
192
|
-
</strong></p>
|
|
250
|
+
<hr/>
|
|
193
251
|
|
|
194
|
-
<
|
|
252
|
+
<h2> Route-Level Security (Advanced & Real-World Usage)</h2>
|
|
195
253
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
254
|
+
<p>
|
|
255
|
+
HiSecure supports fine-grained security control at the route level.
|
|
256
|
+
Each capability can be configured independently without affecting global middleware.
|
|
257
|
+
</p>
|
|
199
258
|
|
|
200
|
-
<
|
|
259
|
+
<p>
|
|
260
|
+
This allows you to apply strict security where needed (auth, payments, admin)
|
|
261
|
+
and relaxed rules for public or internal endpoints.
|
|
262
|
+
</p>
|
|
201
263
|
|
|
202
|
-
<
|
|
264
|
+
<hr/>
|
|
203
265
|
|
|
204
|
-
<
|
|
266
|
+
<h3>Custom CORS (Deep Control)</h3>
|
|
205
267
|
|
|
206
|
-
<
|
|
207
|
-
|
|
268
|
+
<p>
|
|
269
|
+
Route-level CORS is useful when different consumers access different endpoints
|
|
270
|
+
(e.g. web app, admin panel, third-party services).
|
|
271
|
+
</p>
|
|
208
272
|
|
|
209
|
-
<strong>
|
|
210
|
-
<pre><code>const express = require('express');
|
|
211
|
-
const { HiSecure } = require('hi-secure');
|
|
273
|
+
<p><strong>Example: Webhook endpoint (single trusted origin)</strong></p>
|
|
212
274
|
|
|
213
|
-
|
|
275
|
+
<pre><code>router.post(
|
|
276
|
+
"/webhook",
|
|
277
|
+
HiSecure.cors({
|
|
278
|
+
origin: ["https://trusted-client.com"],
|
|
279
|
+
methods: ["POST"],
|
|
280
|
+
allowedHeaders: ["Content-Type", "Authorization"],
|
|
281
|
+
credentials: true
|
|
282
|
+
}),
|
|
283
|
+
controller
|
|
284
|
+
);
|
|
285
|
+
</code></pre>
|
|
214
286
|
|
|
215
|
-
|
|
216
|
-
app.use(HiSecure.middleware('api'));
|
|
287
|
+
<p><strong>Example: Admin dashboard with restricted origins</strong></p>
|
|
217
288
|
|
|
218
|
-
|
|
289
|
+
<pre><code>router.get(
|
|
290
|
+
"/admin/stats",
|
|
291
|
+
HiSecure.cors({
|
|
292
|
+
origin: [
|
|
293
|
+
"https://admin.example.com",
|
|
294
|
+
"https://internal.example.com"
|
|
295
|
+
],
|
|
296
|
+
credentials: true
|
|
297
|
+
}),
|
|
298
|
+
controller
|
|
299
|
+
);
|
|
219
300
|
</code></pre>
|
|
220
301
|
|
|
221
|
-
<p><
|
|
302
|
+
<p><strong>Example: Public API with open read access</strong></p>
|
|
222
303
|
|
|
223
|
-
<
|
|
224
|
-
|
|
304
|
+
<pre><code>router.get(
|
|
305
|
+
"/public/feed",
|
|
306
|
+
HiSecure.cors({ origin: "*" }),
|
|
307
|
+
controller
|
|
308
|
+
);
|
|
309
|
+
</code></pre>
|
|
225
310
|
|
|
226
|
-
<
|
|
311
|
+
<hr/>
|
|
227
312
|
|
|
228
|
-
<h3>
|
|
313
|
+
<h3>Validation (Schema vs Rules — When to Use What)</h3>
|
|
229
314
|
|
|
230
|
-
<p>
|
|
315
|
+
<p>
|
|
316
|
+
HiSecure automatically detects validation strategy based on input type.
|
|
317
|
+
Choose the style based on complexity and ownership.
|
|
318
|
+
</p>
|
|
231
319
|
|
|
232
|
-
<
|
|
233
|
-
|
|
234
|
-
</
|
|
320
|
+
<ul>
|
|
321
|
+
<li><strong>express-validator</strong> — quick, form-like validation</li>
|
|
322
|
+
<li><strong>Zod</strong> — complex schemas, reuse, shared contracts</li>
|
|
323
|
+
</ul>
|
|
235
324
|
|
|
236
|
-
<
|
|
325
|
+
<h4>express-validator (Rule-Based, Inline)</h4>
|
|
237
326
|
|
|
238
|
-
<
|
|
327
|
+
<pre><code>import { body } from "express-validator";
|
|
239
328
|
|
|
240
|
-
|
|
241
|
-
|
|
329
|
+
router.post(
|
|
330
|
+
"/register",
|
|
242
331
|
HiSecure.validate([
|
|
243
|
-
body("
|
|
244
|
-
|
|
245
|
-
|
|
332
|
+
body("email")
|
|
333
|
+
.notEmpty()
|
|
334
|
+
.isEmail(),
|
|
335
|
+
|
|
336
|
+
body("password")
|
|
337
|
+
.isLength({ min: 6 }),
|
|
338
|
+
|
|
339
|
+
body("role")
|
|
340
|
+
.optional()
|
|
341
|
+
.isIn(["user", "admin"])
|
|
246
342
|
]),
|
|
247
|
-
|
|
343
|
+
controller
|
|
344
|
+
);
|
|
345
|
+
</code></pre>
|
|
346
|
+
|
|
347
|
+
<h4>Zod (Schema-Based, Reusable)</h4>
|
|
348
|
+
|
|
349
|
+
<pre><code>import { z } from "zod";
|
|
350
|
+
|
|
351
|
+
const registerSchema = z.object({
|
|
352
|
+
email: z.string().email(),
|
|
353
|
+
password: z.string().min(6),
|
|
354
|
+
role: z.enum(["user", "admin"]).optional()
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
router.post(
|
|
358
|
+
"/register",
|
|
359
|
+
HiSecure.validate(registerSchema),
|
|
360
|
+
controller
|
|
248
361
|
);
|
|
249
362
|
</code></pre>
|
|
250
363
|
|
|
251
|
-
<
|
|
364
|
+
<p>
|
|
365
|
+
Both approaches produce a unified error response format.
|
|
366
|
+
</p>
|
|
367
|
+
|
|
368
|
+
<hr/>
|
|
369
|
+
|
|
370
|
+
<h3>Sanitization (Trust Boundaries)</h3>
|
|
371
|
+
|
|
372
|
+
<p>
|
|
373
|
+
Sanitization should reflect trust boundaries.
|
|
374
|
+
Not all routes require the same level of strictness.
|
|
375
|
+
</p>
|
|
376
|
+
|
|
377
|
+
<p><strong>User-generated content (allow formatting)</strong></p>
|
|
252
378
|
|
|
253
379
|
<pre><code>router.post(
|
|
254
|
-
|
|
255
|
-
HiSecure.
|
|
256
|
-
|
|
257
|
-
|
|
380
|
+
"/comment",
|
|
381
|
+
HiSecure.sanitize({
|
|
382
|
+
allowedTags: ["b", "i", "strong", "em", "a"],
|
|
383
|
+
allowedAttributes: {
|
|
384
|
+
a: ["href"]
|
|
385
|
+
}
|
|
386
|
+
}),
|
|
387
|
+
controller
|
|
258
388
|
);
|
|
259
389
|
</code></pre>
|
|
260
390
|
|
|
261
|
-
<
|
|
391
|
+
<p><strong>Strict input (no HTML allowed)</strong></p>
|
|
262
392
|
|
|
263
|
-
<pre><code>router.
|
|
264
|
-
|
|
265
|
-
HiSecure.
|
|
266
|
-
|
|
393
|
+
<pre><code>router.post(
|
|
394
|
+
"/feedback",
|
|
395
|
+
HiSecure.sanitize({
|
|
396
|
+
allowedTags: [],
|
|
397
|
+
allowedAttributes: {}
|
|
398
|
+
}),
|
|
399
|
+
controller
|
|
400
|
+
);
|
|
401
|
+
</code></pre>
|
|
402
|
+
|
|
403
|
+
<p><strong>Trusted internal pipeline (disable sanitization)</strong></p>
|
|
404
|
+
|
|
405
|
+
<pre><code>router.post(
|
|
406
|
+
"/internal/import",
|
|
407
|
+
HiSecure.sanitize(false),
|
|
408
|
+
controller
|
|
409
|
+
);
|
|
410
|
+
</code></pre>
|
|
411
|
+
|
|
412
|
+
<hr/>
|
|
413
|
+
|
|
414
|
+
<h3>Full Route-Level Security Composition</h3>
|
|
415
|
+
|
|
416
|
+
<p>
|
|
417
|
+
A real-world admin route combining multiple security layers.
|
|
418
|
+
Execution order is deterministic and isolated to the route.
|
|
419
|
+
</p>
|
|
420
|
+
|
|
421
|
+
<pre><code>router.post(
|
|
422
|
+
"/admin/create-user",
|
|
423
|
+
HiSecure.auth({ roles: ["admin"] }),
|
|
424
|
+
HiSecure.rateLimit({ max: 3, windowMs: 10 * 60 * 1000 }),
|
|
425
|
+
HiSecure.cors({
|
|
426
|
+
origin: ["https://admin.example.com"]
|
|
427
|
+
}),
|
|
428
|
+
HiSecure.sanitize(),
|
|
429
|
+
HiSecure.validate([
|
|
430
|
+
body("email").isEmail(),
|
|
431
|
+
body("password").isLength({ min: 8 })
|
|
432
|
+
]),
|
|
433
|
+
controller
|
|
267
434
|
);
|
|
268
435
|
</code></pre>
|
|
269
436
|
|
|
270
|
-
<br/>
|
|
271
|
-
<hr style="border:0; border-top:2px dashed #d4d4d8; margin:32px 0"/>
|
|
272
437
|
|
|
273
|
-
<h2>📘 Part 3 — JWT Mode (Advanced)</h2>
|
|
274
438
|
|
|
275
|
-
<
|
|
439
|
+
<h2>JWT Mode</h2>
|
|
276
440
|
|
|
277
|
-
<
|
|
441
|
+
<p>
|
|
442
|
+
JWT support is optional. Enable it only if you want authentication features.
|
|
443
|
+
</p>
|
|
278
444
|
|
|
279
445
|
<pre><code>HiSecure.resetInstance();
|
|
280
446
|
|
|
@@ -287,280 +453,292 @@ HiSecure.getInstance({
|
|
|
287
453
|
});
|
|
288
454
|
</code></pre>
|
|
289
455
|
|
|
290
|
-
<
|
|
456
|
+
<hr/>
|
|
291
457
|
|
|
292
|
-
<
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
458
|
+
<h2>Final Authentication Setup</h2>
|
|
459
|
+
|
|
460
|
+
<hr/>
|
|
461
|
+
|
|
462
|
+
<h2>🔐 Final Authentication Setup</h2>
|
|
463
|
+
|
|
464
|
+
<p>
|
|
465
|
+
This section demonstrates a complete, production-ready authentication setup using HiSecure.
|
|
466
|
+
It covers signup, JWT login, Google login, role-based access control, and proper initialization.
|
|
467
|
+
</p>
|
|
301
468
|
|
|
302
|
-
<
|
|
303
|
-
<
|
|
469
|
+
<h3>Features Covered</h3>
|
|
470
|
+
<ul>
|
|
471
|
+
<li>Signup using email and password</li>
|
|
472
|
+
<li>Login using email and password (JWT-based)</li>
|
|
473
|
+
<li>Login with Google (ID token verification)</li>
|
|
474
|
+
<li>Role-based protected routes</li>
|
|
475
|
+
<li>Optional authentication support</li>
|
|
476
|
+
<li>Correct HiSecure bootstrap with reset rules</li>
|
|
477
|
+
</ul>
|
|
304
478
|
|
|
305
|
-
<
|
|
479
|
+
<hr/>
|
|
306
480
|
|
|
307
|
-
<
|
|
481
|
+
<h3>Application Bootstrap (server.js / app.js)</h3>
|
|
308
482
|
|
|
309
|
-
<pre><code
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
const { HiSecure } = require("hi-secure");
|
|
483
|
+
<pre><code>import express from "express";
|
|
484
|
+
import dotenv from "dotenv";
|
|
485
|
+
import { HiSecure } from "hi-secure";
|
|
486
|
+
import authRoutes from "./routes/auth.routes.js";
|
|
314
487
|
|
|
315
|
-
|
|
316
|
-
const PORT = process.env.PORT || 3000;
|
|
488
|
+
dotenv.config();
|
|
317
489
|
|
|
318
|
-
|
|
490
|
+
const app = express();
|
|
319
491
|
|
|
320
|
-
// ⭐ FORCE NEW INSTANCE WITH CORRECT CONFIG - if use HiSecure.jwt()
|
|
321
492
|
HiSecure.resetInstance();
|
|
322
493
|
|
|
323
494
|
HiSecure.getInstance({
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
495
|
+
auth: {
|
|
496
|
+
enabled: true,
|
|
497
|
+
jwtSecret: process.env.JWT_SECRET || "supersecret_32_chars_minimum",
|
|
498
|
+
jwtExpiresIn: "1d",
|
|
499
|
+
googleClientId: process.env.GOOGLE_CLIENT_ID
|
|
500
|
+
}
|
|
329
501
|
});
|
|
330
502
|
|
|
331
|
-
|
|
332
|
-
app.use(HiSecure.middleware('api')); // one line setup - along with this u use the HiSecure.validat() and HiSecure.hash() | HiSecure.verify()
|
|
333
|
-
|
|
334
|
-
// Global middleware WITHOUT auth override
|
|
335
|
-
app.use(
|
|
336
|
-
HiSecure.middleware({
|
|
337
|
-
cors: true,
|
|
338
|
-
rateLimit: "strict",
|
|
339
|
-
sanitize: true,
|
|
340
|
-
headers: true,
|
|
341
|
-
compression: true,
|
|
342
|
-
json: true
|
|
343
|
-
})
|
|
344
|
-
);
|
|
503
|
+
app.use(HiSecure.middleware("api"));
|
|
345
504
|
|
|
346
|
-
|
|
347
|
-
const userRoutes = require("./routes/UserRoutes");
|
|
348
|
-
app.use("/api/auth", userRoutes());
|
|
505
|
+
app.use("/auth", authRoutes);
|
|
349
506
|
|
|
350
|
-
app.listen(
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
507
|
+
app.listen(3000);
|
|
508
|
+
</code></pre>
|
|
509
|
+
|
|
510
|
+
<p>
|
|
511
|
+
<em>Note:</em> <code>resetInstance()</code> is recommended only for tests or starter templates.
|
|
512
|
+
It should not be used repeatedly in production runtime.
|
|
513
|
+
</p>
|
|
514
|
+
|
|
515
|
+
<hr/>
|
|
516
|
+
|
|
517
|
+
<h3>Authentication Routes</h3>
|
|
518
|
+
|
|
519
|
+
<pre><code>import { Router } from "express";
|
|
520
|
+
import {
|
|
521
|
+
signup,
|
|
522
|
+
loginWithJwt,
|
|
523
|
+
loginWithGoogle
|
|
524
|
+
} from "../controllers/auth.controller.js";
|
|
525
|
+
import { HiSecure } from "hi-secure";
|
|
526
|
+
|
|
527
|
+
const router = Router();
|
|
528
|
+
|
|
529
|
+
router.post("/signup", signup);
|
|
530
|
+
router.post("/login", loginWithJwt);
|
|
531
|
+
router.post("/google", loginWithGoogle);
|
|
532
|
+
|
|
533
|
+
router.get(
|
|
534
|
+
"/me",
|
|
535
|
+
HiSecure.auth(),
|
|
536
|
+
(req, res) => res.json({ user: req.user })
|
|
537
|
+
);
|
|
538
|
+
|
|
539
|
+
export default router;
|
|
354
540
|
</code></pre>
|
|
355
541
|
|
|
542
|
+
<hr/>
|
|
356
543
|
|
|
357
|
-
<
|
|
358
|
-
const { HiSecure } = require('hi-secure');
|
|
359
|
-
const User = require("../models/User");
|
|
544
|
+
<h3>Authentication Controllers</h3>
|
|
360
545
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
546
|
+
<h4>Signup (Email and Password)</h4>
|
|
547
|
+
|
|
548
|
+
<pre><code>import { HiSecure } from "hi-secure";
|
|
549
|
+
import { HttpError } from "../core/errors/HttpError.js";
|
|
550
|
+
import User from "../models/User.js";
|
|
551
|
+
|
|
552
|
+
export const signup = async (req, res, next) => {
|
|
553
|
+
try {
|
|
554
|
+
const { email, password, name } = req.body;
|
|
367
555
|
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
const { name, email, password } = req.body;
|
|
371
|
-
|
|
372
|
-
// Check if user exists
|
|
373
|
-
const existingUser = await User.findOne({ email });
|
|
374
|
-
if (existingUser) {
|
|
375
|
-
return res.status(400).json({
|
|
376
|
-
error: 'User already exists'
|
|
377
|
-
});
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
// Hash password
|
|
381
|
-
const hashedPassword = await HiSecure.hash(password);
|
|
382
|
-
|
|
383
|
-
// Create user
|
|
384
|
-
const user = await User.create({
|
|
385
|
-
name,
|
|
386
|
-
email,
|
|
387
|
-
password: hashedPassword
|
|
388
|
-
});
|
|
389
|
-
|
|
390
|
-
// FIXED: JWT sign with ALL required options
|
|
391
|
-
const token = HiSecure.jwt.sign({
|
|
392
|
-
userId: user._id.toString(),
|
|
393
|
-
email: user.email,
|
|
394
|
-
name: user.name,
|
|
395
|
-
role: 'user'
|
|
396
|
-
},
|
|
397
|
-
JWT_OPTIONS
|
|
398
|
-
);
|
|
399
|
-
|
|
400
|
-
res.status(201).json({
|
|
401
|
-
message: 'User registered successfully',
|
|
402
|
-
token,
|
|
403
|
-
user: {
|
|
404
|
-
id: user._id,
|
|
405
|
-
name: user.name,
|
|
406
|
-
email: user.email
|
|
407
|
-
}
|
|
408
|
-
});
|
|
409
|
-
|
|
410
|
-
} catch (error) {
|
|
411
|
-
console.error('Registration error:', error);
|
|
412
|
-
res.status(500).json({
|
|
413
|
-
error: 'Registration failed',
|
|
414
|
-
details: error.message
|
|
415
|
-
});
|
|
556
|
+
if (!email || !password) {
|
|
557
|
+
throw HttpError.BadRequest("Email and password required");
|
|
416
558
|
}
|
|
417
|
-
};
|
|
418
559
|
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
// Find user
|
|
424
|
-
const user = await User.findOne({ email });
|
|
425
|
-
if (!user) {
|
|
426
|
-
return res.status(401).json({
|
|
427
|
-
error: 'Invalid credentials'
|
|
428
|
-
});
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
// Verify password
|
|
432
|
-
const isValid = await HiSecure.verify(password, user.password);
|
|
433
|
-
if (!isValid) {
|
|
434
|
-
return res.status(401).json({
|
|
435
|
-
error: 'Invalid credentials'
|
|
436
|
-
});
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
// FIXED: Same JWT options
|
|
440
|
-
const token = HiSecure.jwt.sign({
|
|
441
|
-
userId: user._id.toString(),
|
|
442
|
-
email: user.email,
|
|
443
|
-
name: user.name,
|
|
444
|
-
role: 'user'
|
|
445
|
-
},
|
|
446
|
-
JWT_OPTIONS
|
|
447
|
-
);
|
|
448
|
-
|
|
449
|
-
res.json({
|
|
450
|
-
message: 'Login successful',
|
|
451
|
-
token,
|
|
452
|
-
user: {
|
|
453
|
-
id: user._id,
|
|
454
|
-
name: user.name,
|
|
455
|
-
email: user.email
|
|
456
|
-
}
|
|
457
|
-
});
|
|
458
|
-
|
|
459
|
-
} catch (error) {
|
|
460
|
-
console.error('Login error:', error);
|
|
461
|
-
res.status(500).json({
|
|
462
|
-
error: 'Login failed',
|
|
463
|
-
details: error.message
|
|
464
|
-
});
|
|
560
|
+
const existing = await User.findOne({ email });
|
|
561
|
+
if (existing) {
|
|
562
|
+
throw HttpError.Conflict("User already exists");
|
|
465
563
|
}
|
|
564
|
+
|
|
565
|
+
const passwordHash = await HiSecure.hash(password);
|
|
566
|
+
|
|
567
|
+
const user = await User.create({
|
|
568
|
+
email,
|
|
569
|
+
name,
|
|
570
|
+
passwordHash,
|
|
571
|
+
roles: ["user"],
|
|
572
|
+
provider: "local"
|
|
573
|
+
});
|
|
574
|
+
|
|
575
|
+
const token = HiSecure.jwt.sign({
|
|
576
|
+
userId: user.id,
|
|
577
|
+
roles: user.roles
|
|
578
|
+
});
|
|
579
|
+
|
|
580
|
+
res.status(201).json({ token, user });
|
|
581
|
+
} catch (err) {
|
|
582
|
+
next(err);
|
|
583
|
+
}
|
|
466
584
|
};
|
|
585
|
+
</code></pre>
|
|
467
586
|
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
res.json({
|
|
480
|
-
message: 'Profile data',
|
|
481
|
-
user
|
|
482
|
-
});
|
|
483
|
-
} catch (error) {
|
|
484
|
-
console.error('Profile error:', error);
|
|
485
|
-
res.status(500).json({
|
|
486
|
-
error: 'Failed to fetch profile',
|
|
487
|
-
details: error.message
|
|
488
|
-
});
|
|
587
|
+
<hr/>
|
|
588
|
+
|
|
589
|
+
<h4>Login (Email and Password)</h4>
|
|
590
|
+
|
|
591
|
+
<pre><code>export const loginWithJwt = async (req, res, next) => {
|
|
592
|
+
try {
|
|
593
|
+
const { email, password } = req.body;
|
|
594
|
+
|
|
595
|
+
const user = await User.findOne({ email });
|
|
596
|
+
if (!user || !user.passwordHash) {
|
|
597
|
+
throw HttpError.Unauthorized("Invalid credentials");
|
|
489
598
|
}
|
|
599
|
+
|
|
600
|
+
const isValid = await HiSecure.verify(password, user.passwordHash);
|
|
601
|
+
if (!isValid) {
|
|
602
|
+
throw HttpError.Unauthorized("Invalid credentials");
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
const token = HiSecure.jwt.sign({
|
|
606
|
+
userId: user.id,
|
|
607
|
+
roles: user.roles
|
|
608
|
+
});
|
|
609
|
+
|
|
610
|
+
res.json({ token, user });
|
|
611
|
+
} catch (err) {
|
|
612
|
+
next(err);
|
|
613
|
+
}
|
|
490
614
|
};
|
|
491
615
|
</code></pre>
|
|
492
616
|
|
|
617
|
+
<hr/>
|
|
493
618
|
|
|
494
|
-
<
|
|
495
|
-
const express = require('express');
|
|
496
|
-
const { body } = require('express-validator');
|
|
497
|
-
const { HiSecure } = require('hi-secure');
|
|
498
|
-
const { registerUser, loginUser, getProfile } = require('../controllers/UserControllers');
|
|
499
|
-
|
|
619
|
+
<h4>Login with Google</h4>
|
|
500
620
|
|
|
621
|
+
<pre><code>export const loginWithGoogle = async (req, res, next) => {
|
|
622
|
+
try {
|
|
623
|
+
const { idToken } = req.body;
|
|
624
|
+
if (!idToken) {
|
|
625
|
+
throw HttpError.BadRequest("Google idToken required");
|
|
626
|
+
}
|
|
501
627
|
|
|
628
|
+
const googleUser = await HiSecure.jwt.google.verifyIdToken(idToken);
|
|
502
629
|
|
|
503
|
-
|
|
504
|
-
|
|
630
|
+
if (!googleUser.email_verified) {
|
|
631
|
+
throw HttpError.Unauthorized("Google email not verified");
|
|
632
|
+
}
|
|
505
633
|
|
|
506
|
-
|
|
507
|
-
'/register',
|
|
634
|
+
let user = await User.findOne({ email: googleUser.email });
|
|
508
635
|
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
636
|
+
if (!user) {
|
|
637
|
+
user = await User.create({
|
|
638
|
+
email: googleUser.email,
|
|
639
|
+
name: googleUser.name,
|
|
640
|
+
provider: "google",
|
|
641
|
+
providerId: googleUser.sub,
|
|
642
|
+
roles: ["user"]
|
|
643
|
+
});
|
|
644
|
+
}
|
|
513
645
|
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
646
|
+
const token = HiSecure.jwt.sign({
|
|
647
|
+
userId: user.id,
|
|
648
|
+
roles: user.roles
|
|
649
|
+
});
|
|
517
650
|
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
651
|
+
res.json({ token, user });
|
|
652
|
+
} catch (err) {
|
|
653
|
+
next(err);
|
|
654
|
+
}
|
|
655
|
+
};
|
|
656
|
+
</code></pre>
|
|
522
657
|
|
|
523
|
-
|
|
524
|
-
);
|
|
658
|
+
<hr/>
|
|
525
659
|
|
|
526
|
-
|
|
527
|
-
router.post(
|
|
528
|
-
'/login',
|
|
660
|
+
<h3>Role-Based Protected Routes</h3>
|
|
529
661
|
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
662
|
+
<pre><code>app.get(
|
|
663
|
+
"/admin",
|
|
664
|
+
HiSecure.auth({ roles: ["admin"] }),
|
|
665
|
+
(req, res) => {
|
|
666
|
+
res.json({ message: "Welcome Admin" });
|
|
667
|
+
}
|
|
668
|
+
);
|
|
669
|
+
</code></pre>
|
|
534
670
|
|
|
535
|
-
|
|
536
|
-
.notEmpty().withMessage("Password is required")
|
|
537
|
-
]),
|
|
671
|
+
<hr/>
|
|
538
672
|
|
|
539
|
-
|
|
540
|
-
HiSecure.rateLimit({ max: 5, windowMs: 15 * 60 * 1000 }),
|
|
673
|
+
<h3>JWT Options (Optional)</h3>
|
|
541
674
|
|
|
542
|
-
|
|
543
|
-
|
|
675
|
+
<p>
|
|
676
|
+
HiSecure does not require JWT options for most use cases.
|
|
677
|
+
Default configuration provided during initialization is sufficient.
|
|
678
|
+
</p>
|
|
544
679
|
|
|
680
|
+
<pre><code>HiSecure.getInstance({
|
|
681
|
+
auth: {
|
|
682
|
+
enabled: true,
|
|
683
|
+
jwtSecret: process.env.JWT_SECRET,
|
|
684
|
+
jwtExpiresIn: "1d"
|
|
685
|
+
}
|
|
686
|
+
});
|
|
687
|
+
</code></pre>
|
|
545
688
|
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
getProfile
|
|
550
|
-
);
|
|
689
|
+
<p>
|
|
690
|
+
Advanced JWT options can be provided only when needed:
|
|
691
|
+
</p>
|
|
551
692
|
|
|
552
|
-
|
|
553
|
-
|
|
693
|
+
<pre><code>HiSecure.jwt.sign(
|
|
694
|
+
{
|
|
695
|
+
userId: user.id,
|
|
696
|
+
roles: user.roles
|
|
697
|
+
},
|
|
698
|
+
{
|
|
699
|
+
issuer: "my-app",
|
|
700
|
+
audience: ["web", "mobile"],
|
|
701
|
+
subject: "user-auth",
|
|
702
|
+
expiresIn: "7d"
|
|
703
|
+
}
|
|
704
|
+
);
|
|
554
705
|
</code></pre>
|
|
555
706
|
|
|
556
|
-
<
|
|
557
|
-
|
|
707
|
+
<p>
|
|
708
|
+
JWT options are optional and intended for advanced authentication scenarios.
|
|
709
|
+
</p>
|
|
710
|
+
|
|
711
|
+
<hr/>
|
|
558
712
|
|
|
559
|
-
<
|
|
713
|
+
<h3>Rules to Remember</h3>
|
|
714
|
+
|
|
715
|
+
<ul>
|
|
716
|
+
<li>Initialize HiSecure once during application startup</li>
|
|
717
|
+
<li>Use resetInstance only for tests or starter templates</li>
|
|
718
|
+
<li>Do not initialize HiSecure inside controllers</li>
|
|
719
|
+
<li>Google login is used for identity verification only</li>
|
|
720
|
+
<li>Authorization is enforced using JWT payload and roles</li>
|
|
721
|
+
</ul>
|
|
722
|
+
|
|
723
|
+
<hr/>
|
|
724
|
+
|
|
725
|
+
|
|
726
|
+
<h2>Summary</h2>
|
|
727
|
+
|
|
728
|
+
<p>
|
|
729
|
+
HiSecure provides a complete, opinionated security layer for Express.
|
|
730
|
+
It focuses on correctness, safety and developer productivity.
|
|
731
|
+
</p>
|
|
560
732
|
|
|
561
733
|
<p align="center">
|
|
562
|
-
|
|
563
|
-
<strong>Advanced patterns, RBAC examples, custom adapters, deployment setups & best practices.</strong>
|
|
734
|
+
<strong>One dependency. One middleware. Complete security.</strong>
|
|
564
735
|
</p>
|
|
565
736
|
|
|
566
|
-
<
|
|
737
|
+
<hr/>
|
|
738
|
+
|
|
739
|
+
<h2 align="center">Additional Documentation</h2>
|
|
740
|
+
|
|
741
|
+
<p align="center">
|
|
742
|
+
Advanced patterns, RBAC strategies, adapter extensions and deployment guides
|
|
743
|
+
will be added over time.
|
|
744
|
+
</p>
|