@naman_deep_singh/security 1.1.0 โ 1.3.0
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 +358 -175
- package/dist/cjs/core/crypto/cryptoManager.d.ts +111 -0
- package/dist/cjs/core/crypto/cryptoManager.js +185 -0
- package/dist/cjs/core/crypto/index.d.ts +5 -4
- package/dist/cjs/core/crypto/index.js +12 -4
- package/dist/cjs/core/jwt/extractToken.d.ts +2 -2
- package/dist/cjs/core/jwt/extractToken.js +12 -7
- package/dist/cjs/core/jwt/generateTokens.d.ts +3 -6
- package/dist/cjs/core/jwt/generateTokens.js +10 -3
- package/dist/cjs/core/jwt/index.d.ts +1 -0
- package/dist/cjs/core/jwt/index.js +1 -0
- package/dist/cjs/core/jwt/jwtManager.d.ts +66 -0
- package/dist/cjs/core/jwt/jwtManager.js +319 -0
- package/dist/cjs/core/jwt/signToken.d.ts +1 -1
- package/dist/cjs/core/jwt/types.d.ts +22 -0
- package/dist/cjs/core/jwt/types.js +2 -0
- package/dist/cjs/core/jwt/validateToken.d.ts +1 -1
- package/dist/cjs/core/jwt/verify.d.ts +12 -7
- package/dist/cjs/core/jwt/verify.js +23 -3
- package/dist/cjs/core/password/passwordManager.d.ts +29 -0
- package/dist/cjs/core/password/passwordManager.js +242 -0
- package/dist/cjs/index.d.ts +11 -9
- package/dist/cjs/interfaces/jwt.interface.d.ts +47 -0
- package/dist/cjs/interfaces/jwt.interface.js +2 -0
- package/dist/cjs/interfaces/password.interface.d.ts +60 -0
- package/dist/cjs/interfaces/password.interface.js +2 -0
- package/dist/esm/core/crypto/cryptoManager.d.ts +111 -0
- package/dist/esm/core/crypto/cryptoManager.js +180 -0
- package/dist/esm/core/crypto/index.d.ts +5 -4
- package/dist/esm/core/crypto/index.js +5 -4
- package/dist/esm/core/jwt/extractToken.d.ts +2 -2
- package/dist/esm/core/jwt/extractToken.js +12 -7
- package/dist/esm/core/jwt/generateTokens.d.ts +3 -6
- package/dist/esm/core/jwt/generateTokens.js +10 -3
- package/dist/esm/core/jwt/index.d.ts +1 -0
- package/dist/esm/core/jwt/index.js +1 -0
- package/dist/esm/core/jwt/jwtManager.d.ts +66 -0
- package/dist/esm/core/jwt/jwtManager.js +312 -0
- package/dist/esm/core/jwt/signToken.d.ts +1 -1
- package/dist/esm/core/jwt/types.d.ts +22 -0
- package/dist/esm/core/jwt/types.js +1 -0
- package/dist/esm/core/jwt/validateToken.d.ts +1 -1
- package/dist/esm/core/jwt/verify.d.ts +12 -7
- package/dist/esm/core/jwt/verify.js +20 -2
- package/dist/esm/core/password/passwordManager.d.ts +29 -0
- package/dist/esm/core/password/passwordManager.js +235 -0
- package/dist/esm/index.d.ts +11 -9
- package/dist/esm/interfaces/jwt.interface.d.ts +47 -0
- package/dist/esm/interfaces/jwt.interface.js +1 -0
- package/dist/esm/interfaces/password.interface.d.ts +60 -0
- package/dist/esm/interfaces/password.interface.js +1 -0
- package/dist/types/core/crypto/cryptoManager.d.ts +111 -0
- package/dist/types/core/crypto/index.d.ts +5 -4
- package/dist/types/core/jwt/extractToken.d.ts +2 -2
- package/dist/types/core/jwt/generateTokens.d.ts +3 -6
- package/dist/types/core/jwt/index.d.ts +1 -0
- package/dist/types/core/jwt/jwtManager.d.ts +66 -0
- package/dist/types/core/jwt/signToken.d.ts +1 -1
- package/dist/types/core/jwt/types.d.ts +22 -0
- package/dist/types/core/jwt/validateToken.d.ts +1 -1
- package/dist/types/core/jwt/verify.d.ts +12 -7
- package/dist/types/core/password/passwordManager.d.ts +29 -0
- package/dist/types/index.d.ts +11 -9
- package/dist/types/interfaces/jwt.interface.d.ts +47 -0
- package/dist/types/interfaces/password.interface.d.ts +60 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,105 +1,75 @@
|
|
|
1
1
|
# @naman_deep_singh/security
|
|
2
2
|
|
|
3
|
-
**Version:** 1.
|
|
3
|
+
**Version:** 1.3.0
|
|
4
4
|
|
|
5
5
|
A complete, lightweight security toolkit for Node.js & TypeScript providing:
|
|
6
6
|
|
|
7
|
-
๐ **Password hashing & validation** with bcrypt
|
|
8
|
-
๐ **JWT signing & verification** (no deprecated expiresIn)
|
|
7
|
+
๐ **Password hashing & validation** with bcrypt (async/sync, peppered variants)
|
|
8
|
+
๐ **JWT signing & verification** (no deprecated expiresIn, with caching)
|
|
9
9
|
๐งฎ **Duration parser** ("15m", "7d", etc.)
|
|
10
|
-
๐ชช **Token generator** (access + refresh pair)
|
|
10
|
+
๐ชช **Token generator** (access + refresh pair with branded types)
|
|
11
11
|
โป๏ธ **Refresh token rotation** helper
|
|
12
12
|
๐งฐ **Robust token extraction** (Headers, Cookies, Query, Body, WebSocket)
|
|
13
13
|
๐งฉ **Safe & strict JWT decode** utilities
|
|
14
|
+
๐ **AES-256-GCM encryption/decryption** with HMAC and random utilities
|
|
14
15
|
๐จ **Standardized error handling** with @naman_deep_singh/errors-utils
|
|
16
|
+
|
|
15
17
|
โ **Fully typed** with TypeScript
|
|
18
|
+
โ **Branded token types** for compile-time safety (AccessToken/RefreshToken)
|
|
19
|
+
โ **Class-based managers** for advanced features (PasswordManager, JWTManager, CryptoManager)
|
|
20
|
+
โ **Functional exports** for simple use cases
|
|
21
|
+
โ **Password strength checking** and validation
|
|
22
|
+
โ **Token caching** for performance
|
|
16
23
|
โ **Consistent errors** across your application ecosystem
|
|
17
24
|
โ **Works in both ESM and CommonJS**
|
|
18
25
|
|
|
19
26
|
```bash
|
|
20
|
-
|
|
21
27
|
๐ฆ Installation
|
|
22
28
|
npm install @naman_deep_singh/security
|
|
29
|
+
```
|
|
23
30
|
|
|
24
31
|
๐ง Features
|
|
25
32
|
|
|
26
33
|
๐ฅ Password Hashing โ secure & async (bcrypt with 10 salt rounds)
|
|
34
|
+
๐ฅ Password Validation & Strength Checking
|
|
35
|
+
๐ฅ Password Generation with configurable requirements
|
|
36
|
+
๐ฅ Peppered hashing variants
|
|
37
|
+
๐ฅ Synchronous & asynchronous versions
|
|
27
38
|
|
|
28
39
|
๐ฅ Custom Expiry JWT โ manual exp support using duration strings
|
|
29
|
-
|
|
30
40
|
๐ฅ Token Pair Generation (accessToken + refreshToken)
|
|
31
|
-
|
|
32
41
|
๐ฅ Refresh Token Rotation
|
|
33
|
-
|
|
34
42
|
๐ฅ Safe & Unsafe JWT Verification
|
|
35
|
-
|
|
36
43
|
๐ฅ Strict vs Flexible Decoding
|
|
37
|
-
|
|
38
44
|
๐ฅ Universal Token Extraction (Headers, Cookies, Query, Body, WebSocket)
|
|
45
|
+
๐ฅ Token caching for performance
|
|
39
46
|
|
|
40
|
-
๐ฅ
|
|
47
|
+
๐ฅ AES-256-GCM Encryption/Decryption
|
|
48
|
+
๐ฅ HMAC signing and verification
|
|
49
|
+
๐ฅ Cryptographically secure random generation
|
|
41
50
|
|
|
42
|
-
๐ฅ Production-grade types
|
|
51
|
+
๐ฅ Production-grade types and error handling
|
|
43
52
|
|
|
44
53
|
๐ Quick Start
|
|
54
|
+
|
|
55
|
+
### Functional Approach (Simple)
|
|
56
|
+
```typescript
|
|
45
57
|
import {
|
|
46
58
|
hashPassword,
|
|
47
59
|
verifyPassword,
|
|
48
60
|
generateTokens,
|
|
49
61
|
verifyToken,
|
|
50
62
|
safeVerifyToken,
|
|
51
|
-
extractToken
|
|
63
|
+
extractToken,
|
|
64
|
+
encrypt,
|
|
65
|
+
decrypt
|
|
52
66
|
} from "@naman_deep_singh/security";
|
|
53
67
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
Below is a complete reference with full usage examples.
|
|
57
|
-
|
|
58
|
-
๐ง 1. Password Utilities
|
|
59
|
-
hashPassword(password: string): Promise<string>
|
|
68
|
+
// Password operations
|
|
60
69
|
const hashed = await hashPassword("mypassword");
|
|
61
|
-
console.log(hashed); // $2a$10$...
|
|
62
|
-
|
|
63
|
-
verifyPassword(password: string, hash: string): Promise<boolean>
|
|
64
70
|
const isValid = await verifyPassword("mypassword", hashed);
|
|
65
|
-
if (isValid) console.log("Correct password");
|
|
66
|
-
|
|
67
|
-
comparePassword()
|
|
68
|
-
|
|
69
|
-
Alias for backward compatibility.
|
|
70
|
-
|
|
71
|
-
๐ 2. JWT Signing
|
|
72
|
-
signToken(payload, secret, expiresIn, options)
|
|
73
|
-
|
|
74
|
-
Creates a JWT with custom exp logic ("15m", "1h", "7d")
|
|
75
|
-
|
|
76
|
-
const token = signToken(
|
|
77
|
-
{ userId: 1 },
|
|
78
|
-
process.env.JWT_SECRET!,
|
|
79
|
-
"1h"
|
|
80
|
-
);
|
|
81
|
-
|
|
82
|
-
console.log(token);
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
โ No deprecated expiresIn from jsonwebtoken
|
|
86
|
-
โ Expiration is injected manually via exp
|
|
87
|
-
|
|
88
|
-
๐งฎ 3. parseDuration()
|
|
89
|
-
|
|
90
|
-
Parses duration strings into seconds.
|
|
91
|
-
|
|
92
|
-
parseDuration("15m"); // 900
|
|
93
|
-
parseDuration("2h"); // 7200
|
|
94
|
-
parseDuration("7d"); // 604800
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
Useful for token expiry, cache expiry, rate limiting, etc.
|
|
98
|
-
|
|
99
|
-
๐ชช 4. generateTokens()
|
|
100
|
-
|
|
101
|
-
Generates access + refresh token pair.
|
|
102
71
|
|
|
72
|
+
// JWT operations
|
|
103
73
|
const tokens = generateTokens(
|
|
104
74
|
{ userId: 42 },
|
|
105
75
|
process.env.ACCESS_SECRET!,
|
|
@@ -108,168 +78,276 @@ const tokens = generateTokens(
|
|
|
108
78
|
"7d"
|
|
109
79
|
);
|
|
110
80
|
|
|
111
|
-
|
|
112
|
-
console.log(tokens.refreshToken);
|
|
81
|
+
const result = safeVerifyToken(tokens.accessToken, process.env.ACCESS_SECRET!);
|
|
113
82
|
|
|
114
|
-
|
|
83
|
+
// Crypto operations
|
|
84
|
+
const encrypted = encrypt("sensitive data", "secret-key");
|
|
85
|
+
const decrypted = decrypt(encrypted, "secret-key");
|
|
86
|
+
```
|
|
115
87
|
|
|
116
|
-
|
|
88
|
+
### Class-Based Approach (Advanced)
|
|
89
|
+
```typescript
|
|
90
|
+
import { PasswordManager, JWTManager, CryptoManager } from "@naman_deep_singh/security";
|
|
91
|
+
|
|
92
|
+
// Password Manager with validation
|
|
93
|
+
const passwordManager = new PasswordManager({
|
|
94
|
+
minLength: 12,
|
|
95
|
+
requireUppercase: true,
|
|
96
|
+
requireNumbers: true,
|
|
97
|
+
requireSpecialChars: true
|
|
98
|
+
});
|
|
117
99
|
|
|
118
|
-
|
|
100
|
+
const validation = passwordManager.validate("MySecurePass123!");
|
|
101
|
+
if (validation.isValid) {
|
|
102
|
+
const hashed = await passwordManager.hash("MySecurePass123!");
|
|
103
|
+
}
|
|
119
104
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
process.env.
|
|
123
|
-
|
|
105
|
+
// JWT Manager with caching
|
|
106
|
+
const jwtManager = new JWTManager({
|
|
107
|
+
accessSecret: process.env.ACCESS_SECRET!,
|
|
108
|
+
refreshSecret: process.env.REFRESH_SECRET!,
|
|
109
|
+
accessExpiry: "15m",
|
|
110
|
+
refreshExpiry: "7d",
|
|
111
|
+
enableCaching: true
|
|
112
|
+
});
|
|
124
113
|
|
|
114
|
+
const tokens = await jwtManager.generateTokens({ userId: 42 });
|
|
115
|
+
const payload = await jwtManager.verifyAccessToken(tokens.accessToken);
|
|
125
116
|
|
|
126
|
-
|
|
127
|
-
|
|
117
|
+
// Crypto Manager
|
|
118
|
+
const cryptoManager = new CryptoManager("your-secret-key");
|
|
119
|
+
const encrypted = cryptoManager.encrypt("data");
|
|
120
|
+
const decrypted = cryptoManager.decrypt(encrypted);
|
|
121
|
+
```
|
|
128
122
|
|
|
129
|
-
|
|
123
|
+
๐ API Documentation
|
|
130
124
|
|
|
131
|
-
|
|
125
|
+
Below is a complete reference with full usage examples.
|
|
132
126
|
|
|
133
|
-
|
|
134
|
-
const payload = verifyToken(token, process.env.ACCESS_SECRET!);
|
|
135
|
-
console.log("User authenticated:", payload);
|
|
136
|
-
} catch (err) {
|
|
137
|
-
console.error("Invalid or expired token");
|
|
138
|
-
}
|
|
127
|
+
## ๐ง 1. Password Utilities
|
|
139
128
|
|
|
140
|
-
|
|
129
|
+
### Functional Exports
|
|
130
|
+
```typescript
|
|
131
|
+
// Async hashing
|
|
132
|
+
const hashed = await hashPassword("mypassword"); // Uses 10 salt rounds by default
|
|
133
|
+
const hashed = await hashPassword("mypassword", 12); // Custom salt rounds
|
|
141
134
|
|
|
142
|
-
|
|
135
|
+
// Sync hashing
|
|
136
|
+
const hashedSync = hashPasswordSync("mypassword");
|
|
137
|
+
const hashedSync = hashPasswordSync("mypassword", 12);
|
|
143
138
|
|
|
144
|
-
|
|
139
|
+
// Peppered variants
|
|
140
|
+
const hashedPeppered = await hashPasswordWithPepper("mypassword", "pepper");
|
|
141
|
+
const hashedPepperedSync = hashPasswordWithPepperSync("mypassword", "pepper");
|
|
145
142
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
143
|
+
// Verification
|
|
144
|
+
const isValid = await verifyPassword("mypassword", hashed);
|
|
145
|
+
const isValidSync = verifyPasswordSync("mypassword", hashed);
|
|
146
|
+
|
|
147
|
+
// Peppered verification
|
|
148
|
+
const isValidPeppered = await verifyPasswordWithPepper("mypassword", "pepper", hashed);
|
|
149
|
+
const isValidPepperedSync = verifyPasswordWithPepperSync("mypassword", "pepper", hashed);
|
|
150
|
+
```
|
|
151
151
|
|
|
152
|
-
|
|
153
|
-
|
|
152
|
+
### PasswordManager Class
|
|
153
|
+
```typescript
|
|
154
|
+
const passwordManager = new PasswordManager({
|
|
155
|
+
saltRounds: 12,
|
|
156
|
+
minLength: 8,
|
|
157
|
+
maxLength: 128,
|
|
158
|
+
requireUppercase: true,
|
|
159
|
+
requireLowercase: true,
|
|
160
|
+
requireNumbers: true,
|
|
161
|
+
requireSpecialChars: false,
|
|
162
|
+
customRules: [
|
|
163
|
+
{ test: (pwd) => !pwd.includes('password'), message: 'Cannot contain "password"' }
|
|
164
|
+
]
|
|
165
|
+
});
|
|
154
166
|
|
|
155
|
-
|
|
167
|
+
// Hash with validation
|
|
168
|
+
const result = await passwordManager.hash("MySecurePass123!");
|
|
169
|
+
// Returns: { hash: "$2a$...", salt: "..." }
|
|
156
170
|
|
|
157
|
-
|
|
158
|
-
|
|
171
|
+
// Verify
|
|
172
|
+
const isValid = await passwordManager.verify("MySecurePass123!", result.hash, result.salt);
|
|
159
173
|
|
|
160
|
-
|
|
174
|
+
// Validate password
|
|
175
|
+
const validation = passwordManager.validate("MySecurePass123!");
|
|
176
|
+
/*
|
|
177
|
+
Returns: {
|
|
178
|
+
isValid: true,
|
|
179
|
+
errors: [],
|
|
180
|
+
strength: { score: 4, label: 'strong', feedback: [...], suggestions: [...] }
|
|
181
|
+
}
|
|
182
|
+
*/
|
|
161
183
|
|
|
162
|
-
|
|
184
|
+
// Generate secure password
|
|
185
|
+
const generatedPassword = passwordManager.generate(16, {
|
|
186
|
+
requireUppercase: true,
|
|
187
|
+
requireNumbers: true,
|
|
188
|
+
requireSpecialChars: true
|
|
189
|
+
});
|
|
163
190
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
191
|
+
// Check strength
|
|
192
|
+
const strength = passwordManager.checkStrength("MySecurePass123!");
|
|
193
|
+
/*
|
|
194
|
+
Returns: {
|
|
195
|
+
score: 4,
|
|
196
|
+
label: 'strong',
|
|
197
|
+
feedback: [],
|
|
198
|
+
suggestions: ["Your password is very secure"]
|
|
169
199
|
}
|
|
200
|
+
*/
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## ๐ 2. JWT Utilities
|
|
170
204
|
|
|
171
|
-
|
|
205
|
+
### Functional Exports
|
|
206
|
+
```typescript
|
|
207
|
+
// Sign token with duration string
|
|
208
|
+
const token = signToken(
|
|
209
|
+
{ userId: 1, role: "admin" },
|
|
210
|
+
process.env.JWT_SECRET!,
|
|
211
|
+
"1h" // Duration string: "15m", "2h", "7d", "30s"
|
|
212
|
+
);
|
|
172
213
|
|
|
173
|
-
|
|
214
|
+
// Parse duration to seconds
|
|
215
|
+
parseDuration("15m"); // 900
|
|
216
|
+
parseDuration("2h"); // 7200
|
|
217
|
+
parseDuration("7d"); // 604800
|
|
174
218
|
|
|
175
|
-
|
|
219
|
+
// Generate token pair
|
|
220
|
+
const tokens = generateTokens(
|
|
221
|
+
{ userId: 42 },
|
|
222
|
+
process.env.ACCESS_SECRET!,
|
|
223
|
+
process.env.REFRESH_SECRET!,
|
|
224
|
+
"15m",
|
|
225
|
+
"7d"
|
|
226
|
+
);
|
|
227
|
+
// Returns: { accessToken: AccessToken, refreshToken: RefreshToken }
|
|
228
|
+
|
|
229
|
+
// Rotate refresh token
|
|
230
|
+
const newRefreshToken = rotateRefreshToken(
|
|
231
|
+
oldRefreshToken,
|
|
232
|
+
process.env.REFRESH_SECRET!
|
|
233
|
+
);
|
|
176
234
|
|
|
177
|
-
|
|
235
|
+
// Verify token (throws on error)
|
|
236
|
+
const payload = verifyToken(token, process.env.ACCESS_SECRET!);
|
|
178
237
|
|
|
179
|
-
|
|
238
|
+
// Safe verify (never throws)
|
|
239
|
+
const result = safeVerifyToken(token, process.env.ACCESS_SECRET!);
|
|
240
|
+
/*
|
|
241
|
+
Returns: {
|
|
242
|
+
valid: true,
|
|
243
|
+
payload: { userId: 1, ... },
|
|
244
|
+
error?: undefined
|
|
245
|
+
}
|
|
246
|
+
*/
|
|
247
|
+
|
|
248
|
+
// Decode without verification
|
|
249
|
+
const decoded = decodeToken(token); // Flexible: null | string | JwtPayload
|
|
250
|
+
const payload = decodeTokenStrict(token); // Throws if not object
|
|
251
|
+
|
|
252
|
+
// Extract token from various sources
|
|
253
|
+
const token = extractToken({
|
|
254
|
+
header: req.headers.authorization, // "Bearer <token>"
|
|
255
|
+
cookies: req.cookies, // { token: "...", accessToken: "..." }
|
|
256
|
+
query: req.query, // { token: "..." }
|
|
257
|
+
body: req.body, // { token: "..." }
|
|
258
|
+
wsMessage: message // string or { token: "..." }
|
|
259
|
+
});
|
|
260
|
+
```
|
|
180
261
|
|
|
181
|
-
|
|
262
|
+
### JWTManager Class
|
|
263
|
+
```typescript
|
|
264
|
+
const jwtManager = new JWTManager({
|
|
265
|
+
accessSecret: process.env.ACCESS_SECRET!,
|
|
266
|
+
refreshSecret: process.env.REFRESH_SECRET!,
|
|
267
|
+
accessExpiry: "15m",
|
|
268
|
+
refreshExpiry: "7d",
|
|
269
|
+
enableCaching: true, // Optional caching
|
|
270
|
+
maxCacheSize: 100 // Default 100
|
|
271
|
+
});
|
|
182
272
|
|
|
183
|
-
|
|
273
|
+
// Generate tokens
|
|
274
|
+
const tokens = await jwtManager.generateTokens({ userId: 42 });
|
|
184
275
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
header: req.headers.authorization,
|
|
189
|
-
cookies: req.cookies,
|
|
190
|
-
query: req.query,
|
|
191
|
-
body: req.body
|
|
192
|
-
});
|
|
276
|
+
// Verify tokens
|
|
277
|
+
const accessPayload = await jwtManager.verifyAccessToken(tokens.accessToken);
|
|
278
|
+
const refreshPayload = await jwtManager.verifyRefreshToken(tokens.refreshToken);
|
|
193
279
|
|
|
194
|
-
|
|
280
|
+
// Rotate refresh token
|
|
281
|
+
const newRefreshToken = await jwtManager.rotateRefreshToken(oldRefreshToken);
|
|
195
282
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
next();
|
|
199
|
-
} catch (err) {
|
|
200
|
-
return res.status(401).json({ error: "Invalid token" });
|
|
201
|
-
}
|
|
202
|
-
}
|
|
283
|
+
// Decode token
|
|
284
|
+
const decoded = jwtManager.decodeToken(token);
|
|
203
285
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
const token = extractToken({ wsMessage: msg });
|
|
286
|
+
// Extract from header
|
|
287
|
+
const token = jwtManager.extractTokenFromHeader("Bearer eyJ...");
|
|
207
288
|
|
|
208
|
-
|
|
289
|
+
// Validate without throwing
|
|
290
|
+
const isValid = jwtManager.validateToken(token, secret);
|
|
209
291
|
|
|
210
|
-
|
|
292
|
+
// Check expiration
|
|
293
|
+
const isExpired = jwtManager.isTokenExpired(token);
|
|
294
|
+
const expiresAt = jwtManager.getTokenExpiration(token);
|
|
211
295
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
296
|
+
// Cache management
|
|
297
|
+
jwtManager.clearCache();
|
|
298
|
+
const stats = jwtManager.getCacheStats(); // { size: 5, maxSize: 100 }
|
|
299
|
+
```
|
|
216
300
|
|
|
217
|
-
|
|
218
|
-
Registration
|
|
219
|
-
async function registerUser(email: string, password: string) {
|
|
220
|
-
const hash = await hashPassword(password);
|
|
301
|
+
## ๐ 3. Crypto Utilities
|
|
221
302
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
303
|
+
### Functional Exports
|
|
304
|
+
```typescript
|
|
305
|
+
// AES-256-GCM Encryption
|
|
306
|
+
const encrypted = encrypt("sensitive data", "your-secret-key");
|
|
307
|
+
// Returns: "iv:encrypted_data"
|
|
227
308
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
const valid = await verifyPassword(password, storedHash);
|
|
309
|
+
const decrypted = decrypt(encrypted, "your-secret-key");
|
|
310
|
+
// Returns: "sensitive data"
|
|
231
311
|
|
|
232
|
-
|
|
312
|
+
// HMAC
|
|
313
|
+
const hmac = createHMAC("data", "secret-key");
|
|
314
|
+
const isValidHMAC = verifyHMAC("data", hmac, "secret-key");
|
|
233
315
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
"7d"
|
|
240
|
-
);
|
|
241
|
-
}
|
|
316
|
+
// Random generation
|
|
317
|
+
const randomBytes = generateRandomBytes(32); // Buffer
|
|
318
|
+
const randomString = generateRandomString(16); // Base64 string
|
|
319
|
+
const randomHex = generateRandomHex(32); // Hex string
|
|
320
|
+
```
|
|
242
321
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
oldRefreshToken,
|
|
247
|
-
process.env.REFRESH_SECRET!
|
|
248
|
-
);
|
|
322
|
+
### CryptoManager Class
|
|
323
|
+
```typescript
|
|
324
|
+
const cryptoManager = new CryptoManager("your-secret-key");
|
|
249
325
|
|
|
250
|
-
|
|
326
|
+
// Encryption
|
|
327
|
+
const encrypted = cryptoManager.encrypt("data");
|
|
328
|
+
const decrypted = cryptoManager.decrypt(encrypted);
|
|
251
329
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
"15m"
|
|
256
|
-
);
|
|
330
|
+
// HMAC
|
|
331
|
+
const hmac = cryptoManager.createHMAC("data");
|
|
332
|
+
const isValid = cryptoManager.verifyHMAC("data", hmac);
|
|
257
333
|
|
|
258
|
-
|
|
259
|
-
|
|
334
|
+
// Random
|
|
335
|
+
const randomBytes = cryptoManager.generateRandomBytes(32);
|
|
336
|
+
const randomString = cryptoManager.generateRandomString(16);
|
|
337
|
+
```
|
|
260
338
|
|
|
261
|
-
๐จ Error Handling
|
|
339
|
+
## ๐จ Error Handling
|
|
262
340
|
|
|
263
341
|
This package uses standardized errors from `@naman_deep_singh/errors-utils`:
|
|
264
342
|
|
|
265
343
|
```typescript
|
|
266
|
-
import {
|
|
267
|
-
hashPassword,
|
|
344
|
+
import {
|
|
345
|
+
hashPassword,
|
|
268
346
|
verifyPassword,
|
|
269
|
-
BadRequestError,
|
|
347
|
+
BadRequestError,
|
|
270
348
|
UnauthorizedError,
|
|
271
349
|
ValidationError,
|
|
272
|
-
InternalServerError
|
|
350
|
+
InternalServerError
|
|
273
351
|
} from '@naman_deep_singh/security';
|
|
274
352
|
|
|
275
353
|
try {
|
|
@@ -300,14 +378,118 @@ try {
|
|
|
300
378
|
- `ValidationError` (422) - Password strength validation
|
|
301
379
|
- `InternalServerError` (500) - Server-side processing errors
|
|
302
380
|
|
|
381
|
+
## ๐งฉ Complete Authentication Example
|
|
382
|
+
|
|
383
|
+
### Registration with Validation
|
|
384
|
+
```typescript
|
|
385
|
+
import { PasswordManager, JWTManager } from '@naman_deep_singh/security';
|
|
386
|
+
|
|
387
|
+
const passwordManager = new PasswordManager({
|
|
388
|
+
minLength: 12,
|
|
389
|
+
requireUppercase: true,
|
|
390
|
+
requireNumbers: true,
|
|
391
|
+
requireSpecialChars: true
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
const jwtManager = new JWTManager({
|
|
395
|
+
accessSecret: process.env.ACCESS_SECRET!,
|
|
396
|
+
refreshSecret: process.env.REFRESH_SECRET!,
|
|
397
|
+
accessExpiry: "15m",
|
|
398
|
+
refreshExpiry: "7d"
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
async function registerUser(email: string, password: string) {
|
|
402
|
+
// Validate password strength
|
|
403
|
+
const validation = passwordManager.validate(password);
|
|
404
|
+
if (!validation.isValid) {
|
|
405
|
+
throw new ValidationError(`Password validation failed: ${validation.errors.join(', ')}`);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// Hash password
|
|
409
|
+
const { hash, salt } = await passwordManager.hash(password);
|
|
410
|
+
|
|
411
|
+
// Store user with hash and salt
|
|
412
|
+
return {
|
|
413
|
+
email,
|
|
414
|
+
passwordHash: hash,
|
|
415
|
+
passwordSalt: salt
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
### Login with Token Generation
|
|
421
|
+
```typescript
|
|
422
|
+
async function loginUser(email: string, password: string, storedHash: string, storedSalt: string) {
|
|
423
|
+
// Verify password
|
|
424
|
+
const isValid = await passwordManager.verify(password, storedHash, storedSalt);
|
|
425
|
+
if (!isValid) {
|
|
426
|
+
throw new UnauthorizedError("Invalid credentials");
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
// Generate tokens
|
|
430
|
+
return jwtManager.generateTokens({ email });
|
|
431
|
+
}
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
### Token Refresh
|
|
435
|
+
```typescript
|
|
436
|
+
async function refreshTokens(oldRefreshToken: string) {
|
|
437
|
+
// Verify old refresh token
|
|
438
|
+
const decoded = await jwtManager.verifyRefreshToken(oldRefreshToken);
|
|
439
|
+
|
|
440
|
+
// Generate new token pair
|
|
441
|
+
const newTokens = await jwtManager.generateTokens(decoded);
|
|
442
|
+
|
|
443
|
+
// Rotate refresh token
|
|
444
|
+
const rotatedRefreshToken = await jwtManager.rotateRefreshToken(oldRefreshToken);
|
|
445
|
+
|
|
446
|
+
return {
|
|
447
|
+
accessToken: newTokens.accessToken,
|
|
448
|
+
refreshToken: rotatedRefreshToken
|
|
449
|
+
};
|
|
450
|
+
}
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
### Express Middleware
|
|
454
|
+
```typescript
|
|
455
|
+
import { extractToken, safeVerifyToken } from '@naman_deep_singh/security';
|
|
456
|
+
|
|
457
|
+
export function authMiddleware(req, res, next) {
|
|
458
|
+
const token = extractToken({
|
|
459
|
+
header: req.headers.authorization,
|
|
460
|
+
cookies: req.cookies,
|
|
461
|
+
query: req.query,
|
|
462
|
+
body: req.body
|
|
463
|
+
});
|
|
464
|
+
|
|
465
|
+
if (!token) {
|
|
466
|
+
return res.status(401).json({ error: "Token missing" });
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
const result = safeVerifyToken(token, process.env.ACCESS_SECRET!);
|
|
470
|
+
|
|
471
|
+
if (!result.valid) {
|
|
472
|
+
return res.status(401).json({ error: "Invalid token" });
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
req.user = result.payload;
|
|
476
|
+
next();
|
|
477
|
+
}
|
|
478
|
+
```
|
|
479
|
+
|
|
303
480
|
๐ Security Best Practices
|
|
304
481
|
|
|
305
|
-
โ Use 32+ character secrets
|
|
482
|
+
โ Use 32+ character secrets for JWT and encryption
|
|
306
483
|
โ Store secrets in environment variables
|
|
307
484
|
โ Always use HTTPS in production
|
|
308
485
|
โ Keep refresh tokens secure (HttpOnly cookie recommended)
|
|
309
486
|
โ Do not store passwords in plain textโever
|
|
487
|
+
โ Use password peppering for additional security
|
|
488
|
+
โ Implement proper password strength requirements
|
|
489
|
+
โ Enable JWT caching for performance (but monitor memory usage)
|
|
310
490
|
โ Handle errors appropriately with proper HTTP status codes
|
|
491
|
+
โ Regularly rotate secrets and tokens
|
|
492
|
+
โ Use secure random generation for all cryptographic operations
|
|
311
493
|
|
|
312
494
|
๐ Integration with Other Packages
|
|
313
495
|
|
|
@@ -315,19 +497,20 @@ try {
|
|
|
315
497
|
|
|
316
498
|
```typescript
|
|
317
499
|
import { createServer } from '@naman_deep_singh/server-utils';
|
|
318
|
-
import {
|
|
500
|
+
import { PasswordManager } from '@naman_deep_singh/security';
|
|
319
501
|
|
|
320
502
|
const server = createServer('Auth API', '1.0.0');
|
|
503
|
+
const passwordManager = new PasswordManager();
|
|
321
504
|
|
|
322
505
|
server.app.post('/register', async (req, res) => {
|
|
323
506
|
try {
|
|
324
507
|
const { password } = req.body;
|
|
325
|
-
const hash = await
|
|
508
|
+
const hash = await passwordManager.hash(password);
|
|
326
509
|
// Save user with hash...
|
|
327
510
|
res.json({ success: true });
|
|
328
511
|
} catch (error) {
|
|
329
512
|
// Errors automatically handled by server-utils middleware
|
|
330
|
-
throw error;
|
|
513
|
+
throw error;
|
|
331
514
|
}
|
|
332
515
|
});
|
|
333
516
|
```
|
|
@@ -344,4 +527,4 @@ server.app.use(expressErrorHandler); // Handles security errors consistently
|
|
|
344
527
|
|
|
345
528
|
๐ License
|
|
346
529
|
|
|
347
|
-
MIT โ free to use & modify.
|
|
530
|
+
MIT โ free to use & modify.
|