auth-verify 1.0.3 → 1.1.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/package.json CHANGED
@@ -2,6 +2,7 @@
2
2
  "dependencies": {
3
3
  "axios": "^1.12.2",
4
4
  "crypto": "^1.0.1",
5
+ "express": "^5.1.0",
5
6
  "ioredis": "^5.8.1",
6
7
  "jsonwebtoken": "^9.0.2",
7
8
  "node-telegram-bot-api": "^0.66.0",
@@ -11,7 +12,7 @@
11
12
  "uuid": "^13.0.0"
12
13
  },
13
14
  "name": "auth-verify",
14
- "version": "1.0.3",
15
+ "version": "1.1.0",
15
16
  "description": "A simple Node.js library for sending and verifying OTP via email",
16
17
  "main": "index.js",
17
18
  "scripts": {
@@ -43,6 +44,5 @@
43
44
  "bugs": {
44
45
  "url": "https://github.com/jahongir2007/auth-verify/issues"
45
46
  },
46
- "homepage": "https://jahongir2007.github.io/auth-verify/",
47
- "devDependencies": {}
47
+ "homepage": "https://jahongir2007.github.io/auth-verify/"
48
48
  }
package/readme.md CHANGED
@@ -71,6 +71,40 @@ await auth.jwt.revokeUntil(token, '10m');
71
71
  // check if token is revoked (returns boolean)
72
72
  const isRevoked = await auth.jwt.isRevoked(token);
73
73
  ```
74
+ ## 🍪 Automatic Cookie Handling (New in v1.1.0)
75
+
76
+ You can now automatically store and verify JWTs via HTTP cookies — no need to manually send them!
77
+ ```js
78
+ const AuthVerify = require("auth-verify");
79
+ const express = require("express");
80
+ const app = express();
81
+
82
+ const auth = new AuthVerify({
83
+ jwtSecret: "supersecret", storeTokens: "memory"
84
+ });
85
+
86
+ app.post("/login", async (req, res) => {
87
+ const token = await auth.jwt.sign({ userId: 1 }, "5s", { res });
88
+ res.json({ token }); // token is also set as cookie automatically
89
+ });
90
+
91
+ app.get("/verify", async (req, res) => {
92
+ try {
93
+ const data = await auth.jwt.verify(req); // auto reads from cookie
94
+ res.json({ valid: true, data });
95
+ } catch (err) {
96
+ res.json({ valid: false, error: err.message });
97
+ }
98
+ });
99
+
100
+ app.listen(3000, () => console.log("🚀 Server running at http://localhost:3000"));
101
+ ```
102
+
103
+ What it does automatically:
104
+
105
+ - Saves token in a secure HTTP-only cookie
106
+ - Reads and verifies token from cookies
107
+ - Supports both async/await and callback styles
74
108
 
75
109
  Notes:
76
110
  - `sign` and `verify` support callback and promise styles in the implementation. When `storeTokens` is `"redis"` you should use the promise/async style (callback mode returns an error for redis in the current implementation).
@@ -0,0 +1,29 @@
1
+ class CookieManager {
2
+ static setCookie(res, name, value, options = {}) {
3
+ if (!res || typeof res.setHeader !== 'function') {
4
+ throw new Error("Response object must have setHeader() method");
5
+ }
6
+
7
+ let cookieStr = `${name}=${encodeURIComponent(value)}; Path=/;`;
8
+
9
+ if (options.httpOnly) cookieStr += " HttpOnly;";
10
+ if (options.secure) cookieStr += " Secure;";
11
+ if (options.maxAge) cookieStr += ` Max-Age=${Math.floor(options.maxAge / 1000)};`;
12
+ if (options.sameSite) cookieStr += ` SameSite=${options.sameSite};`;
13
+ if (options.domain) cookieStr += ` Domain=${options.domain};`;
14
+
15
+ const existing = res.getHeader('Set-Cookie') || [];
16
+ const newCookies = Array.isArray(existing) ? [...existing, cookieStr] : [cookieStr];
17
+ res.setHeader('Set-Cookie', newCookies);
18
+ }
19
+
20
+ static getCookie(req, name) {
21
+ const cookieHeader = req.headers?.cookie;
22
+ if (!cookieHeader) return null;
23
+ const cookies = cookieHeader.split(';').map(c => c.trim());
24
+ const found = cookies.find(c => c.startsWith(name + '='));
25
+ return found ? decodeURIComponent(found.split('=')[1]) : null;
26
+ }
27
+ }
28
+
29
+ module.exports = CookieManager;
package/src/jwt/index.js CHANGED
@@ -1,6 +1,250 @@
1
+ // const jwt = require("jsonwebtoken");
2
+ // const Redis = require("ioredis");
3
+ // const { parseTime } = require('../helpers/helper');
4
+ // const CookieManager = require('./cookie');
5
+
6
+ // class JWTManager {
7
+ // constructor(secret, options = {}) {
8
+ // if (!secret) throw new Error("JWT secret is required");
9
+ // this.secret = secret;
10
+ // this.storeType = options.storeTokens || "none";
11
+
12
+ // if (this.storeType !== 'none') {
13
+ // if (this.storeType === 'memory') {
14
+ // this.tokenStore = new Map();
15
+ // } else if (this.storeType === 'redis') {
16
+ // this.redis = new Redis(options.redisUrl || "redis://localhost:6379");
17
+ // } else {
18
+ // throw new Error("{storeTokens} should be 'none', 'memory', or 'redis'");
19
+ // }
20
+ // }
21
+ // }
22
+
23
+ // // Helper: convert expiry string like "1h" / "30m" / "10s" to milliseconds
24
+ // _parseExpiry(expiry) {
25
+ // if (typeof expiry === 'number') return expiry;
26
+ // if (typeof expiry !== 'string') return 3600000; // default 1h
27
+
28
+ // const num = parseInt(expiry);
29
+ // if (expiry.endsWith('h')) return num * 60 * 60 * 1000;
30
+ // if (expiry.endsWith('m')) return num * 60 * 1000;
31
+ // if (expiry.endsWith('s')) return num * 1000;
32
+ // return num;
33
+ // }
34
+
35
+ // async sign(payload, expiry, options = {}, callback) {
36
+ // if (typeof expiry === 'function') {
37
+ // callback = expiry;
38
+ // expiry = '1h'; // default
39
+ // }
40
+
41
+ // const expiryMs = this._parseExpiry(expiry || '1h'); // fallback to '1h'
42
+ // const expiryJwt = typeof expiry === 'number'
43
+ // ? Math.floor(expiry / 1000)
44
+ // : (typeof expiry === 'string' ? expiry : '1h');
45
+
46
+ // // Auto-set cookie if res provided
47
+ // if(typeof options == 'function'){
48
+ // callback = options;
49
+ // }
50
+
51
+
52
+ // // Callback version
53
+ // if(callback && typeof callback === 'function') {
54
+ // if(this.storeType === 'redis') return callback(new Error("⚠️ Redis requires async/await use promise style functions"));
55
+
56
+ // jwt.sign(payload, this.secret, { expiresIn: expiryJwt }, (err, token) => {
57
+ // if(err) return callback(err);
58
+
59
+ // if (options.res) {
60
+ // CookieManager.setCookie(options.res, 'jwt_token', token, {
61
+ // httpOnly: true,
62
+ // secure: options.secure ?? true,
63
+ // sameSite: 'Strict',
64
+ // maxAge: this._parseTime(expiresIn),
65
+ // });
66
+ // }else if(this.storeType === 'memory') {
67
+ // this.tokenStore.set(token, {payload, createdAt: Date.now()});
68
+ // setTimeout(() => this.tokenStore.delete(token), expiryMs);
69
+ // }
70
+
71
+ // callback(null, token);
72
+ // });
73
+ // return;
74
+ // }
75
+
76
+ // // Async version
77
+ // const token = await new Promise((res, rej) => {
78
+ // jwt.sign(payload, this.secret, { expiresIn: expiryJwt }, (err, t) => {
79
+ // if(err) rej(err);
80
+ // else res(t);
81
+ // });
82
+ // });
83
+
84
+ // if (options.res) {
85
+ // CookieManager.setCookie(options.res, 'jwt_token', token, {
86
+ // httpOnly: true,
87
+ // secure: options.secure ?? true,
88
+ // sameSite: 'Strict',
89
+ // maxAge: this._parseExpiry(expiresIn),
90
+ // });
91
+ // }else if(this.storeType === 'memory') {
92
+ // this.tokenStore.set(token, {payload, createdAt: Date.now()});
93
+ // setTimeout(() => this.tokenStore.delete(token), expiryMs);
94
+ // } else if(this.storeType === 'redis') {
95
+ // await this.redis.set(token, JSON.stringify({payload, createdAt: Date.now()}), "EX", Math.floor(expiryMs/1000));
96
+ // }
97
+
98
+ // return token;
99
+ // }
100
+
101
+ // async verify(token, callback) {
102
+
103
+ // let cookieToken;
104
+ // if(typeof token == 'object' && token.headers){
105
+ // cookieToken = CookieManager.getCookie(token, 'jwt_token');
106
+ // if (!token) throw new Error('JWT not found in cookies');
107
+
108
+ // try{
109
+ // const decoded = jwt.verify(cookieToken, this.secret);
110
+ // return decoded;
111
+ // }catch(err){
112
+ // throw new Error('Invalid or expired token');
113
+ // }
114
+ // }
115
+
116
+ // // Callback version
117
+ // if (callback && typeof callback === 'function') {
118
+ // if (this.storeType === 'redis') {
119
+ // return callback(new Error("⚠️ Redis requires async/await. Use Promise style."));
120
+ // }
121
+
122
+ // if (this.storeType === 'memory' && !this.tokenStore.has(token)) {
123
+ // return callback(new Error("❌ Token not found or revoked"));
124
+ // }
125
+
126
+ // jwt.verify(token, this.secret, (err, decoded) => {
127
+ // if (err) {
128
+ // if (err.name === "TokenExpiredError") return callback(new Error("❌ Token expired!"));
129
+ // if (err.name === "JsonWebTokenError") return callback(new Error("❌ Invalid token!"));
130
+ // return callback(new Error("❌ JWT error: " + err.message));
131
+ // }
132
+ // callback(null, decoded);
133
+ // });
134
+ // return;
135
+ // }
136
+
137
+ // // Async / Promise version
138
+ // try {
139
+ // if (this.storeType === 'memory' && !this.tokenStore.has(token)) {
140
+ // throw new Error("❌ Token not found or revoked");
141
+ // }
142
+
143
+ // if (this.storeType === 'redis') {
144
+ // const data = await this.redis.get(token);
145
+ // if (!data) throw new Error("❌ Token not found or revoked");
146
+ // }
147
+
148
+ // const decoded = jwt.verify(token, this.secret);
149
+ // return decoded;
150
+ // } catch (err) {
151
+ // throw new Error("❌ JWT verification failed: " + err.message);
152
+ // }
153
+ // }
154
+
155
+ // async decode(token, callback) {
156
+ // try {
157
+ // const decoded = jwt.decode(token);
158
+ // // if (callback && typeof callback === 'function') return callback(null, decoded);
159
+ // return decoded;
160
+ // } catch (err) {
161
+ // // if (callback && typeof callback === 'function') return callback(err);
162
+ // throw err;
163
+ // }
164
+ // }
165
+
166
+ // // Optional: manual token revoke for memory/redis
167
+ // async revoke(token, revokeTime = 0) {
168
+ // // function parseTime(str) {
169
+ // // if (typeof str === 'number') return str; // already in ms
170
+ // // if (typeof str !== 'string') return 0;
171
+
172
+ // // const num = parseInt(str);
173
+ // // if (str.endsWith('h')) return num * 60 * 60 * 1000;
174
+ // // if (str.endsWith('m')) return num * 60 * 1000;
175
+ // // if (str.endsWith('s')) return num * 1000;
176
+ // // return num;
177
+ // // }
178
+
179
+ // const revokeMs = parseTime(revokeTime);
180
+ // const revokeAfter = Date.now() + revokeMs;
181
+
182
+
183
+ // if (this.storeType === 'memory') {
184
+ // if(revokeTime == 0){
185
+ // this.tokenStore.delete(token);
186
+ // }else{
187
+ // setTimeout(() => this.tokenStore.delete(token), revokeAfter);
188
+ // }
189
+ // }else if(this.storeType == 'redis'){
190
+ // if(revokeTime == 0){
191
+ // await this.redis.del(token);
192
+ // }else{
193
+ // await this.redis.pexpire(token, revokeAfter);
194
+ // }
195
+ // }else{
196
+ // throw new Error("❌ {storeTokens} should be 'memory' or 'redis' or 'none'");
197
+ // }
198
+ // }
199
+
200
+ // async isRevoked(token) {
201
+ // if(this.storeType === 'memory') {
202
+ // const data = this.tokenStore.get(token);
203
+ // return data?.revokedUntil && data.revokedUntil > Date.now();
204
+ // } else if(this.storeType === 'redis') {
205
+ // const dataRaw = await this.redis.get(token);
206
+ // if (!dataRaw) return true;
207
+ // const data = JSON.parse(dataRaw);
208
+ // return data?.revokedUntil && data.revokedUntil > Date.now();
209
+ // } else {
210
+ // return false; // no store, can't revoke
211
+ // }
212
+ // }
213
+
214
+ // async revokeUntil(token, timestamp){
215
+ // // function parseTime(str) {
216
+ // // if (typeof str === 'number') return str; // already in ms
217
+ // // if (typeof str !== 'string') return 0;
218
+
219
+ // // const num = parseInt(str);
220
+ // // if (str.endsWith('h')) return num * 60 * 60 * 1000;
221
+ // // if (str.endsWith('m')) return num * 60 * 1000;
222
+ // // if (str.endsWith('s')) return num * 1000;
223
+ // // return num;
224
+ // // }
225
+
226
+ // const revokeMs = parseTime(timestamp);
227
+ // const revokedUntil = Date.now() + revokeMs;
228
+
229
+ // if(this.storeType == 'memory'){
230
+ // const data = this.tokenStore.get(token) || {};
231
+ // this.tokenStore.set(token, {...data, revokedUntil: revokedUntil});
232
+ // }else if(this.storeType == 'redis'){
233
+ // const dataRaw = await this.redis.get(token);
234
+ // const data = dataRaw ? JSON.parse(dataRaw) : {};
235
+ // data.revokedUntil = revokedUntil;
236
+ // await this.redis.set(token, JSON.stringify(data));
237
+ // }else{
238
+ // throw new Error("{storeTokens} should be 'memory' or 'redis'");
239
+ // }
240
+ // }
241
+ // }
242
+
243
+ // module.exports = JWTManager;
244
+
1
245
  const jwt = require("jsonwebtoken");
2
246
  const Redis = require("ioredis");
3
- const { parseTime } = require('../helpers/helper');
247
+ const CookieManager = require("./cookie");
4
248
 
5
249
  class JWTManager {
6
250
  constructor(secret, options = {}) {
@@ -8,199 +252,139 @@ class JWTManager {
8
252
  this.secret = secret;
9
253
  this.storeType = options.storeTokens || "none";
10
254
 
11
- if (this.storeType !== 'none') {
12
- if (this.storeType === 'memory') {
13
- this.tokenStore = new Map();
14
- } else if (this.storeType === 'redis') {
15
- this.redis = new Redis(options.redisUrl || "redis://localhost:6379");
16
- } else {
17
- throw new Error("{storeTokens} should be 'none', 'memory', or 'redis'");
18
- }
255
+ if (this.storeType === "memory") {
256
+ this.tokenStore = new Map();
257
+ } else if (this.storeType === "redis") {
258
+ this.redis = new Redis(options.redisUrl || "redis://localhost:6379");
259
+ } else if (this.storeType !== "none") {
260
+ throw new Error("{storeTokens} must be 'none', 'memory', or 'redis'");
19
261
  }
20
262
  }
21
263
 
22
- // Helper: convert expiry string like "1h" / "30m" / "10s" to milliseconds
23
264
  _parseExpiry(expiry) {
24
- if (typeof expiry === 'number') return expiry;
25
- if (typeof expiry !== 'string') return 3600000; // default 1h
26
-
265
+ if (typeof expiry === "number") return expiry;
266
+ if (typeof expiry !== "string") return 3600000; // default 1h
27
267
  const num = parseInt(expiry);
28
- if (expiry.endsWith('h')) return num * 60 * 60 * 1000;
29
- if (expiry.endsWith('m')) return num * 60 * 1000;
30
- if (expiry.endsWith('s')) return num * 1000;
268
+ if (expiry.endsWith("h")) return num * 3600000;
269
+ if (expiry.endsWith("m")) return num * 60000;
270
+ if (expiry.endsWith("s")) return num * 1000;
31
271
  return num;
32
272
  }
33
273
 
34
- async sign(payload, expiry, callback) {
35
- if (typeof expiry === 'function') {
274
+ async sign(payload, expiry = "1h", options = {}, callback) {
275
+ if (typeof expiry === "function") {
36
276
  callback = expiry;
37
- expiry = '1h'; // default
277
+ expiry = "1h";
278
+ }
279
+ if (typeof options === "function") {
280
+ callback = options;
281
+ options = {};
38
282
  }
39
283
 
40
- const expiryMs = this._parseExpiry(expiry || '1h'); // fallback to '1h'
41
- const expiryJwt = typeof expiry === 'number'
42
- ? Math.floor(expiry / 1000)
43
- : (typeof expiry === 'string' ? expiry : '1h');
44
-
45
- // Callback version
46
- if(callback && typeof callback === 'function') {
47
- if(this.storeType === 'redis') return callback(new Error("⚠️ Redis requires async/await use promise style functions"));
284
+ const expiryMs = this._parseExpiry(expiry);
285
+ const expiryJwt = typeof expiry === "number"
286
+ ? Math.floor(expiry / 1000)
287
+ : expiry;
48
288
 
49
- jwt.sign(payload, this.secret, { expiresIn: expiryJwt }, (err, token) => {
50
- if(err) return callback(err);
289
+ const createToken = () =>
290
+ new Promise((resolve, reject) => {
291
+ jwt.sign(payload, this.secret, { expiresIn: expiryJwt }, (err, token) => {
292
+ if (err) return reject(err);
293
+ resolve(token);
294
+ });
295
+ });
51
296
 
52
- if(this.storeType === 'memory') {
53
- this.tokenStore.set(token, {payload, createdAt: Date.now()});
54
- setTimeout(() => this.tokenStore.delete(token), expiryMs);
55
- }
297
+ const token = await createToken();
56
298
 
57
- callback(null, token);
58
- });
59
- return;
299
+ // Save token if needed
300
+ if (this.storeType === "memory") {
301
+ this.tokenStore.set(token, { payload, createdAt: Date.now() });
302
+ setTimeout(() => this.tokenStore.delete(token), expiryMs);
303
+ } else if (this.storeType === "redis") {
304
+ await this.redis.set(token, JSON.stringify({ payload, createdAt: Date.now() }), "EX", Math.floor(expiryMs / 1000));
60
305
  }
61
306
 
62
- // Async version
63
- const token = await new Promise((res, rej) => {
64
- jwt.sign(payload, this.secret, { expiresIn: expiryJwt }, (err, t) => {
65
- if(err) rej(err);
66
- else res(t);
307
+ // Auto cookie support
308
+ if (options.res) {
309
+ CookieManager.setCookie(options.res, "jwt_token", token, {
310
+ httpOnly: true,
311
+ secure: options.secure ?? true,
312
+ sameSite: "Strict",
313
+ maxAge: expiryMs,
67
314
  });
68
- });
69
-
70
- if(this.storeType === 'memory') {
71
- this.tokenStore.set(token, {payload, createdAt: Date.now()});
72
- setTimeout(() => this.tokenStore.delete(token), expiryMs);
73
- } else if(this.storeType === 'redis') {
74
- await this.redis.set(token, JSON.stringify({payload, createdAt: Date.now()}), "EX", Math.floor(expiryMs/1000));
75
315
  }
76
316
 
317
+ if (callback) return callback(null, token);
77
318
  return token;
78
319
  }
79
320
 
80
- async verify(token, callback) {
81
- // Callback version
82
- if (callback && typeof callback === 'function') {
83
- if (this.storeType === 'redis') {
84
- return callback(new Error("⚠️ Redis requires async/await. Use Promise style."));
85
- }
321
+ async verify(input, callback) {
322
+ let token = input;
86
323
 
87
- if (this.storeType === 'memory' && !this.tokenStore.has(token)) {
88
- return callback(new Error("❌ Token not found or revoked"));
89
- }
324
+ // If request object provided
325
+ if (typeof input === "object" && input.headers) {
326
+ token =
327
+ CookieManager.getCookie(input, "jwt_token") ||
328
+ (input.headers.authorization
329
+ ? input.headers.authorization.replace("Bearer ", "")
330
+ : null);
90
331
 
91
- jwt.verify(token, this.secret, (err, decoded) => {
92
- if (err) {
93
- if (err.name === "TokenExpiredError") return callback(new Error("❌ Token expired!"));
94
- if (err.name === "JsonWebTokenError") return callback(new Error("❌ Invalid token!"));
95
- return callback(new Error("❌ JWT error: " + err.message));
96
- }
97
- callback(null, decoded);
98
- });
99
- return;
332
+ if (!token) throw new Error("JWT not found in cookies or headers");
100
333
  }
101
334
 
102
- // Async / Promise version
103
335
  try {
104
- if (this.storeType === 'memory' && !this.tokenStore.has(token)) {
105
- throw new Error("❌ Token not found or revoked");
106
- }
336
+ const decoded = jwt.verify(token, this.secret);
337
+
338
+ if (this.storeType === "memory" && !this.tokenStore.has(token))
339
+ throw new Error("Token not found or revoked");
107
340
 
108
- if (this.storeType === 'redis') {
341
+ if (this.storeType === "redis") {
109
342
  const data = await this.redis.get(token);
110
- if (!data) throw new Error("Token not found or revoked");
343
+ if (!data) throw new Error("Token not found or revoked");
111
344
  }
112
345
 
113
- const decoded = jwt.verify(token, this.secret);
346
+ if (callback) return callback(null, decoded);
114
347
  return decoded;
115
348
  } catch (err) {
116
- throw new Error("❌ JWT verification failed: " + err.message);
349
+ if (callback) return callback(err);
350
+ throw new Error("JWT verification failed: " + err.message);
117
351
  }
118
352
  }
119
353
 
120
- async decode(token, callback) {
121
- try {
122
- const decoded = jwt.decode(token);
123
- // if (callback && typeof callback === 'function') return callback(null, decoded);
124
- return decoded;
125
- } catch (err) {
126
- // if (callback && typeof callback === 'function') return callback(err);
127
- throw err;
128
- }
354
+ async decode(token) {
355
+ return jwt.decode(token);
129
356
  }
130
357
 
131
- // Optional: manual token revoke for memory/redis
132
358
  async revoke(token, revokeTime = 0) {
133
- // function parseTime(str) {
134
- // if (typeof str === 'number') return str; // already in ms
135
- // if (typeof str !== 'string') return 0;
136
-
137
- // const num = parseInt(str);
138
- // if (str.endsWith('h')) return num * 60 * 60 * 1000;
139
- // if (str.endsWith('m')) return num * 60 * 1000;
140
- // if (str.endsWith('s')) return num * 1000;
141
- // return num;
142
- // }
143
-
144
- const revokeMs = parseTime(revokeTime);
145
- const revokeAfter = Date.now() + revokeMs;
146
-
147
-
148
- if (this.storeType === 'memory') {
149
- if(revokeTime == 0){
150
- this.tokenStore.delete(token);
151
- }else{
152
- setTimeout(() => this.tokenStore.delete(token), revokeAfter);
153
- }
154
- }else if(this.storeType == 'redis'){
155
- if(revokeTime == 0){
156
- await this.redis.del(token);
157
- }else{
158
- await this.redis.pexpire(token, revokeAfter);
159
- }
160
- }else{
161
- throw new Error("❌ {storeTokens} should be 'memory' or 'redis' or 'none'");
359
+ const revokeMs = this._parseExpiry(revokeTime);
360
+
361
+ if (this.storeType === "memory") {
362
+ if (revokeTime === 0) this.tokenStore.delete(token);
363
+ else setTimeout(() => this.tokenStore.delete(token), revokeMs);
364
+ } else if (this.storeType === "redis") {
365
+ if (revokeTime === 0) await this.redis.del(token);
366
+ else await this.redis.pexpire(token, revokeMs);
162
367
  }
163
368
  }
164
369
 
165
370
  async isRevoked(token) {
166
- if(this.storeType === 'memory') {
167
- const data = this.tokenStore.get(token);
168
- return data?.revokedUntil && data.revokedUntil > Date.now();
169
- } else if(this.storeType === 'redis') {
170
- const dataRaw = await this.redis.get(token);
171
- if (!dataRaw) return true;
172
- const data = JSON.parse(dataRaw);
173
- return data?.revokedUntil && data.revokedUntil > Date.now();
174
- } else {
175
- return false; // no store, can't revoke
176
- }
371
+ if (this.storeType === "memory") return !this.tokenStore.has(token);
372
+ if (this.storeType === "redis") return !(await this.redis.get(token));
373
+ return false;
177
374
  }
178
375
 
179
- async revokeUntil(token, timestamp){
180
- // function parseTime(str) {
181
- // if (typeof str === 'number') return str; // already in ms
182
- // if (typeof str !== 'string') return 0;
183
-
184
- // const num = parseInt(str);
185
- // if (str.endsWith('h')) return num * 60 * 60 * 1000;
186
- // if (str.endsWith('m')) return num * 60 * 1000;
187
- // if (str.endsWith('s')) return num * 1000;
188
- // return num;
189
- // }
190
-
191
- const revokeMs = parseTime(timestamp);
192
- const revokedUntil = Date.now() + revokeMs;
376
+ async revokeUntil(token, timestamp) {
377
+ const revokeMs = this._parseExpiry(timestamp);
378
+ const revokedUntil = Date.now() + revokeMs;
193
379
 
194
- if(this.storeType == 'memory'){
380
+ if (this.storeType === "memory") {
195
381
  const data = this.tokenStore.get(token) || {};
196
- this.tokenStore.set(token, {...data, revokedUntil: revokedUntil});
197
- }else if(this.storeType == 'redis'){
382
+ this.tokenStore.set(token, { ...data, revokedUntil });
383
+ } else if (this.storeType === "redis") {
198
384
  const dataRaw = await this.redis.get(token);
199
385
  const data = dataRaw ? JSON.parse(dataRaw) : {};
200
386
  data.revokedUntil = revokedUntil;
201
387
  await this.redis.set(token, JSON.stringify(data));
202
- }else{
203
- throw new Error("{storeTokens} should be 'memory' or 'redis'");
204
388
  }
205
389
  }
206
390
  }
package/test.js CHANGED
@@ -101,9 +101,11 @@
101
101
  // }catch(err){}
102
102
  // })();
103
103
 
104
- const TelegramBot = require("node-telegram-bot-api");
104
+ // const TelegramBot = require("node-telegram-bot-api");
105
+ const express = require('express');
105
106
  const AuthVerify = require("./index"); // your library
106
-
107
+ const app = express();
108
+ app.use(express.json());
107
109
  // // Your bot token from BotFather
108
110
  // const BOT_TOKEN = "6657700716:AAGW3s5Yxk5SrRH7yRqrgG-kVrG9a6PXBxk";
109
111
 
@@ -149,7 +151,25 @@ const AuthVerify = require("./index"); // your library
149
151
  // }
150
152
  // });
151
153
 
152
- const auth = new AuthVerify({ jwtSecret: 's', storeTokens: 'memory', otpExpiry: '5m' });
154
+ const auth = new AuthVerify({ jwtSecret: 's', storeTokens: 'memory'});
155
+
156
+ app.get('/', async (req, res) => {
157
+ const token = await auth.jwt.sign({ id: 1, role: 'user' }, '1h', { res });
158
+ res.send(`JWT saved in cookie!`);
159
+ });
160
+
161
+ app.get('/verify', async (req, res) => {
162
+ try {
163
+ const data = await auth.jwt.verify({ headers: req.headers });
164
+ res.json({ valid: true, data });
165
+ } catch (err) {
166
+ res.status(401).json({ valid: false, error: err.message });
167
+ }
168
+ });
169
+
170
+ app.listen(3000, ()=>{
171
+ console.log('App is running')
172
+ });
153
173
 
154
174
  // auth.register.sender("consoleOtp", async ({ to, code }) => {
155
175
  // console.log(`🔑 Sending OTP ${code} to ${to}`);