webortex-auth 1.0.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/.env.example ADDED
@@ -0,0 +1,15 @@
1
+ # Example .env file for consuming application
2
+ # Copy this to .env and update with your values
3
+
4
+ # MongoDB Connection
5
+ MONGO_URI=mongodb://localhost:27017/your-database-name
6
+
7
+ # JWT Configuration (REQUIRED)
8
+ JWT_SECRET=your-super-secret-jwt-key-change-this-to-something-secure
9
+
10
+ # JWT Token Expiration (Optional, default: 24h)
11
+ JWT_EXPIRES_IN=24h
12
+
13
+ # Server Configuration
14
+ PORT=3000
15
+ NODE_ENV=development
package/PUBLISHING.md ADDED
@@ -0,0 +1,303 @@
1
+ # Publishing webortex-auth to npm
2
+
3
+ ## Prerequisites
4
+
5
+ Before publishing, ensure you have:
6
+ - ✅ An npm account (create one at https://www.npmjs.com/signup)
7
+ - ✅ Node.js and npm installed
8
+ - ✅ Package is ready and tested
9
+
10
+ ## Step-by-Step Publishing Guide
11
+
12
+ ### 1. Create npm Account (if you don't have one)
13
+
14
+ Visit https://www.npmjs.com/signup and create an account.
15
+
16
+ ---
17
+
18
+ ### 2. Login to npm
19
+
20
+ Open your terminal in the package directory and login:
21
+
22
+ ```bash
23
+ npm login
24
+ ```
25
+
26
+ You'll be prompted for:
27
+ - Username
28
+ - Password
29
+ - Email (this will be public)
30
+ - One-time password (if 2FA is enabled)
31
+
32
+ **Verify login:**
33
+ ```bash
34
+ npm whoami
35
+ ```
36
+
37
+ ---
38
+
39
+ ### 3. Check Package Name Availability
40
+
41
+ Before publishing, verify the package name is available:
42
+
43
+ ```bash
44
+ npm search webortex-auth
45
+ ```
46
+
47
+ If the name is taken, you'll need to:
48
+ - Choose a different name, OR
49
+ - Use a scoped package: `@your-username/webortex-auth`
50
+
51
+ **To use a scoped package**, update `package.json`:
52
+ ```json
53
+ {
54
+ "name": "@your-username/webortex-auth",
55
+ ...
56
+ }
57
+ ```
58
+
59
+ ---
60
+
61
+ ### 4. Verify Package Contents
62
+
63
+ Check what files will be published:
64
+
65
+ ```bash
66
+ npm pack --dry-run
67
+ ```
68
+
69
+ This shows you exactly what will be included in the package. Verify:
70
+ - ✅ `src/` directory is included
71
+ - ✅ `README.md` is included
72
+ - ✅ `package.json` is included
73
+ - ❌ `node_modules/` is NOT included
74
+ - ❌ `.env` files are NOT included
75
+
76
+ ---
77
+
78
+ ### 5. Test Package Locally (Recommended)
79
+
80
+ Before publishing, test the package locally:
81
+
82
+ ```bash
83
+ # In webortex-auth directory
84
+ npm pack
85
+ ```
86
+
87
+ This creates a `.tgz` file (e.g., `webortex-auth-1.0.0.tgz`).
88
+
89
+ **Test in another project:**
90
+ ```bash
91
+ # Create test project
92
+ mkdir test-webortex-auth
93
+ cd test-webortex-auth
94
+ npm init -y
95
+
96
+ # Install the local package
97
+ npm install ../webortex-auth/webortex-auth-1.0.0.tgz
98
+
99
+ # Test it works
100
+ ```
101
+
102
+ ---
103
+
104
+ ### 6. Update Package Version (for future releases)
105
+
106
+ For the first publish, version `1.0.0` is fine. For future updates:
107
+
108
+ ```bash
109
+ # Patch release (1.0.0 -> 1.0.1) - bug fixes
110
+ npm version patch
111
+
112
+ # Minor release (1.0.0 -> 1.1.0) - new features
113
+ npm version minor
114
+
115
+ # Major release (1.0.0 -> 2.0.0) - breaking changes
116
+ npm version major
117
+ ```
118
+
119
+ ---
120
+
121
+ ### 7. Publish to npm
122
+
123
+ **For public package (free):**
124
+ ```bash
125
+ npm publish
126
+ ```
127
+
128
+ **For scoped package (public):**
129
+ ```bash
130
+ npm publish --access public
131
+ ```
132
+
133
+ **For private package (requires paid account):**
134
+ ```bash
135
+ npm publish --access restricted
136
+ ```
137
+
138
+ ---
139
+
140
+ ### 8. Verify Publication
141
+
142
+ After publishing, verify your package:
143
+
144
+ 1. **Visit npm website:**
145
+ ```
146
+ https://www.npmjs.com/package/webortex-auth
147
+ ```
148
+
149
+ 2. **Install from npm:**
150
+ ```bash
151
+ npm install webortex-auth
152
+ ```
153
+
154
+ 3. **Check package info:**
155
+ ```bash
156
+ npm info webortex-auth
157
+ ```
158
+
159
+ ---
160
+
161
+ ## Common Issues & Solutions
162
+
163
+ ### Issue: Package name already exists
164
+
165
+ **Solution:** Use a scoped package name:
166
+ ```json
167
+ {
168
+ "name": "@your-username/webortex-auth"
169
+ }
170
+ ```
171
+
172
+ ### Issue: "You do not have permission to publish"
173
+
174
+ **Solutions:**
175
+ - Verify you're logged in: `npm whoami`
176
+ - Use scoped package with `--access public`
177
+ - Check if package name is already taken
178
+
179
+ ### Issue: "npm ERR! 402 Payment Required"
180
+
181
+ **Solution:** You're trying to publish a private scoped package. Either:
182
+ - Publish as public: `npm publish --access public`
183
+ - Upgrade to npm Pro for private packages
184
+
185
+ ### Issue: Files missing in published package
186
+
187
+ **Solution:** Check your `.npmignore` and ensure important files aren't excluded.
188
+
189
+ ---
190
+
191
+ ## Post-Publication Checklist
192
+
193
+ After successful publication:
194
+
195
+ - [ ] Verify package appears on npm website
196
+ - [ ] Test installation: `npm install webortex-auth`
197
+ - [ ] Check README renders correctly on npm
198
+ - [ ] Add repository URL to package.json (if using GitHub)
199
+ - [ ] Add badges to README (version, downloads, license)
200
+ - [ ] Share with the community!
201
+
202
+ ---
203
+
204
+ ## Updating Your Package
205
+
206
+ When you make changes and want to publish an update:
207
+
208
+ 1. **Make your changes**
209
+ 2. **Update version:**
210
+ ```bash
211
+ npm version patch # or minor/major
212
+ ```
213
+ 3. **Publish:**
214
+ ```bash
215
+ npm publish
216
+ ```
217
+
218
+ ---
219
+
220
+ ## Unpublishing (Use with Caution)
221
+
222
+ You can unpublish within 72 hours:
223
+
224
+ ```bash
225
+ # Unpublish specific version
226
+ npm unpublish webortex-auth@1.0.0
227
+
228
+ # Unpublish entire package (only within 72 hours)
229
+ npm unpublish webortex-auth --force
230
+ ```
231
+
232
+ ⚠️ **Warning:** Unpublishing is discouraged as it breaks dependencies for others.
233
+
234
+ ---
235
+
236
+ ## Optional: Add to package.json
237
+
238
+ Consider adding these fields before publishing:
239
+
240
+ ```json
241
+ {
242
+ "repository": {
243
+ "type": "git",
244
+ "url": "https://github.com/your-username/webortex-auth.git"
245
+ },
246
+ "bugs": {
247
+ "url": "https://github.com/your-username/webortex-auth/issues"
248
+ },
249
+ "homepage": "https://github.com/your-username/webortex-auth#readme"
250
+ }
251
+ ```
252
+
253
+ ---
254
+
255
+ ## Quick Command Reference
256
+
257
+ ```bash
258
+ # Login
259
+ npm login
260
+
261
+ # Check login
262
+ npm whoami
263
+
264
+ # Preview package contents
265
+ npm pack --dry-run
266
+
267
+ # Test package locally
268
+ npm pack
269
+
270
+ # Publish
271
+ npm publish
272
+
273
+ # Publish scoped package as public
274
+ npm publish --access public
275
+
276
+ # Update version
277
+ npm version patch|minor|major
278
+
279
+ # View package info
280
+ npm info webortex-auth
281
+ ```
282
+
283
+ ---
284
+
285
+ ## 🎉 Ready to Publish?
286
+
287
+ Run these commands in order:
288
+
289
+ ```bash
290
+ # 1. Navigate to package directory
291
+ cd "d:\Prem Secure Solutions\webortex-auth"
292
+
293
+ # 2. Login to npm
294
+ npm login
295
+
296
+ # 3. Preview what will be published
297
+ npm pack --dry-run
298
+
299
+ # 4. Publish!
300
+ npm publish
301
+ ```
302
+
303
+ Good luck! 🚀
package/README.md ADDED
@@ -0,0 +1,391 @@
1
+ # webortex-auth
2
+
3
+ A production-ready, reusable authentication package for Node.js applications using Express and MongoDB (Mongoose) with dependency injection pattern.
4
+
5
+ ## ✨ Features
6
+
7
+ - 🔐 **Secure Authentication** - JWT-based signup and login
8
+ - 💉 **Dependency Injection** - No internal MongoDB connections
9
+ - 🚀 **Zero Configuration** - Works out of the box
10
+ - 🔒 **Password Hashing** - Automatic bcrypt hashing
11
+ - ⚡ **ES Modules** - Modern JavaScript support
12
+ - 🎯 **Type Safe** - Clean API with factory functions
13
+ - 🔄 **Reusable** - Use across multiple projects
14
+ - 🛡️ **Production Ready** - Comprehensive error handling
15
+
16
+ ## 📦 Installation
17
+
18
+ ```bash
19
+ npm install webortex-auth
20
+ ```
21
+
22
+ ## 🚀 Quick Start
23
+
24
+ ```javascript
25
+ import express from 'express';
26
+ import mongoose from 'mongoose';
27
+ import { authRoutes } from 'webortex-auth';
28
+
29
+ const app = express();
30
+ app.use(express.json());
31
+
32
+ // 1. Connect to MongoDB FIRST
33
+ await mongoose.connect(process.env.MONGO_URI);
34
+
35
+ // 2. Pass connected mongoose instance to the package
36
+ app.use('/api/auth', authRoutes(mongoose));
37
+
38
+ app.listen(3000, () => {
39
+ console.log('Server running on port 3000');
40
+ });
41
+ ```
42
+
43
+ ## 🔧 Environment Variables
44
+
45
+ Create a `.env` file in your project root:
46
+
47
+ ```env
48
+ MONGO_URI=mongodb://localhost:27017/your-database
49
+ JWT_SECRET=your-super-secret-jwt-key-change-this
50
+ JWT_EXPIRES_IN=24h
51
+ NODE_ENV=development
52
+ ```
53
+
54
+ **Required:**
55
+ - `JWT_SECRET` - Secret key for JWT token generation
56
+
57
+ **Optional:**
58
+ - `JWT_EXPIRES_IN` - Token expiration time (default: `24h`)
59
+ - `NODE_ENV` - Environment mode (shows detailed errors in `development`)
60
+
61
+ ## 📡 API Endpoints
62
+
63
+ ### POST `/signup`
64
+
65
+ Register a new user.
66
+
67
+ **Request Body:**
68
+ ```json
69
+ {
70
+ "name": "John Doe",
71
+ "email": "john@example.com",
72
+ "password": "securePassword123"
73
+ }
74
+ ```
75
+
76
+ **Success Response (201):**
77
+ ```json
78
+ {
79
+ "success": true,
80
+ "message": "User registered successfully",
81
+ "data": {
82
+ "user": {
83
+ "id": "507f1f77bcf86cd799439011",
84
+ "name": "John Doe",
85
+ "email": "john@example.com",
86
+ "createdAt": "2025-12-28T08:30:00.000Z"
87
+ }
88
+ }
89
+ }
90
+ ```
91
+
92
+ **Error Response (409 - Duplicate Email):**
93
+ ```json
94
+ {
95
+ "success": false,
96
+ "message": "User with this email already exists"
97
+ }
98
+ ```
99
+
100
+ ---
101
+
102
+ ### POST `/login`
103
+
104
+ Authenticate a user and receive JWT token.
105
+
106
+ **Request Body:**
107
+ ```json
108
+ {
109
+ "email": "john@example.com",
110
+ "password": "securePassword123"
111
+ }
112
+ ```
113
+
114
+ **Success Response (200):**
115
+ ```json
116
+ {
117
+ "success": true,
118
+ "message": "Login successful",
119
+ "data": {
120
+ "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
121
+ "user": {
122
+ "id": "507f1f77bcf86cd799439011",
123
+ "name": "John Doe",
124
+ "email": "john@example.com"
125
+ }
126
+ }
127
+ }
128
+ ```
129
+
130
+ **Error Response (401 - Invalid Credentials):**
131
+ ```json
132
+ {
133
+ "success": false,
134
+ "message": "Invalid email or password"
135
+ }
136
+ ```
137
+
138
+ ## 💡 Usage Examples
139
+
140
+ ### Complete Express App
141
+
142
+ ```javascript
143
+ import express from 'express';
144
+ import mongoose from 'mongoose';
145
+ import dotenv from 'dotenv';
146
+ import { authRoutes } from 'webortex-auth';
147
+
148
+ dotenv.config();
149
+
150
+ const app = express();
151
+ app.use(express.json());
152
+
153
+ // Connect to MongoDB
154
+ const connectDB = async () => {
155
+ try {
156
+ await mongoose.connect(process.env.MONGO_URI);
157
+ console.log('MongoDB connected successfully');
158
+ } catch (error) {
159
+ console.error('MongoDB connection error:', error);
160
+ process.exit(1);
161
+ }
162
+ };
163
+
164
+ await connectDB();
165
+
166
+ // Use auth routes
167
+ app.use('/api/auth', authRoutes(mongoose));
168
+
169
+ // Health check
170
+ app.get('/health', (req, res) => {
171
+ res.json({ status: 'ok' });
172
+ });
173
+
174
+ const PORT = process.env.PORT || 3000;
175
+ app.listen(PORT, () => {
176
+ console.log(`Server running on port ${PORT}`);
177
+ });
178
+ ```
179
+
180
+ ### Using with Custom Routes
181
+
182
+ ```javascript
183
+ import { authRoutes } from 'webortex-auth';
184
+
185
+ // Mount on different path
186
+ app.use('/auth', authRoutes(mongoose));
187
+
188
+ // Or with route prefix
189
+ app.use('/v1/authentication', authRoutes(mongoose));
190
+ ```
191
+
192
+ ### Testing with cURL
193
+
194
+ **Signup:**
195
+ ```bash
196
+ curl -X POST http://localhost:3000/api/auth/signup \
197
+ -H "Content-Type: application/json" \
198
+ -d '{
199
+ "name": "John Doe",
200
+ "email": "john@example.com",
201
+ "password": "securePassword123"
202
+ }'
203
+ ```
204
+
205
+ **Login:**
206
+ ```bash
207
+ curl -X POST http://localhost:3000/api/auth/login \
208
+ -H "Content-Type: application/json" \
209
+ -d '{
210
+ "email": "john@example.com",
211
+ "password": "securePassword123"
212
+ }'
213
+ ```
214
+
215
+ ## 🔍 Advanced Usage
216
+
217
+ ### Accessing User Model
218
+
219
+ If you need direct access to the User model:
220
+
221
+ ```javascript
222
+ import { createUserModel } from 'webortex-auth';
223
+
224
+ const User = createUserModel(mongoose);
225
+
226
+ // Now you can use the User model
227
+ const users = await User.find();
228
+ ```
229
+
230
+ ### Custom Middleware
231
+
232
+ Add middleware before auth routes:
233
+
234
+ ```javascript
235
+ import rateLimit from 'express-rate-limit';
236
+
237
+ const limiter = rateLimit({
238
+ windowMs: 15 * 60 * 1000, // 15 minutes
239
+ max: 5 // limit each IP to 5 requests per windowMs
240
+ });
241
+
242
+ app.use('/api/auth/login', limiter);
243
+ app.use('/api/auth', authRoutes(mongoose));
244
+ ```
245
+
246
+ ## ⚠️ Common Errors & Fixes
247
+
248
+ ### Error: `buffering timed out after 10000ms`
249
+
250
+ **Cause:** Mongoose is not connected before using the package.
251
+
252
+ **Fix:** Ensure you connect to MongoDB before using `authRoutes`:
253
+
254
+ ```javascript
255
+ // ✅ Correct
256
+ await mongoose.connect(process.env.MONGO_URI);
257
+ app.use('/api/auth', authRoutes(mongoose));
258
+
259
+ // ❌ Wrong
260
+ app.use('/api/auth', authRoutes(mongoose));
261
+ await mongoose.connect(process.env.MONGO_URI);
262
+ ```
263
+
264
+ ---
265
+
266
+ ### Error: `JWT_SECRET is not defined`
267
+
268
+ **Cause:** Missing `JWT_SECRET` environment variable.
269
+
270
+ **Fix:** Add to your `.env` file:
271
+
272
+ ```env
273
+ JWT_SECRET=your-secret-key-here
274
+ ```
275
+
276
+ ---
277
+
278
+ ### Error: `E11000 duplicate key error`
279
+
280
+ **Cause:** User with the email already exists.
281
+
282
+ **Fix:** This is expected behavior. The API returns a 409 status code. Handle it in your client:
283
+
284
+ ```javascript
285
+ const response = await fetch('/api/auth/signup', {
286
+ method: 'POST',
287
+ body: JSON.stringify(userData)
288
+ });
289
+
290
+ if (response.status === 409) {
291
+ console.log('Email already registered');
292
+ }
293
+ ```
294
+
295
+ ---
296
+
297
+ ### Error: `Cannot find module 'mongoose'`
298
+
299
+ **Cause:** Mongoose is a peer dependency and must be installed separately.
300
+
301
+ **Fix:**
302
+
303
+ ```bash
304
+ npm install mongoose
305
+ ```
306
+
307
+ ## 🏗️ Package Structure
308
+
309
+ ```
310
+ webortex-auth/
311
+ ├── src/
312
+ │ ├── controllers/
313
+ │ │ └── auth.controller.js # Signup & Login logic
314
+ │ ├── models/
315
+ │ │ └── User.model.js # User schema with password hashing
316
+ │ ├── routes/
317
+ │ │ └── auth.routes.js # Express routes
318
+ │ └── index.js # Public API exports
319
+ ├── package.json
320
+ ├── README.md
321
+ └── .npmignore
322
+ ```
323
+
324
+ ## 🛡️ Security Best Practices
325
+
326
+ 1. **Never commit `.env` files** - Add to `.gitignore`
327
+ 2. **Use strong JWT secrets** - Generate with: `node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"`
328
+ 3. **Enable HTTPS in production** - Use SSL/TLS certificates
329
+ 4. **Add rate limiting** - Prevent brute force attacks
330
+ 5. **Validate input** - Consider adding validation middleware
331
+ 6. **Use environment variables** - Never hardcode secrets
332
+
333
+ ## 📝 User Schema
334
+
335
+ The package creates a User model with the following schema:
336
+
337
+ ```javascript
338
+ {
339
+ name: String, // Required, trimmed
340
+ email: String, // Required, unique, lowercase, validated
341
+ password: String, // Required, hashed with bcrypt, min 6 chars
342
+ createdAt: Date, // Auto-generated
343
+ updatedAt: Date // Auto-generated
344
+ }
345
+ ```
346
+
347
+ ## 🔄 How It Works
348
+
349
+ 1. **Dependency Injection**: The package receives a connected mongoose instance from your app
350
+ 2. **Model Creation**: User model is created using the injected mongoose instance
351
+ 3. **No Internal Connections**: Package never calls `mongoose.connect()`
352
+ 4. **Factory Pattern**: All exports are factory functions that accept mongoose
353
+ 5. **Single Instance**: Prevents multiple mongoose instances and buffering issues
354
+
355
+ ## 🚀 Why Dependency Injection?
356
+
357
+ **Traditional packages** create their own mongoose connection:
358
+ ```javascript
359
+ // ❌ Creates separate connection
360
+ import auth from 'some-auth-package';
361
+ ```
362
+
363
+ **This package** uses your existing connection:
364
+ ```javascript
365
+ // ✅ Uses your connection
366
+ import { authRoutes } from 'webortex-auth';
367
+ app.use('/api/auth', authRoutes(mongoose));
368
+ ```
369
+
370
+ **Benefits:**
371
+ - ✅ No buffering timeout errors
372
+ - ✅ No multiple mongoose instances
373
+ - ✅ No peerDependency conflicts
374
+ - ✅ Works in monorepos
375
+ - ✅ Full control over connection
376
+
377
+ ## 📄 License
378
+
379
+ MIT
380
+
381
+ ## 🤝 Contributing
382
+
383
+ Contributions are welcome! Please feel free to submit a Pull Request.
384
+
385
+ ## 📧 Support
386
+
387
+ For issues and questions, please open an issue on GitHub.
388
+
389
+ ---
390
+
391
+ **Made with ❤️ by WebOrtex**
@@ -0,0 +1,70 @@
1
+ import express from 'express';
2
+ import mongoose from 'mongoose';
3
+ import dotenv from 'dotenv';
4
+ import { authRoutes } from 'webortex-auth';
5
+
6
+ // Load environment variables
7
+ dotenv.config();
8
+
9
+ const app = express();
10
+
11
+ // Middleware
12
+ app.use(express.json());
13
+ app.use(express.urlencoded({ extended: true }));
14
+
15
+ // Connect to MongoDB
16
+ const connectDB = async () => {
17
+ try {
18
+ await mongoose.connect(process.env.MONGO_URI, {
19
+ useNewUrlParser: true,
20
+ useUnifiedTopology: true,
21
+ });
22
+ console.log('✅ MongoDB connected successfully');
23
+ } catch (error) {
24
+ console.error('❌ MongoDB connection error:', error.message);
25
+ process.exit(1);
26
+ }
27
+ };
28
+
29
+ // Initialize database connection
30
+ await connectDB();
31
+
32
+ // Health check endpoint
33
+ app.get('/health', (req, res) => {
34
+ res.json({
35
+ status: 'ok',
36
+ timestamp: new Date().toISOString(),
37
+ database: mongoose.connection.readyState === 1 ? 'connected' : 'disconnected',
38
+ });
39
+ });
40
+
41
+ // Use webortex-auth routes
42
+ // IMPORTANT: Pass the connected mongoose instance
43
+ app.use('/api/auth', authRoutes(mongoose));
44
+
45
+ // 404 handler
46
+ app.use((req, res) => {
47
+ res.status(404).json({
48
+ success: false,
49
+ message: 'Route not found',
50
+ });
51
+ });
52
+
53
+ // Error handler
54
+ app.use((err, req, res, next) => {
55
+ console.error('Error:', err);
56
+ res.status(500).json({
57
+ success: false,
58
+ message: 'Internal server error',
59
+ error: process.env.NODE_ENV === 'development' ? err.message : undefined,
60
+ });
61
+ });
62
+
63
+ // Start server
64
+ const PORT = process.env.PORT || 3000;
65
+ app.listen(PORT, () => {
66
+ console.log(`🚀 Server running on http://localhost:${PORT}`);
67
+ console.log(`📡 Auth endpoints available at http://localhost:${PORT}/api/auth`);
68
+ console.log(` - POST /api/auth/signup`);
69
+ console.log(` - POST /api/auth/login`);
70
+ });
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "webortex-auth",
3
+ "version": "1.0.0",
4
+ "description": "Reusable authentication package for Express + MongoDB with dependency injection",
5
+ "type": "module",
6
+ "main": "./src/index.js",
7
+ "exports": {
8
+ ".": "./src/index.js"
9
+ },
10
+ "scripts": {
11
+ "test": "echo \"Error: no test specified\" && exit 1"
12
+ },
13
+ "keywords": [
14
+ "authentication",
15
+ "express",
16
+ "mongoose",
17
+ "jwt",
18
+ "auth",
19
+ "login",
20
+ "signup",
21
+ "mongodb"
22
+ ],
23
+ "author": "WebOrtex",
24
+ "license": "MIT",
25
+ "peerDependencies": {
26
+ "express": "^4.18.0",
27
+ "mongoose": "^7.0.0 || ^8.0.0"
28
+ },
29
+ "dependencies": {
30
+ "bcryptjs": "^2.4.3",
31
+ "jsonwebtoken": "^9.0.2"
32
+ },
33
+ "engines": {
34
+ "node": ">=16.0.0",
35
+ "npm": ">=9.0.0"
36
+ }
37
+ }
@@ -0,0 +1,156 @@
1
+ import jwt from 'jsonwebtoken';
2
+ import { createUserModel } from '../models/User.model.js';
3
+
4
+ /**
5
+ * Creates authentication controllers with injected mongoose instance
6
+ * @param {Object} mongoose - Connected mongoose instance from consuming app
7
+ * @returns {Object} Authentication controllers (signup, login)
8
+ */
9
+ export const createAuthController = (mongoose) => {
10
+ const User = createUserModel(mongoose);
11
+
12
+ /**
13
+ * Signup Controller
14
+ * Creates a new user account
15
+ */
16
+ const signup = async (req, res) => {
17
+ try {
18
+ const { name, email, password } = req.body;
19
+
20
+ // Validate required fields
21
+ if (!name || !email || !password) {
22
+ return res.status(400).json({
23
+ success: false,
24
+ message: 'Please provide name, email, and password',
25
+ });
26
+ }
27
+
28
+ // Check if user already exists
29
+ const existingUser = await User.findOne({ email });
30
+ if (existingUser) {
31
+ return res.status(409).json({
32
+ success: false,
33
+ message: 'User with this email already exists',
34
+ });
35
+ }
36
+
37
+ // Create new user (password will be hashed by pre-save hook)
38
+ const user = await User.create({
39
+ name,
40
+ email,
41
+ password,
42
+ });
43
+
44
+ // Return success response without password
45
+ return res.status(201).json({
46
+ success: true,
47
+ message: 'User registered successfully',
48
+ data: {
49
+ user: {
50
+ id: user._id,
51
+ name: user.name,
52
+ email: user.email,
53
+ createdAt: user.createdAt,
54
+ },
55
+ },
56
+ });
57
+ } catch (error) {
58
+ // Handle duplicate key error (E11000)
59
+ if (error.code === 11000) {
60
+ return res.status(409).json({
61
+ success: false,
62
+ message: 'User with this email already exists',
63
+ });
64
+ }
65
+
66
+ // Handle validation errors
67
+ if (error.name === 'ValidationError') {
68
+ const messages = Object.values(error.errors).map((err) => err.message);
69
+ return res.status(400).json({
70
+ success: false,
71
+ message: messages.join(', '),
72
+ });
73
+ }
74
+
75
+ // Generic error
76
+ return res.status(500).json({
77
+ success: false,
78
+ message: 'Error creating user',
79
+ error: process.env.NODE_ENV === 'development' ? error.message : undefined,
80
+ });
81
+ }
82
+ };
83
+
84
+ /**
85
+ * Login Controller
86
+ * Authenticates user and returns JWT token
87
+ */
88
+ const login = async (req, res) => {
89
+ try {
90
+ const { email, password } = req.body;
91
+
92
+ // Validate required fields
93
+ if (!email || !password) {
94
+ return res.status(400).json({
95
+ success: false,
96
+ message: 'Please provide email and password',
97
+ });
98
+ }
99
+
100
+ // Find user and include password field
101
+ const user = await User.findOne({ email }).select('+password');
102
+ if (!user) {
103
+ return res.status(401).json({
104
+ success: false,
105
+ message: 'Invalid email or password',
106
+ });
107
+ }
108
+
109
+ // Compare passwords
110
+ const isPasswordValid = await user.comparePassword(password);
111
+ if (!isPasswordValid) {
112
+ return res.status(401).json({
113
+ success: false,
114
+ message: 'Invalid email or password',
115
+ });
116
+ }
117
+
118
+ // Check if JWT_SECRET is defined
119
+ if (!process.env.JWT_SECRET) {
120
+ throw new Error('JWT_SECRET is not defined in environment variables');
121
+ }
122
+
123
+ // Generate JWT token
124
+ const token = jwt.sign(
125
+ { userId: user._id, email: user.email },
126
+ process.env.JWT_SECRET,
127
+ { expiresIn: process.env.JWT_EXPIRES_IN || '24h' }
128
+ );
129
+
130
+ // Return success response with token
131
+ return res.status(200).json({
132
+ success: true,
133
+ message: 'Login successful',
134
+ data: {
135
+ token,
136
+ user: {
137
+ id: user._id,
138
+ name: user.name,
139
+ email: user.email,
140
+ },
141
+ },
142
+ });
143
+ } catch (error) {
144
+ return res.status(500).json({
145
+ success: false,
146
+ message: 'Error during login',
147
+ error: process.env.NODE_ENV === 'development' ? error.message : undefined,
148
+ });
149
+ }
150
+ };
151
+
152
+ return {
153
+ signup,
154
+ login,
155
+ };
156
+ };
package/src/index.js ADDED
@@ -0,0 +1,9 @@
1
+ /**
2
+ * webortex-auth - Reusable authentication package
3
+ *
4
+ * Main entry point for the package
5
+ * Exports factory functions that accept injected mongoose instance
6
+ */
7
+
8
+ export { createAuthRoutes as authRoutes } from './routes/auth.routes.js';
9
+ export { createUserModel } from './models/User.model.js';
@@ -0,0 +1,70 @@
1
+ import bcrypt from 'bcryptjs';
2
+
3
+ /**
4
+ * Creates User model with injected mongoose instance
5
+ * @param {Object} mongoose - Connected mongoose instance from consuming app
6
+ * @returns {Model} User model
7
+ */
8
+ export const createUserModel = (mongoose) => {
9
+ // Prevent model recompilation error
10
+ if (mongoose.models.User) {
11
+ return mongoose.models.User;
12
+ }
13
+
14
+ const userSchema = new mongoose.Schema(
15
+ {
16
+ name: {
17
+ type: String,
18
+ required: [true, 'Name is required'],
19
+ trim: true,
20
+ },
21
+ email: {
22
+ type: String,
23
+ required: [true, 'Email is required'],
24
+ unique: true,
25
+ lowercase: true,
26
+ trim: true,
27
+ match: [
28
+ /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/,
29
+ 'Please provide a valid email',
30
+ ],
31
+ },
32
+ password: {
33
+ type: String,
34
+ required: [true, 'Password is required'],
35
+ minlength: [6, 'Password must be at least 6 characters'],
36
+ select: false, // Don't return password by default
37
+ },
38
+ },
39
+ {
40
+ timestamps: true,
41
+ }
42
+ );
43
+
44
+ // Hash password before saving
45
+ userSchema.pre('save', async function (next) {
46
+ // Only hash if password is modified
47
+ if (!this.isModified('password')) {
48
+ return next();
49
+ }
50
+
51
+ try {
52
+ const salt = await bcrypt.genSalt(10);
53
+ this.password = await bcrypt.hash(this.password, salt);
54
+ next();
55
+ } catch (error) {
56
+ next(error);
57
+ }
58
+ });
59
+
60
+ // Method to compare passwords
61
+ userSchema.methods.comparePassword = async function (candidatePassword) {
62
+ try {
63
+ return await bcrypt.compare(candidatePassword, this.password);
64
+ } catch (error) {
65
+ throw new Error('Password comparison failed');
66
+ }
67
+ };
68
+
69
+ return mongoose.model('User', userSchema);
70
+ };
@@ -0,0 +1,20 @@
1
+ import express from 'express';
2
+ import { createAuthController } from '../controllers/auth.controller.js';
3
+
4
+ /**
5
+ * Creates authentication routes with injected mongoose instance
6
+ * @param {Object} mongoose - Connected mongoose instance from consuming app
7
+ * @returns {Router} Express router with auth routes
8
+ */
9
+ export const createAuthRoutes = (mongoose) => {
10
+ const router = express.Router();
11
+ const { signup, login } = createAuthController(mongoose);
12
+
13
+ // POST /signup - Register new user
14
+ router.post('/signup', signup);
15
+
16
+ // POST /login - Authenticate user
17
+ router.post('/login', login);
18
+
19
+ return router;
20
+ };
Binary file