authbackendpackage 1.1.3 → 1.1.9
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 +265 -263
- package/index.js +199 -196
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -1,263 +1,265 @@
|
|
|
1
|
-
|
|
2
|
-
---
|
|
3
|
-
|
|
4
|
-
# 🔐 AuthBackendPackage
|
|
5
|
-
|
|
6
|
-
A flexible and plug-and-play authentication module for [Node.js](w) applications. Provides features such as [OTP](w)-based verification, [JWT](w) authentication, email verification, password reset, and user profile management.
|
|
7
|
-
|
|
8
|
-
✅ **Successfully tested and used in production at:**
|
|
9
|
-
🔗 [https://pulsetalk-6lrk.onrender.com](https://pulsetalk-6lrk.onrender.com)
|
|
10
|
-
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
## 🔧 Installation
|
|
14
|
-
|
|
15
|
-
```bash
|
|
16
|
-
npm i authbackendpackage
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
---
|
|
20
|
-
|
|
21
|
-
## 📦 Module Setup
|
|
22
|
-
|
|
23
|
-
```js
|
|
24
|
-
// index.js or app.js
|
|
25
|
-
import express from "express";
|
|
26
|
-
import { createAuthModule } from "authbackendpackage";
|
|
27
|
-
import userModel from "./models/user.model.js";
|
|
28
|
-
import cloudinary from "./lib/cloudinary.js";
|
|
29
|
-
|
|
30
|
-
const app = express();
|
|
31
|
-
|
|
32
|
-
const auth = createAuthModule({
|
|
33
|
-
userModel,
|
|
34
|
-
cloudinaryInstance: cloudinary,
|
|
35
|
-
jwtSecret: process.env.JWT_SECRET,
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
import {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
app.post("/api/
|
|
103
|
-
app.post("/api/
|
|
104
|
-
app.post("/api/
|
|
105
|
-
app.post("/api/
|
|
106
|
-
app.
|
|
107
|
-
app.
|
|
108
|
-
app.
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
import
|
|
118
|
-
import
|
|
119
|
-
dotenv
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
* ✅
|
|
150
|
-
* ✅
|
|
151
|
-
* ✅
|
|
152
|
-
* ✅
|
|
153
|
-
* ✅
|
|
154
|
-
* ✅
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
"
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
1
|
+
|
|
2
|
+
---
|
|
3
|
+
|
|
4
|
+
# 🔐 AuthBackendPackage
|
|
5
|
+
|
|
6
|
+
A flexible and plug-and-play authentication module for [Node.js](w) applications. Provides features such as [OTP](w)-based verification, [JWT](w) authentication, email verification, password reset, and user profile management.
|
|
7
|
+
|
|
8
|
+
✅ **Successfully tested and used in production at:**
|
|
9
|
+
🔗 [https://pulsetalk-6lrk.onrender.com](https://pulsetalk-6lrk.onrender.com)
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## 🔧 Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm i authbackendpackage
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 📦 Module Setup
|
|
22
|
+
|
|
23
|
+
```js
|
|
24
|
+
// index.js or app.js
|
|
25
|
+
import express from "express";
|
|
26
|
+
import { createAuthModule } from "authbackendpackage";
|
|
27
|
+
import userModel from "./models/user.model.js";
|
|
28
|
+
import cloudinary from "./lib/cloudinary.js";
|
|
29
|
+
|
|
30
|
+
const app = express();
|
|
31
|
+
|
|
32
|
+
const auth = createAuthModule({
|
|
33
|
+
userModel,
|
|
34
|
+
cloudinaryInstance: cloudinary,
|
|
35
|
+
jwtSecret: process.env.JWT_SECRET,
|
|
36
|
+
BREVO_API_KEY=your_brevo_api_key_here
|
|
37
|
+
BREVO_SENDER_EMAIL=noreply@pulsetalk.com
|
|
38
|
+
BREVO_SENDER_NAME=PulseTalk
|
|
39
|
+
env: process.env.NODE_ENV,
|
|
40
|
+
});
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## ☁️ Cloudinary Configuration
|
|
46
|
+
|
|
47
|
+
Create an account on [Cloudinary](https://cloudinary.com/), generate API credentials, and store them in your `.env` file.
|
|
48
|
+
|
|
49
|
+
**Cloudinary Instance:**
|
|
50
|
+
|
|
51
|
+
```js
|
|
52
|
+
import { config } from "dotenv";
|
|
53
|
+
import { v2 as cloudinary } from "cloudinary";
|
|
54
|
+
config();
|
|
55
|
+
|
|
56
|
+
cloudinary.config({
|
|
57
|
+
cloud_name: process.env.CLOUDINARY_CLOUD_NAME,
|
|
58
|
+
api_key: process.env.CLOUDINARY_API_KEY,
|
|
59
|
+
api_secret: process.env.CLOUDINARY_API_SECRET,
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
export default cloudinary;
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## 🔐 JWT Secret
|
|
68
|
+
|
|
69
|
+
Set a secure `JWT_SECRET` string in your `.env` file.
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## 📧 Mail Setup
|
|
74
|
+
|
|
75
|
+
Generate an **App Password** from your Gmail settings and store it in `.env`.
|
|
76
|
+
|
|
77
|
+
👉 Follow this [Gmail App Password Guide](https://itsupport.umd.edu/itsupport?id=kb_article_view&sysparm_article=KB0015112)
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## 👤 User Model Example
|
|
82
|
+
|
|
83
|
+
```js
|
|
84
|
+
import mongoose from 'mongoose';
|
|
85
|
+
|
|
86
|
+
const userSchema = new mongoose.Schema({
|
|
87
|
+
email: { type: String, required: true, unique: true },
|
|
88
|
+
name: { type: String, required: true },
|
|
89
|
+
password: { type: String, required: true },
|
|
90
|
+
profilePicture: { type: String, default: "" },
|
|
91
|
+
}, { timestamps: true });
|
|
92
|
+
|
|
93
|
+
const User = mongoose.model('User', userSchema);
|
|
94
|
+
export default User;
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## 🔀 Routes Setup
|
|
100
|
+
|
|
101
|
+
```js
|
|
102
|
+
app.post("/api/send-otp", auth.sendOtp);
|
|
103
|
+
app.post("/api/verify-otp", auth.verifyOTP);
|
|
104
|
+
app.post("/api/signup", auth.signup);
|
|
105
|
+
app.post("/api/login", auth.login);
|
|
106
|
+
app.post("/api/logout", auth.logout);
|
|
107
|
+
app.put("/api/update-profile", auth.updateProfile);
|
|
108
|
+
app.get("/api/check-auth", auth.checkAuth);
|
|
109
|
+
app.post("/api/forgot-password", auth.forgotPassword);
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## 🛡️ Middleware: Protect Route
|
|
115
|
+
|
|
116
|
+
```js
|
|
117
|
+
import jwt from "jsonwebtoken";
|
|
118
|
+
import user from "../models/user.model.js";
|
|
119
|
+
import dotenv from "dotenv";
|
|
120
|
+
dotenv.config();
|
|
121
|
+
|
|
122
|
+
export const protectRoute = async (req, res, next) => {
|
|
123
|
+
try {
|
|
124
|
+
const token = req.cookies.jwt;
|
|
125
|
+
if (!token) {
|
|
126
|
+
return res.status(401).json({ message: "Not authorized - No token provided" });
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const decoded = jwt.verify(token, process.env.JWT_SECRET || "shreyash5506");
|
|
130
|
+
const foundUser = await user.findById(decoded.userId).select("-password");
|
|
131
|
+
|
|
132
|
+
if (!foundUser) {
|
|
133
|
+
return res.status(401).json({ message: "Not authorized - User not found" });
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
req.user = foundUser;
|
|
137
|
+
next();
|
|
138
|
+
} catch (error) {
|
|
139
|
+
console.error("Auth middleware error:", error);
|
|
140
|
+
res.status(401).json({ message: "Not authorized - Invalid token" });
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## 🧠 Features
|
|
148
|
+
|
|
149
|
+
* ✅ OTP verification via email (SMTP)
|
|
150
|
+
* ✅ Signup with verified OTP
|
|
151
|
+
* ✅ Secure login with JWT
|
|
152
|
+
* ✅ Profile update with image support (Cloudinary)
|
|
153
|
+
* ✅ Forgot password with [bcrypt](w)
|
|
154
|
+
* ✅ Cookie-based logout
|
|
155
|
+
* ✅ Middleware-ready routes
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## 🧪 Example `.env`
|
|
160
|
+
|
|
161
|
+
```env
|
|
162
|
+
BREVO_API_KEY=your_brevo_api_key_here
|
|
163
|
+
BREVO_SENDER_EMAIL=noreply@pulsetalk.com
|
|
164
|
+
BREVO_SENDER_NAME=PulseTalk
|
|
165
|
+
JWT_SECRET=your-secret-key
|
|
166
|
+
NODE_ENV=development
|
|
167
|
+
CLOUDINARY_CLOUD_NAME=your-cloud-name
|
|
168
|
+
CLOUDINARY_API_KEY=your-api-key
|
|
169
|
+
CLOUDINARY_API_SECRET=your-api-secret
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## 📥 Request Examples
|
|
175
|
+
|
|
176
|
+
### 1. Send OTP
|
|
177
|
+
|
|
178
|
+
```http
|
|
179
|
+
POST /api/send-otp
|
|
180
|
+
Content-Type: application/json
|
|
181
|
+
{
|
|
182
|
+
"email": "user@example.com"
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### 2. Verify OTP
|
|
187
|
+
|
|
188
|
+
```http
|
|
189
|
+
POST /api/verify-otp
|
|
190
|
+
Content-Type: application/json
|
|
191
|
+
{
|
|
192
|
+
"email": "user@example.com",
|
|
193
|
+
"otp": "123456"
|
|
194
|
+
}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### 3. Signup
|
|
198
|
+
|
|
199
|
+
```http
|
|
200
|
+
POST /api/signup
|
|
201
|
+
Content-Type: application/json
|
|
202
|
+
{
|
|
203
|
+
"email": "user@example.com",
|
|
204
|
+
"password": "your-password",
|
|
205
|
+
"name": "User Name"
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### 4. Login
|
|
210
|
+
|
|
211
|
+
```http
|
|
212
|
+
POST /api/login
|
|
213
|
+
Content-Type: application/json
|
|
214
|
+
{
|
|
215
|
+
"email": "user@example.com",
|
|
216
|
+
"password": "your-password"
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### 5. Update Profile
|
|
221
|
+
|
|
222
|
+
```http
|
|
223
|
+
PUT /api/update-profile
|
|
224
|
+
Content-Type: application/json
|
|
225
|
+
{
|
|
226
|
+
"name": "New Name",
|
|
227
|
+
"profilePicture": "base64encodedImageOrUrl"
|
|
228
|
+
}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### 6. Forgot Password
|
|
232
|
+
|
|
233
|
+
```http
|
|
234
|
+
POST /api/forgot-password
|
|
235
|
+
Content-Type: application/json
|
|
236
|
+
{
|
|
237
|
+
"email": "user@example.com",
|
|
238
|
+
"newPassword": "new-secure-password"
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## 🔐 Cookie-Based JWT Auth
|
|
245
|
+
|
|
246
|
+
Authentication is done using `httpOnly` cookies which automatically expire after 7 days for enhanced security.
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
## 🚀 Live Usage Demo
|
|
251
|
+
|
|
252
|
+
✅ **Successfully running on:**
|
|
253
|
+
🌐 [https://pulsetalk-6lrk.onrender.com](https://pulsetalk-6lrk.onrender.com)
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
## 📄 License
|
|
258
|
+
|
|
259
|
+
Licensed under [Apache-2.0](w).
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
Built with ❤️ by the **Shreyash Team**
|
|
264
|
+
|
|
265
|
+
---
|
package/index.js
CHANGED
|
@@ -1,196 +1,199 @@
|
|
|
1
|
-
// File: index.js
|
|
2
|
-
|
|
3
|
-
import dotenv from "dotenv";
|
|
4
|
-
dotenv.config();
|
|
5
|
-
|
|
6
|
-
import bcrypt from "bcryptjs";
|
|
7
|
-
import jwt from "jsonwebtoken";
|
|
8
|
-
import
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
}
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
const
|
|
154
|
-
return res.status(
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
const
|
|
175
|
-
if (!
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
await userModel.
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
1
|
+
// File: index.js
|
|
2
|
+
import axios from "axios";
|
|
3
|
+
import dotenv from "dotenv";
|
|
4
|
+
dotenv.config();
|
|
5
|
+
|
|
6
|
+
import bcrypt from "bcryptjs";
|
|
7
|
+
import jwt from "jsonwebtoken";
|
|
8
|
+
import dns from "dns/promises";
|
|
9
|
+
|
|
10
|
+
export const createAuthModule = ({
|
|
11
|
+
userModel,
|
|
12
|
+
cloudinaryInstance,
|
|
13
|
+
jwtSecret,
|
|
14
|
+
env = "development",
|
|
15
|
+
}) => {
|
|
16
|
+
|
|
17
|
+
const otpStorage = new Map();
|
|
18
|
+
|
|
19
|
+
// ================= TOKEN =================
|
|
20
|
+
const generateToken = (userId, res) => {
|
|
21
|
+
const token = jwt.sign({ userId }, jwtSecret, { expiresIn: "7d" });
|
|
22
|
+
|
|
23
|
+
res.cookie("jwt", token, {
|
|
24
|
+
httpOnly: true,
|
|
25
|
+
secure: env !== "development",
|
|
26
|
+
sameSite: "strict",
|
|
27
|
+
maxAge: 30 * 24 * 60 * 60 * 1000,
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
return token;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
// ================= BREVO API =================
|
|
34
|
+
const sendBrevoEmail = async ({ to, subject, html }) => {
|
|
35
|
+
return axios.post(
|
|
36
|
+
"https://api.brevo.com/v3/smtp/email",
|
|
37
|
+
{
|
|
38
|
+
sender: {
|
|
39
|
+
name: process.env.BREVO_SENDER_NAME,
|
|
40
|
+
email: process.env.BREVO_SENDER_EMAIL,
|
|
41
|
+
},
|
|
42
|
+
to: [{ email: to }],
|
|
43
|
+
subject,
|
|
44
|
+
htmlContent: html,
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
headers: {
|
|
48
|
+
"api-key": process.env.BREVO_API_KEY,
|
|
49
|
+
"Content-Type": "application/json",
|
|
50
|
+
},
|
|
51
|
+
}
|
|
52
|
+
);
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
// ================= SEND OTP =================
|
|
56
|
+
const sendOtp = async (req, res) => {
|
|
57
|
+
const { email } = req.body;
|
|
58
|
+
if (!email) return res.status(400).json({ message: "Email required", success: false });
|
|
59
|
+
|
|
60
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
61
|
+
if (!emailRegex.test(email))
|
|
62
|
+
return res.status(422).json({ message: "Invalid email", success: false });
|
|
63
|
+
|
|
64
|
+
try {
|
|
65
|
+
const domain = email.split("@")[1];
|
|
66
|
+
const mx = await dns.resolveMx(domain);
|
|
67
|
+
if (!mx.length)
|
|
68
|
+
return res.status(452).json({ message: "Invalid email domain", success: false });
|
|
69
|
+
} catch {
|
|
70
|
+
return res.status(452).json({ message: "Email domain unreachable", success: false });
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const otp = Math.floor(100000 + Math.random() * 900000).toString();
|
|
74
|
+
|
|
75
|
+
try {
|
|
76
|
+
await sendBrevoEmail({
|
|
77
|
+
to: email,
|
|
78
|
+
subject: "🔐 Your PulseTalk OTP",
|
|
79
|
+
html: `
|
|
80
|
+
<h2>OTP Verification</h2>
|
|
81
|
+
<p>Your OTP is:</p>
|
|
82
|
+
<h1>${otp}</h1>
|
|
83
|
+
<p>Valid for 10 minutes</p>
|
|
84
|
+
`,
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
otpStorage.set(email, {
|
|
88
|
+
otp,
|
|
89
|
+
verified: false,
|
|
90
|
+
createdAt: Date.now(),
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
return res.status(200).json({ message: "OTP sent", success: true });
|
|
94
|
+
} catch (error) {
|
|
95
|
+
return res.status(502).json({
|
|
96
|
+
message: "Brevo API email failed",
|
|
97
|
+
success: false,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
// ================= VERIFY OTP =================
|
|
103
|
+
const verifyOTP = (req, res) => {
|
|
104
|
+
const { email, otp } = req.body;
|
|
105
|
+
const record = otpStorage.get(email);
|
|
106
|
+
|
|
107
|
+
if (record && record.otp === otp) {
|
|
108
|
+
otpStorage.set(email, { ...record, verified: true });
|
|
109
|
+
return res.status(200).json({ message: "OTP verified", success: true });
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return res.status(400).json({ message: "Invalid OTP", success: false });
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
// ================= SIGNUP =================
|
|
116
|
+
const signup = async (req, res) => {
|
|
117
|
+
try {
|
|
118
|
+
const { email, password, name } = req.body;
|
|
119
|
+
const record = otpStorage.get(email);
|
|
120
|
+
|
|
121
|
+
if (!record || !record.verified)
|
|
122
|
+
return res.status(400).json({ message: "OTP not verified" });
|
|
123
|
+
|
|
124
|
+
if (!email || !password || !name)
|
|
125
|
+
return res.status(400).json({ message: "Missing fields" });
|
|
126
|
+
|
|
127
|
+
if (password.length < 6)
|
|
128
|
+
return res.status(400).json({ message: "Password too short" });
|
|
129
|
+
|
|
130
|
+
const exists = await userModel.findOne({ email });
|
|
131
|
+
if (exists)
|
|
132
|
+
return res.status(400).json({ message: "User already exists" });
|
|
133
|
+
|
|
134
|
+
const hash = await bcrypt.hash(password, 10);
|
|
135
|
+
const user = await userModel.create({ email, password: hash, name });
|
|
136
|
+
|
|
137
|
+
generateToken(user._id, res);
|
|
138
|
+
otpStorage.delete(email);
|
|
139
|
+
|
|
140
|
+
return res.status(201).json({ message: "User created", success: true, user });
|
|
141
|
+
} catch (err) {
|
|
142
|
+
return res.status(500).json({ message: err.message });
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
// ================= LOGIN =================
|
|
147
|
+
const login = async (req, res) => {
|
|
148
|
+
try {
|
|
149
|
+
const { email, password } = req.body;
|
|
150
|
+
const user = await userModel.findOne({ email });
|
|
151
|
+
if (!user) return res.status(400).json({ message: "User not found" });
|
|
152
|
+
|
|
153
|
+
const valid = await bcrypt.compare(password, user.password);
|
|
154
|
+
if (!valid) return res.status(400).json({ message: "Invalid password" });
|
|
155
|
+
|
|
156
|
+
generateToken(user._id, res);
|
|
157
|
+
return res.status(200).json({ message: "Login successful", success: true, user });
|
|
158
|
+
} catch (err) {
|
|
159
|
+
return res.status(500).json({ message: err.message });
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
const logout = (req, res) => {
|
|
164
|
+
res.cookie("jwt", "", { maxAge: 0 });
|
|
165
|
+
res.status(200).json({ message: "Logout successful" });
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
const checkAuth = (req, res) => {
|
|
169
|
+
res.status(200).json({ success: true, user: req.user });
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
const forgotPassword = async (req, res) => {
|
|
173
|
+
try {
|
|
174
|
+
const { email, newPassword } = req.body;
|
|
175
|
+
if (!email || !newPassword)
|
|
176
|
+
return res.status(400).json({ message: "Missing fields" });
|
|
177
|
+
|
|
178
|
+
const user = await userModel.findOne({ email });
|
|
179
|
+
if (!user) return res.status(400).json({ message: "User not found" });
|
|
180
|
+
|
|
181
|
+
const hash = await bcrypt.hash(newPassword, 10);
|
|
182
|
+
await userModel.findByIdAndUpdate(user._id, { password: hash });
|
|
183
|
+
|
|
184
|
+
res.status(200).json({ message: "Password updated", success: true });
|
|
185
|
+
} catch (err) {
|
|
186
|
+
res.status(500).json({ message: err.message });
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
return {
|
|
191
|
+
sendOtp,
|
|
192
|
+
verifyOTP,
|
|
193
|
+
signup,
|
|
194
|
+
login,
|
|
195
|
+
logout,
|
|
196
|
+
checkAuth,
|
|
197
|
+
forgotPassword,
|
|
198
|
+
};
|
|
199
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "authbackendpackage",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.9",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "npm run test"
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
"auth",
|
|
10
10
|
"otp",
|
|
11
11
|
"nodemailer",
|
|
12
|
+
"axios",
|
|
12
13
|
"jwt",
|
|
13
14
|
"bcrypt",
|
|
14
15
|
"cloudinary"
|
|
@@ -25,10 +26,11 @@
|
|
|
25
26
|
"homepage": "https://github.com/shreyashpatel5506/authbackendpackage#readme",
|
|
26
27
|
"description": "",
|
|
27
28
|
"dependencies": {
|
|
29
|
+
"axios": "^1.13.2",
|
|
28
30
|
"bcryptjs": "^3.0.2",
|
|
29
31
|
"dns": "^0.2.2",
|
|
30
32
|
"dotenv": "^17.0.1",
|
|
31
33
|
"jsonwebtoken": "^9.0.2",
|
|
32
34
|
"nodemailer": "^7.0.4"
|
|
33
35
|
}
|
|
34
|
-
}
|
|
36
|
+
}
|