authbackendpackage 1.1.2 β†’ 1.1.8

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.
Files changed (3) hide show
  1. package/README.md +265 -264
  2. package/index.js +200 -196
  3. package/package.json +4 -2
package/README.md CHANGED
@@ -1,264 +1,265 @@
1
- Here’s the updated **README** file with the mention of successful testing on your website **PulseTalk**:
2
-
3
- ---
4
-
5
- # πŸ” AuthBackendPackage
6
-
7
- 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.
8
-
9
- βœ… **Successfully tested and used in production at:**
10
- πŸ”— [https://pulsetalk-6lrk.onrender.com](https://pulsetalk-6lrk.onrender.com)
11
-
12
- ---
13
-
14
- ## πŸ”§ Installation
15
-
16
- ```bash
17
- npm i authbackendpackage
18
- ```
19
-
20
- ---
21
-
22
- ## πŸ“¦ Module Setup
23
-
24
- ```js
25
- // index.js or app.js
26
- import express from "express";
27
- import { createAuthModule } from "authbackendpackage";
28
- import userModel from "./models/user.model.js";
29
- import cloudinary from "./lib/cloudinary.js";
30
-
31
- const app = express();
32
-
33
- const auth = createAuthModule({
34
- userModel,
35
- cloudinaryInstance: cloudinary,
36
- jwtSecret: process.env.JWT_SECRET,
37
- mailUser: process.env.MY_MAIL,
38
- mailPass: process.env.MY_PASSWORD,
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
- MY_MAIL=your-email@gmail.com
163
- MY_PASSWORD=your-app-password
164
- JWT_SECRET=your-secret-key
165
- NODE_ENV=development
166
- CLOUDINARY_CLOUD_NAME=your-cloud-name
167
- CLOUDINARY_API_KEY=your-api-key
168
- CLOUDINARY_API_SECRET=your-api-secret
169
- ```
170
-
171
- ---
172
-
173
- ## πŸ“₯ Request Examples
174
-
175
- ### 1. Send OTP
176
-
177
- ```http
178
- POST /api/send-otp
179
- Content-Type: application/json
180
- {
181
- "email": "user@example.com"
182
- }
183
- ```
184
-
185
- ### 2. Verify OTP
186
-
187
- ```http
188
- POST /api/verify-otp
189
- Content-Type: application/json
190
- {
191
- "email": "user@example.com",
192
- "otp": "123456"
193
- }
194
- ```
195
-
196
- ### 3. Signup
197
-
198
- ```http
199
- POST /api/signup
200
- Content-Type: application/json
201
- {
202
- "email": "user@example.com",
203
- "password": "your-password",
204
- "name": "User Name"
205
- }
206
- ```
207
-
208
- ### 4. Login
209
-
210
- ```http
211
- POST /api/login
212
- Content-Type: application/json
213
- {
214
- "email": "user@example.com",
215
- "password": "your-password"
216
- }
217
- ```
218
-
219
- ### 5. Update Profile
220
-
221
- ```http
222
- PUT /api/update-profile
223
- Content-Type: application/json
224
- {
225
- "name": "New Name",
226
- "profilePicture": "base64encodedImageOrUrl"
227
- }
228
- ```
229
-
230
- ### 6. Forgot Password
231
-
232
- ```http
233
- POST /api/forgot-password
234
- Content-Type: application/json
235
- {
236
- "email": "user@example.com",
237
- "newPassword": "new-secure-password"
238
- }
239
- ```
240
-
241
- ---
242
-
243
- ## πŸ” Cookie-Based JWT Auth
244
-
245
- Authentication is done using `httpOnly` cookies which automatically expire after 7 days for enhanced security.
246
-
247
- ---
248
-
249
- ## πŸš€ Live Usage Demo
250
-
251
- βœ… **Successfully running on:**
252
- 🌐 [https://pulsetalk-6lrk.onrender.com](https://pulsetalk-6lrk.onrender.com)
253
-
254
- ---
255
-
256
- ## πŸ“„ License
257
-
258
- Licensed under [Apache-2.0](w).
259
-
260
- ---
261
-
262
- Built with ❀️ by the **Shreyash Team**
263
-
264
- ---
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,200 @@
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 nodemailer from "nodemailer";
9
- import dns from "dns/promises";
10
-
11
- export const createAuthModule = ({ userModel, cloudinaryInstance, jwtSecret, mailUser, mailPass, env = "development" }) => {
12
-
13
- const otpStorage = new Map();
14
-
15
- const generateToken = (userId, res) => {
16
- const token = jwt.sign({ userId }, jwtSecret, {
17
- expiresIn: "7d",
18
- });
19
-
20
- res.cookie("jwt", token, {
21
- httpOnly: true,
22
- secure: env !== "development",
23
- sameSite: "strict",
24
- maxAge: 30 * 24 * 60 * 60 * 1000,
25
- });
26
-
27
- return token;
28
- };
29
-
30
- const transporter = nodemailer.createTransport({
31
- service: "gmail",
32
- auth: {
33
- user: mailUser,
34
- pass: mailPass,
35
- },
36
- });
37
-
38
- const sendOtp = async (req, res) => {
39
- const { email } = req.body;
40
- if (!email) return res.status(400).json({ message: "Email is required", success: false });
41
-
42
- const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
43
- if (!emailRegex.test(email)) return res.status(422).json({ message: "Invalid email format", success: false });
44
-
45
- try {
46
- const domain = email.split("@")[1];
47
- const mxRecords = await dns.resolveMx(domain);
48
- if (!mxRecords || mxRecords.length === 0) {
49
- return res.status(452).json({ message: "Email domain does not accept mail", success: false });
50
- }
51
- } catch (dnsError) {
52
- return res.status(452).json({ message: "Invalid or unreachable email domain", success: false });
53
- }
54
-
55
- const otp = Math.floor(100000 + Math.random() * 900000).toString();
56
- const mailOptions = {
57
- from: `PulseTalk <${mailUser}>`,
58
- to: email,
59
- subject: "πŸ” Your PulseTalk OTP Code",
60
- html: `Your OTP code is: <strong>${otp}</strong> (valid for 10 minutes)`
61
- };
62
-
63
- try {
64
- const info = await transporter.sendMail(mailOptions);
65
- if (info.accepted.includes(email)) {
66
- otpStorage.set(email, { otp, verified: false });
67
- return res.status(200).json({ message: "OTP sent", success: true });
68
- } else {
69
- return res.status(452).json({ message: "SMTP did not accept the email", success: false });
70
- }
71
- } catch (err) {
72
- return res.status(502).json({ message: "Failed to send email", success: false });
73
- }
74
- };
75
-
76
- const verifyOTP = (req, res) => {
77
- const { email, otp } = req.body;
78
- const record = otpStorage.get(email);
79
- if (record && record.otp === otp) {
80
- otpStorage.set(email, { ...record, verified: true });
81
- return res.status(200).json({ message: "OTP verified", success: true });
82
- }
83
- return res.status(400).json({ message: "Invalid OTP", success: false });
84
- };
85
-
86
- const signup = async (req, res) => {
87
- try {
88
- const { email, password, name } = req.body;
89
- const { profilePicture } = req.files || {};
90
- const record = otpStorage.get(email);
91
-
92
- if (!record || !record.verified) return res.status(400).json({ message: "OTP not verified for this email" });
93
- if (!email || !password || !name) return res.status(400).json({ message: "Missing required fields" });
94
- if (password.length < 6) return res.status(401).json({ message: "Password too short" });
95
-
96
- const existingUser = await userModel.findOne({ email });
97
- if (existingUser) return res.status(400).json({ message: "User already exists" });
98
-
99
- const hashPassword = await bcrypt.hash(password, 10);
100
- const newUser = new userModel({ email, password: hashPassword, name });
101
- await newUser.save();
102
- generateToken(newUser._id, res);
103
- otpStorage.delete(email);
104
-
105
- return res.status(201).json({
106
- message: "User created",
107
- success: true,
108
- user: newUser,
109
- });
110
- } catch (err) {
111
- return res.status(500).json({ message: err.message });
112
- }
113
- };
114
-
115
- const login = async (req, res) => {
116
- try {
117
- const { email, password } = req.body;
118
- const user = await userModel.findOne({ email });
119
- if (!user) return res.status(400).json({ message: "User does not exist" });
120
-
121
- const validPassword = await bcrypt.compare(password, user.password);
122
- if (!validPassword) return res.status(400).json({ message: "Invalid password" });
123
-
124
- generateToken(user._id, res);
125
- return res.status(200).json({ message: "Login successful", success: true, user });
126
- } catch (error) {
127
- return res.status(500).json({ message: error.message });
128
- }
129
- };
130
-
131
- const logout = async (req, res) => {
132
- res.cookie("jwt", "", { maxAge: 0 });
133
- return res.status(200).json({ message: "Logout successful" });
134
- };
135
-
136
- const updateProfile = async (req, res) => {
137
- try {
138
- const userId = req.user._id;
139
- const { name, profilePicture } = req.body;
140
-
141
- const updatedFields = {};
142
- if (name) updatedFields.name = name;
143
-
144
- if (profilePicture && profilePicture.trim() !== '') {
145
- try {
146
- const pic = await cloudinaryInstance.uploader.upload(profilePicture);
147
- updatedFields.profilePicture = pic.secure_url;
148
- } catch {
149
- return res.status(400).json({ message: "Invalid profile picture format" });
150
- }
151
- }
152
-
153
- const user = await userModel.findByIdAndUpdate(userId, updatedFields, { new: true });
154
- return res.status(200).json({ message: "Profile updated", success: true, user });
155
- } catch (error) {
156
- return res.status(500).json({ message: error.message });
157
- }
158
- };
159
-
160
- const checkAuth = async (req, res) => {
161
- try {
162
- const user = req.user;
163
- return res.status(200).json({ message: "User authenticated", success: true, user });
164
- } catch (error) {
165
- return res.status(500).json({ message: error.message });
166
- }
167
- };
168
-
169
- const forgotPassword = async (req, res) => {
170
- try {
171
- const { email, newPassword } = req.body;
172
- if (!email || !newPassword) return res.status(400).json({ message: "Email and new password are required" });
173
-
174
- const user = await userModel.findOne({ email });
175
- if (!user) return res.status(400).json({ message: "User does not exist" });
176
-
177
- const hashPassword = await bcrypt.hash(newPassword, 10);
178
- await userModel.findByIdAndUpdate(user._id, { password: hashPassword });
179
-
180
- return res.status(200).json({ message: "Password updated", success: true });
181
- } catch (error) {
182
- return res.status(500).json({ message: error.message });
183
- }
184
- };
185
-
186
- return {
187
- sendOtp,
188
- verifyOTP,
189
- signup,
190
- login,
191
- logout,
192
- updateProfile,
193
- checkAuth,
194
- forgotPassword,
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
+ import axios from "axios";
10
+
11
+ export const createAuthModule = ({
12
+ userModel,
13
+ cloudinaryInstance,
14
+ jwtSecret,
15
+ env = "development",
16
+ }) => {
17
+
18
+ const otpStorage = new Map();
19
+
20
+ // ================= TOKEN =================
21
+ const generateToken = (userId, res) => {
22
+ const token = jwt.sign({ userId }, jwtSecret, { expiresIn: "7d" });
23
+
24
+ res.cookie("jwt", token, {
25
+ httpOnly: true,
26
+ secure: env !== "development",
27
+ sameSite: "strict",
28
+ maxAge: 30 * 24 * 60 * 60 * 1000,
29
+ });
30
+
31
+ return token;
32
+ };
33
+
34
+ // ================= BREVO API =================
35
+ const sendBrevoEmail = async ({ to, subject, html }) => {
36
+ return axios.post(
37
+ "https://api.brevo.com/v3/smtp/email",
38
+ {
39
+ sender: {
40
+ name: process.env.BREVO_SENDER_NAME,
41
+ email: process.env.BREVO_SENDER_EMAIL,
42
+ },
43
+ to: [{ email: to }],
44
+ subject,
45
+ htmlContent: html,
46
+ },
47
+ {
48
+ headers: {
49
+ "api-key": process.env.BREVO_API_KEY,
50
+ "Content-Type": "application/json",
51
+ },
52
+ }
53
+ );
54
+ };
55
+
56
+ // ================= SEND OTP =================
57
+ const sendOtp = async (req, res) => {
58
+ const { email } = req.body;
59
+ if (!email) return res.status(400).json({ message: "Email required", success: false });
60
+
61
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
62
+ if (!emailRegex.test(email))
63
+ return res.status(422).json({ message: "Invalid email", success: false });
64
+
65
+ try {
66
+ const domain = email.split("@")[1];
67
+ const mx = await dns.resolveMx(domain);
68
+ if (!mx.length)
69
+ return res.status(452).json({ message: "Invalid email domain", success: false });
70
+ } catch {
71
+ return res.status(452).json({ message: "Email domain unreachable", success: false });
72
+ }
73
+
74
+ const otp = Math.floor(100000 + Math.random() * 900000).toString();
75
+
76
+ try {
77
+ await sendBrevoEmail({
78
+ to: email,
79
+ subject: "πŸ” Your PulseTalk OTP",
80
+ html: `
81
+ <h2>OTP Verification</h2>
82
+ <p>Your OTP is:</p>
83
+ <h1>${otp}</h1>
84
+ <p>Valid for 10 minutes</p>
85
+ `,
86
+ });
87
+
88
+ otpStorage.set(email, {
89
+ otp,
90
+ verified: false,
91
+ createdAt: Date.now(),
92
+ });
93
+
94
+ return res.status(200).json({ message: "OTP sent", success: true });
95
+ } catch (error) {
96
+ return res.status(502).json({
97
+ message: "Brevo API email failed",
98
+ success: false,
99
+ });
100
+ }
101
+ };
102
+
103
+ // ================= VERIFY OTP =================
104
+ const verifyOTP = (req, res) => {
105
+ const { email, otp } = req.body;
106
+ const record = otpStorage.get(email);
107
+
108
+ if (record && record.otp === otp) {
109
+ otpStorage.set(email, { ...record, verified: true });
110
+ return res.status(200).json({ message: "OTP verified", success: true });
111
+ }
112
+
113
+ return res.status(400).json({ message: "Invalid OTP", success: false });
114
+ };
115
+
116
+ // ================= SIGNUP =================
117
+ const signup = async (req, res) => {
118
+ try {
119
+ const { email, password, name } = req.body;
120
+ const record = otpStorage.get(email);
121
+
122
+ if (!record || !record.verified)
123
+ return res.status(400).json({ message: "OTP not verified" });
124
+
125
+ if (!email || !password || !name)
126
+ return res.status(400).json({ message: "Missing fields" });
127
+
128
+ if (password.length < 6)
129
+ return res.status(400).json({ message: "Password too short" });
130
+
131
+ const exists = await userModel.findOne({ email });
132
+ if (exists)
133
+ return res.status(400).json({ message: "User already exists" });
134
+
135
+ const hash = await bcrypt.hash(password, 10);
136
+ const user = await userModel.create({ email, password: hash, name });
137
+
138
+ generateToken(user._id, res);
139
+ otpStorage.delete(email);
140
+
141
+ return res.status(201).json({ message: "User created", success: true, user });
142
+ } catch (err) {
143
+ return res.status(500).json({ message: err.message });
144
+ }
145
+ };
146
+
147
+ // ================= LOGIN =================
148
+ const login = async (req, res) => {
149
+ try {
150
+ const { email, password } = req.body;
151
+ const user = await userModel.findOne({ email });
152
+ if (!user) return res.status(400).json({ message: "User not found" });
153
+
154
+ const valid = await bcrypt.compare(password, user.password);
155
+ if (!valid) return res.status(400).json({ message: "Invalid password" });
156
+
157
+ generateToken(user._id, res);
158
+ return res.status(200).json({ message: "Login successful", success: true, user });
159
+ } catch (err) {
160
+ return res.status(500).json({ message: err.message });
161
+ }
162
+ };
163
+
164
+ const logout = (req, res) => {
165
+ res.cookie("jwt", "", { maxAge: 0 });
166
+ res.status(200).json({ message: "Logout successful" });
167
+ };
168
+
169
+ const checkAuth = (req, res) => {
170
+ res.status(200).json({ success: true, user: req.user });
171
+ };
172
+
173
+ const forgotPassword = async (req, res) => {
174
+ try {
175
+ const { email, newPassword } = req.body;
176
+ if (!email || !newPassword)
177
+ return res.status(400).json({ message: "Missing fields" });
178
+
179
+ const user = await userModel.findOne({ email });
180
+ if (!user) return res.status(400).json({ message: "User not found" });
181
+
182
+ const hash = await bcrypt.hash(newPassword, 10);
183
+ await userModel.findByIdAndUpdate(user._id, { password: hash });
184
+
185
+ res.status(200).json({ message: "Password updated", success: true });
186
+ } catch (err) {
187
+ res.status(500).json({ message: err.message });
188
+ }
189
+ };
190
+
191
+ return {
192
+ sendOtp,
193
+ verifyOTP,
194
+ signup,
195
+ login,
196
+ logout,
197
+ checkAuth,
198
+ forgotPassword,
199
+ };
200
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "authbackendpackage",
3
- "version": "1.1.2",
3
+ "version": "1.1.8",
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
+ }