auth-verify 1.13.6 → 1.14.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/index.js +10 -10
- package/package.json +1 -1
- package/readme.md +19 -80
- package/src/magiclink/index.js +114 -4
- package/src/otp/index.js +1 -1
- package/src/session/index.js +0 -83
package/index.js
CHANGED
|
@@ -51,7 +51,7 @@ class AuthVerify {
|
|
|
51
51
|
redisUrl,
|
|
52
52
|
});
|
|
53
53
|
|
|
54
|
-
this.session = new SessionManager({ storeTokens, redisUrl });
|
|
54
|
+
// this.session = new SessionManager({ storeTokens, redisUrl });
|
|
55
55
|
this.oauth = new OAuthManager();
|
|
56
56
|
this.totp = new TOTPManager(totp);
|
|
57
57
|
|
|
@@ -63,17 +63,17 @@ class AuthVerify {
|
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
// --- Session helpers ---
|
|
66
|
-
async createSession(userId, options = {}) {
|
|
67
|
-
|
|
68
|
-
}
|
|
66
|
+
// async createSession(userId, options = {}) {
|
|
67
|
+
// return this.session.create(userId, options);
|
|
68
|
+
// }
|
|
69
69
|
|
|
70
|
-
async verifySession(sessionId) {
|
|
71
|
-
|
|
72
|
-
}
|
|
70
|
+
// async verifySession(sessionId) {
|
|
71
|
+
// return this.session.verify(sessionId);
|
|
72
|
+
// }
|
|
73
73
|
|
|
74
|
-
async destroySession(sessionId) {
|
|
75
|
-
|
|
76
|
-
}
|
|
74
|
+
// async destroySession(sessionId) {
|
|
75
|
+
// return this.session.destroy(sessionId);
|
|
76
|
+
// }
|
|
77
77
|
|
|
78
78
|
// --- Passkey helpers ---
|
|
79
79
|
async registerPasskey(user) {
|
package/package.json
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"uuid": "^9.0.1"
|
|
20
20
|
},
|
|
21
21
|
"name": "auth-verify",
|
|
22
|
-
"version": "1.
|
|
22
|
+
"version": "1.14.0",
|
|
23
23
|
"description": "A simple Node.js library for sending and verifying OTP via email, SMS and Telegram bot. And generating TOTP codes and QR codes. And handling JWT with Cookies. And also handling passwordless logins with passkeys/webauth. And handling magiclink passwordless logins",
|
|
24
24
|
"main": "index.js",
|
|
25
25
|
"scripts": {
|
package/readme.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# auth-verify
|
|
2
2
|
|
|
3
|
-
**AuthVerify** is a modular authentication library for Node.js, providing JWT, OTP, TOTP, Passkeys (WebAuthn), Magic Links,
|
|
3
|
+
**AuthVerify** is a modular authentication library for Node.js, providing JWT, OTP, TOTP, Passkeys (WebAuthn), Magic Links, and OAuth helpers. You can easily register custom senders for OTPs or notifications. Auth-verify now supports **REST API** for generating, sending OTP with email/SMS and verifying it.
|
|
4
4
|
- [Installation](https://github.com/Jahongir2007/auth-verify/blob/main/docs/docs.md#-installation)
|
|
5
5
|
- [Initialization](https://github.com/Jahongir2007/auth-verify/blob/main/docs/docs.md#-example-initialize-library-commonjs)
|
|
6
6
|
- [JWT](https://github.com/Jahongir2007/auth-verify/blob/main/docs/docs.md#-jwt-usage)
|
|
@@ -11,7 +11,6 @@
|
|
|
11
11
|
- [OAuth](https://github.com/Jahongir2007/auth-verify/blob/main/docs/docs.md#-oauth-manager--auth-verify)
|
|
12
12
|
- [Magic Links](https://github.com/Jahongir2007/auth-verify/blob/main/docs/docs.md#-magiclink-passwordless-login-v180)
|
|
13
13
|
- [Custom Senders](https://github.com/Jahongir2007/auth-verify/blob/main/docs/docs.md#developer-extensibility-custom-senders)
|
|
14
|
-
- [Session Management](https://github.com/Jahongir2007/auth-verify/blob/main/docs/docs.md#-sessionmanager-api-documentation---auth-verify)
|
|
15
14
|
- [Crypto hashing](https://github.com/Jahongir2007/auth-verify/blob/main/docs/docs.md#-cryptomanager-api-guide)
|
|
16
15
|
- [Auth-verify REST API](https://auth-verify-sy2y.onrender.com/)
|
|
17
16
|
---
|
|
@@ -30,11 +29,10 @@ npm install auth-verify
|
|
|
30
29
|
|
|
31
30
|
## ⚙️ Quick overview
|
|
32
31
|
|
|
33
|
-
- `AuthVerify` (entry): constructs and exposes `.jwt`, `.otp`,
|
|
32
|
+
- `AuthVerify` (entry): constructs and exposes `.jwt`, `.otp`, `.totp` and `.oauth` managers.
|
|
34
33
|
- `JWTManager`: sign, verify, decode, revoke tokens. Supports `storeTokens: "memory" | "redis" | "none"` and middleware with custom cookie, header, and token extraction.
|
|
35
34
|
- `OTPManager`: generate, store, send, verify, resend OTPs. Supports `storeTokens: "memory" | "redis" | "none"`. Supports email, SMS helper, Telegram bot, and custom dev senders.
|
|
36
35
|
- `TOTPManager`: generate, verify uri, codes and QR codes.
|
|
37
|
-
- `SessionManager`: simple session creation/verification/destroy with memory or Redis backend.
|
|
38
36
|
- `OAuthManager`: Handle OAuth 2.0 logins for 20+ providers.
|
|
39
37
|
- `PasskeyManager`: Handle passwordless login and registration using WebAuthn/passkey.
|
|
40
38
|
- `MagicLinkManager`: Handle passwordless login with magic link generation and verification.
|
|
@@ -1447,7 +1445,22 @@ await auth.magic.sender({
|
|
|
1447
1445
|
pass: 'your_smtp_password'
|
|
1448
1446
|
});
|
|
1449
1447
|
```
|
|
1450
|
-
|
|
1448
|
+
|
|
1449
|
+
#### API services Example
|
|
1450
|
+
```js
|
|
1451
|
+
auth.magic.sender({
|
|
1452
|
+
service: 'api',
|
|
1453
|
+
apiService: 'resend', // 'mailgun', 'sendgrid'
|
|
1454
|
+
sender: 'noreply@yourdomain.com',
|
|
1455
|
+
apiKey: 'YOUR_API_KEY'
|
|
1456
|
+
})
|
|
1457
|
+
```
|
|
1458
|
+
> For `"mailgun"` you should also add also your domain
|
|
1459
|
+
> ```js
|
|
1460
|
+
> domain: "your-domain.com"
|
|
1461
|
+
>```
|
|
1462
|
+
|
|
1463
|
+
> ✅ Gmail, any SMTP provider and API based email services are supported.
|
|
1451
1464
|
> Use app passwords or tokens instead of your real password!
|
|
1452
1465
|
|
|
1453
1466
|
### 📩 Send Magic Link
|
|
@@ -1518,7 +1531,7 @@ auth.magic.send('user@example.com', (err) => {
|
|
|
1518
1531
|
```js
|
|
1519
1532
|
const express = require('express');
|
|
1520
1533
|
const bodyParser = require('body-parser');
|
|
1521
|
-
const
|
|
1534
|
+
const AuthVerify = require('auth-verify');
|
|
1522
1535
|
|
|
1523
1536
|
const app = express();
|
|
1524
1537
|
app.use(bodyParser.json());
|
|
@@ -1602,79 +1615,6 @@ When a custom sender is registered, `auth.otp.message()` will first attempt the
|
|
|
1602
1615
|
|
|
1603
1616
|
---
|
|
1604
1617
|
|
|
1605
|
-
## 📝 SessionManager API Documentation - `auth-verify`
|
|
1606
|
-
The session manager of `auth-verify` provides a simple way to **create**, **verify**, and **destroy user sessions** in either **memory** or **Redis** storage.
|
|
1607
|
-
|
|
1608
|
-
### Import
|
|
1609
|
-
```js
|
|
1610
|
-
const AuthVerify = require('auth-verify');
|
|
1611
|
-
const auth = new AuthVerify({ storeTokens: 'redis', redisUrl: "redis://localhost:6379" });
|
|
1612
|
-
```
|
|
1613
|
-
##### Options:
|
|
1614
|
-
| Option | Type | Default | Description |
|
|
1615
|
-
| ------------- | ------ | -------------------------- | --------------------------------------------------------- |
|
|
1616
|
-
| `storeTokens` | string | `'memory'` | Storage type for sessions: `'memory'` or `'redis'` |
|
|
1617
|
-
| `redisUrl` | string | `"redis://localhost:6379"` | Redis connection URL (required if `storeTokens: 'redis'`) |
|
|
1618
|
-
|
|
1619
|
-
### Methods
|
|
1620
|
-
#### 1️⃣ `create(userId, options)`
|
|
1621
|
-
Create a new session for a user.
|
|
1622
|
-
**Parameters:**
|
|
1623
|
-
| Name | Type | Required | Description | |
|
|
1624
|
-
| --------- | ------ | -------- | --------------------------------------- | --------- |
|
|
1625
|
-
| `userId` | string | ✅ | Unique ID of the user | |
|
|
1626
|
-
| `options` | object | ❌ | Optional settings: `{ expiresIn: number | string }` |
|
|
1627
|
-
|
|
1628
|
-
`expiresIn` formats:
|
|
1629
|
-
- Number → seconds
|
|
1630
|
-
- String → `"30s"`, `"5m"`, `"2h"`, `"1d"`
|
|
1631
|
-
##### **Returns:**
|
|
1632
|
-
`Promise<string>` → The session ID (UUID)
|
|
1633
|
-
##### **Example:**
|
|
1634
|
-
```js
|
|
1635
|
-
// Memory storage
|
|
1636
|
-
const auth = new AuthVerify({ storeTokens: 'memory' });
|
|
1637
|
-
const sessionId = await auth.session.create("user123", { expiresIn: "2h" });
|
|
1638
|
-
console.log(sessionId); // "550e8400-e29b-41d4-a716-446655440000"
|
|
1639
|
-
```
|
|
1640
|
-
#### 2️⃣ `verify(sessionId)`
|
|
1641
|
-
Verify if a session is valid.
|
|
1642
|
-
##### **Parameters:**
|
|
1643
|
-
| Name | Type | Required | Description |
|
|
1644
|
-
| ----------- | ------ | -------- | ------------------------ |
|
|
1645
|
-
| `sessionId` | string | ✅ | The session ID to verify |
|
|
1646
|
-
##### Returns:
|
|
1647
|
-
`Promise<string>` → Returns the `userId` if session is valid
|
|
1648
|
-
##### Throws:
|
|
1649
|
-
- `"Session not found or expired"`
|
|
1650
|
-
- `"Session expired"`
|
|
1651
|
-
##### Example:
|
|
1652
|
-
```js
|
|
1653
|
-
const userId = await auth.session.verify(sessionId);
|
|
1654
|
-
console.log(userId); // "user123"
|
|
1655
|
-
```
|
|
1656
|
-
#### 3️⃣ `destroy(sessionId)`
|
|
1657
|
-
Invalidate (destroy) a session manually.
|
|
1658
|
-
##### Parameters:
|
|
1659
|
-
| Name | Type | Required | Description |
|
|
1660
|
-
| ----------- | ------ | -------- | ------------------------- |
|
|
1661
|
-
| `sessionId` | string | ✅ | The session ID to destroy |
|
|
1662
|
-
##### Returns:
|
|
1663
|
-
`Promise<void>`
|
|
1664
|
-
##### Example:
|
|
1665
|
-
```js
|
|
1666
|
-
await auth.session.destroy(sessionId);
|
|
1667
|
-
console.log("Session destroyed");
|
|
1668
|
-
```
|
|
1669
|
-
|
|
1670
|
-
### Notes & Best Practices
|
|
1671
|
-
- **Memory** storage is fast but not persistent across server restarts. Use **Redis** in production.
|
|
1672
|
-
- Always verify session before allowing access to protected routes.
|
|
1673
|
-
- Optionally, combine with JWT or OTP for multi-layered authentication.
|
|
1674
|
-
- Use `expiresIn` wisely — shorter times improve security but may require more frequent re-login.
|
|
1675
|
-
|
|
1676
|
-
---
|
|
1677
|
-
|
|
1678
1618
|
## 🔐 CryptoManager API Guide
|
|
1679
1619
|
It supports both **PBKDF2** and **scrypt** algorithms for password or data hashing.
|
|
1680
1620
|
|
|
@@ -1829,7 +1769,6 @@ auth-verify/
|
|
|
1829
1769
|
│ ├─ totp/
|
|
1830
1770
|
| | ├─ index.js
|
|
1831
1771
|
| | ├─ base32.js
|
|
1832
|
-
│ ├─ /session/index.js
|
|
1833
1772
|
| ├─ /oauth/index.js
|
|
1834
1773
|
│ └─ helpers/helper.js
|
|
1835
1774
|
├─ rest-api/
|
package/src/magiclink/index.js
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
const jwt = require('jsonwebtoken');
|
|
2
2
|
const nodemailer = require('nodemailer');
|
|
3
3
|
const Redis = require('ioredis');
|
|
4
|
+
const sgMail = require('@sendgrid/mail');
|
|
5
|
+
const formData = require('form-data');
|
|
6
|
+
const Mailgun = require('mailgun.js');
|
|
7
|
+
const { Resend } = require('resend');
|
|
4
8
|
|
|
5
9
|
class MagicLinkManager {
|
|
6
10
|
constructor(config = {}) {
|
|
@@ -40,10 +44,114 @@ class MagicLinkManager {
|
|
|
40
44
|
? mailOption.html.replace(/{{\s*link\s*}}/gi, link)
|
|
41
45
|
: `<p>Click to login: <a href="${link}">${link}</a></p>`;
|
|
42
46
|
|
|
47
|
+
if(this.senderConfig.apiService === "sendgrid" && this.senderConfig.service === 'api'){
|
|
48
|
+
sgMail.setApiKey(this.senderConfig.apiKey)
|
|
49
|
+
|
|
50
|
+
const apiMail = {
|
|
51
|
+
to: email,
|
|
52
|
+
from: this.senderConfig.sender,
|
|
53
|
+
subject: mailOption.subject || 'Your Magic Login Link ✨',
|
|
54
|
+
html: letterHtml
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
try{
|
|
58
|
+
const info = await sgMail.send(apiMail)
|
|
59
|
+
this.recieverConfig = mailOption
|
|
60
|
+
// return info
|
|
61
|
+
|
|
62
|
+
let timeVal = 5 * 60 * 1000;
|
|
63
|
+
if (typeof this.expiresIn === 'string') {
|
|
64
|
+
if (this.expiresIn.endsWith('m')) timeVal = parseInt(this.expiresIn) * 60 * 1000;
|
|
65
|
+
else if (this.expiresIn.endsWith('s')) timeVal = parseInt(this.expiresIn) * 1000;
|
|
66
|
+
} else if (typeof this.expiresIn === 'number') timeVal = this.expiresIn * 1000;
|
|
67
|
+
|
|
68
|
+
if (this.storeType === 'memory') {
|
|
69
|
+
this.tokenStore.set(email, token);
|
|
70
|
+
setTimeout(() => this.tokenStore.delete(email), timeVal);
|
|
71
|
+
} else if (this.storeType === 'redis') {
|
|
72
|
+
await this.redis.set(email, token, 'PX', timeVal);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return { token, link };
|
|
76
|
+
}catch(err){
|
|
77
|
+
throw new Error(err.response?.body || err.message)
|
|
78
|
+
}
|
|
79
|
+
}else if(this.senderConfig.apiService === "mailgun" && this.senderConfig.service === "api"){
|
|
80
|
+
const mg = new Mailgun(formData).client({
|
|
81
|
+
username: 'api',
|
|
82
|
+
key: this.senderConfig.apiKey,
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
const apiMail = {
|
|
86
|
+
to: email,
|
|
87
|
+
from: this.senderConfig.sender,
|
|
88
|
+
subject: mailOption.subject || 'Your Magic Login Link ✨',
|
|
89
|
+
html: letterHtml
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
try{
|
|
93
|
+
const info = await mg.messages.create(this.senderConfig.domain, apiMail)
|
|
94
|
+
this.recieverConfig = mailOption
|
|
95
|
+
// return info
|
|
96
|
+
|
|
97
|
+
let timeVal = 5 * 60 * 1000;
|
|
98
|
+
if (typeof this.expiresIn === 'string') {
|
|
99
|
+
if (this.expiresIn.endsWith('m')) timeVal = parseInt(this.expiresIn) * 60 * 1000;
|
|
100
|
+
else if (this.expiresIn.endsWith('s')) timeVal = parseInt(this.expiresIn) * 1000;
|
|
101
|
+
} else if (typeof this.expiresIn === 'number') timeVal = this.expiresIn * 1000;
|
|
102
|
+
|
|
103
|
+
if (this.storeType === 'memory') {
|
|
104
|
+
this.tokenStore.set(email, token);
|
|
105
|
+
setTimeout(() => this.tokenStore.delete(email), timeVal);
|
|
106
|
+
} else if (this.storeType === 'redis') {
|
|
107
|
+
await this.redis.set(email, token, 'PX', timeVal);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return { token, link };
|
|
111
|
+
}catch(err){
|
|
112
|
+
throw new Error(err.response?.body || err.message)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
}else if(this.senderConfig.apiService === "resend" && this.senderConfig.service === 'api'){
|
|
116
|
+
const resend = new Resend(this.senderConfig.apiKey);
|
|
117
|
+
|
|
118
|
+
const apiMail = {
|
|
119
|
+
to: email,
|
|
120
|
+
from: this.senderConfig.sender,
|
|
121
|
+
subject: mailOption.subject || 'Your Magic Login Link ✨',
|
|
122
|
+
html: letterHtml
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
try {
|
|
126
|
+
const info = await resend.emails.send(apiMail);
|
|
127
|
+
this.recieverConfig = mailOption;
|
|
128
|
+
// return info;
|
|
129
|
+
|
|
130
|
+
let timeVal = 5 * 60 * 1000;
|
|
131
|
+
if (typeof this.expiresIn === 'string') {
|
|
132
|
+
if (this.expiresIn.endsWith('m')) timeVal = parseInt(this.expiresIn) * 60 * 1000;
|
|
133
|
+
else if (this.expiresIn.endsWith('s')) timeVal = parseInt(this.expiresIn) * 1000;
|
|
134
|
+
} else if (typeof this.expiresIn === 'number') timeVal = this.expiresIn * 1000;
|
|
135
|
+
|
|
136
|
+
if (this.storeType === 'memory') {
|
|
137
|
+
this.tokenStore.set(email, token);
|
|
138
|
+
setTimeout(() => this.tokenStore.delete(email), timeVal);
|
|
139
|
+
} else if (this.storeType === 'redis') {
|
|
140
|
+
await this.redis.set(email, token, 'PX', timeVal);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return { token, link };
|
|
144
|
+
} catch(err) {
|
|
145
|
+
throw new Error(err.response?.body || err.message);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
43
149
|
let transporter;
|
|
44
150
|
if (this.senderConfig.service === 'gmail') {
|
|
45
151
|
transporter = nodemailer.createTransport({
|
|
46
|
-
|
|
152
|
+
host: 'smtp.gmail.com',
|
|
153
|
+
port: this.senderConfig.port || 587,
|
|
154
|
+
secure: this.senderConfig.secure || false,
|
|
47
155
|
auth: { user: this.senderConfig.sender, pass: this.senderConfig.pass },
|
|
48
156
|
pool: true,
|
|
49
157
|
maxConnections: 3,
|
|
@@ -92,7 +200,9 @@ class MagicLinkManager {
|
|
|
92
200
|
const verifyProcess = async () => {
|
|
93
201
|
try {
|
|
94
202
|
const decoded = jwt.verify(token, this.secret);
|
|
95
|
-
// console.log(decoded);
|
|
203
|
+
// console.log("Decoded",decoded);
|
|
204
|
+
// console.log("Token", token);
|
|
205
|
+
// console.log("Secret", this.secret);
|
|
96
206
|
const email = decoded.email;
|
|
97
207
|
|
|
98
208
|
let stored;
|
|
@@ -107,7 +217,7 @@ class MagicLinkManager {
|
|
|
107
217
|
|
|
108
218
|
return { success: true, user: decoded };
|
|
109
219
|
} catch (err) {
|
|
110
|
-
throw new Error(
|
|
220
|
+
throw new Error(`Invalid or expired magic link: ${err}`);
|
|
111
221
|
}
|
|
112
222
|
};
|
|
113
223
|
|
|
@@ -117,4 +227,4 @@ class MagicLinkManager {
|
|
|
117
227
|
}
|
|
118
228
|
}
|
|
119
229
|
|
|
120
|
-
module.exports = MagicLinkManager;
|
|
230
|
+
module.exports = MagicLinkManager;
|
package/src/otp/index.js
CHANGED
|
@@ -6,7 +6,7 @@ const sgMail = require('@sendgrid/mail')
|
|
|
6
6
|
const formData = require('form-data');
|
|
7
7
|
const Mailgun = require('mailgun.js');
|
|
8
8
|
const { Resend } = require('resend');
|
|
9
|
-
const mail = require('@sendgrid/mail');
|
|
9
|
+
// const mail = require('@sendgrid/mail');
|
|
10
10
|
|
|
11
11
|
class OTPManager {
|
|
12
12
|
constructor(otpOptions = {}){
|
package/src/session/index.js
DELETED
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
const Redis = require("ioredis");
|
|
2
|
-
const { v4: uuidv4 } = require("uuid");
|
|
3
|
-
|
|
4
|
-
class SessionManager {
|
|
5
|
-
constructor(options = {}) {
|
|
6
|
-
this.storeType = options.storeTokens || 'memory'; // 'memory' or 'redis'
|
|
7
|
-
|
|
8
|
-
if (this.storeType === 'memory') {
|
|
9
|
-
this.sessions = new Map();
|
|
10
|
-
} else if (this.storeType === 'redis') {
|
|
11
|
-
this.redis = new Redis(options.redisUrl || "redis://localhost:6379");
|
|
12
|
-
}else if(this.storeType === 'none'){
|
|
13
|
-
return;
|
|
14
|
-
} else {
|
|
15
|
-
throw new Error("{storeTokens} should be 'memory' or 'redis'");
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
// Create a session
|
|
20
|
-
async create(userId, options = {}) {
|
|
21
|
-
const sessionId = uuidv4();
|
|
22
|
-
const expiresIn = options.expiresIn || 3600; // default 1 hour
|
|
23
|
-
if (typeof expiresIn === "string") {
|
|
24
|
-
const timeValue = parseInt(expiresIn);
|
|
25
|
-
if (expiresIn.endsWith("s")) expiresIn = timeValue;
|
|
26
|
-
else if (expiresIn.endsWith("m")) expiresIn = timeValue * 60;
|
|
27
|
-
else if (expiresIn.endsWith("h")) expiresIn = timeValue * 60 * 60;
|
|
28
|
-
else if (expiresIn.endsWith("d")) expiresIn = timeValue * 60 * 60 * 24;
|
|
29
|
-
else throw new Error("Invalid expiresIn format (use s, m, h, d)");
|
|
30
|
-
}
|
|
31
|
-
const now = Date.now();
|
|
32
|
-
|
|
33
|
-
const sessionData = {
|
|
34
|
-
userId,
|
|
35
|
-
createdAt: now,
|
|
36
|
-
expiresAt: now + expiresIn * 1000
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
if (this.storeType === 'memory') {
|
|
40
|
-
this.sessions.set(sessionId, sessionData);
|
|
41
|
-
} else if (this.storeType === 'redis') {
|
|
42
|
-
await this.redis.set(
|
|
43
|
-
sessionId,
|
|
44
|
-
JSON.stringify(sessionData),
|
|
45
|
-
"EX",
|
|
46
|
-
expiresIn
|
|
47
|
-
);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
return sessionId;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// Verify a session
|
|
54
|
-
async verify(sessionId) {
|
|
55
|
-
let data;
|
|
56
|
-
if (this.storeType === 'memory') {
|
|
57
|
-
data = this.sessions.get(sessionId);
|
|
58
|
-
} else if (this.storeType === 'redis') {
|
|
59
|
-
const raw = await this.redis.get(sessionId);
|
|
60
|
-
data = raw ? JSON.parse(raw) : null;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
if (!data) throw new Error("Session not found or expired");
|
|
64
|
-
|
|
65
|
-
if (Date.now() > data.expiresAt) {
|
|
66
|
-
await this.destroy(sessionId);
|
|
67
|
-
throw new Error("Session expired");
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
return data.userId;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// Destroy a session
|
|
74
|
-
async destroy(sessionId) {
|
|
75
|
-
if (this.storeType === 'memory') {
|
|
76
|
-
this.sessions.delete(sessionId);
|
|
77
|
-
} else if (this.storeType === 'redis') {
|
|
78
|
-
await this.redis.del(sessionId);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
module.exports = SessionManager;
|