webortex-auth 1.0.3 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,303 @@
1
+ # Custom User Model Guide
2
+
3
+ This guide shows you how to extend the default User model with your own custom fields.
4
+
5
+ ## Method 1: Using `createCustomUserModel` Helper
6
+
7
+ The easiest way to add custom fields to the User model.
8
+
9
+ ### Example: Adding Phone Number and Role
10
+
11
+ ```javascript
12
+ import express from 'express';
13
+ import mongoose from 'mongoose';
14
+ import { authRoutes, createCustomUserModel } from 'webortex-auth';
15
+
16
+ const app = express();
17
+ app.use(express.json());
18
+
19
+ // Connect to MongoDB
20
+ await mongoose.connect(process.env.MONGO_URI);
21
+
22
+ // Create custom User model with additional fields
23
+ const CustomUser = createCustomUserModel(mongoose, {
24
+ phone: {
25
+ type: String,
26
+ required: false,
27
+ },
28
+ role: {
29
+ type: String,
30
+ enum: ['user', 'admin', 'moderator'],
31
+ default: 'user',
32
+ },
33
+ isVerified: {
34
+ type: Boolean,
35
+ default: false,
36
+ },
37
+ profilePicture: {
38
+ type: String,
39
+ default: null,
40
+ },
41
+ });
42
+
43
+ // Use auth routes with custom User model
44
+ app.use('/api/auth', authRoutes(mongoose, CustomUser));
45
+
46
+ app.listen(3000);
47
+ ```
48
+
49
+ ### Signup Request with Custom Fields
50
+
51
+ ```bash
52
+ curl -X POST http://localhost:3000/api/auth/signup \
53
+ -H "Content-Type: application/json" \
54
+ -d '{
55
+ "name": "John Doe",
56
+ "email": "john@example.com",
57
+ "password": "securePass123",
58
+ "phone": "+1234567890",
59
+ "role": "admin"
60
+ }'
61
+ ```
62
+
63
+ ---
64
+
65
+ ## Method 2: Creating Your Own Model from Scratch
66
+
67
+ For complete control, create your own User model.
68
+
69
+ ### Example: Fully Custom User Model
70
+
71
+ ```javascript
72
+ import mongoose from 'mongoose';
73
+ import bcrypt from 'bcryptjs';
74
+ import { authRoutes } from 'webortex-auth';
75
+
76
+ // Create your own User schema
77
+ const userSchema = new mongoose.Schema({
78
+ // Required fields for authentication
79
+ name: {
80
+ type: String,
81
+ required: true,
82
+ },
83
+ email: {
84
+ type: String,
85
+ required: true,
86
+ unique: true,
87
+ lowercase: true,
88
+ },
89
+ password: {
90
+ type: String,
91
+ required: true,
92
+ select: false,
93
+ },
94
+
95
+ // Your custom fields
96
+ company: {
97
+ type: String,
98
+ required: true,
99
+ },
100
+ department: String,
101
+ employeeId: {
102
+ type: String,
103
+ unique: true,
104
+ },
105
+ permissions: [{
106
+ type: String,
107
+ }],
108
+ }, {
109
+ timestamps: true,
110
+ });
111
+
112
+ // IMPORTANT: Add password hashing middleware
113
+ userSchema.pre('save', async function () {
114
+ if (!this.isModified('password')) return;
115
+
116
+ const salt = await bcrypt.genSalt(10);
117
+ this.password = await bcrypt.hash(this.password, salt);
118
+ });
119
+
120
+ // IMPORTANT: Add password comparison method
121
+ userSchema.methods.comparePassword = async function (candidatePassword) {
122
+ return await bcrypt.compare(candidatePassword, this.password);
123
+ };
124
+
125
+ // Create model
126
+ const CustomUser = mongoose.model('User', userSchema);
127
+
128
+ // Use with auth routes
129
+ app.use('/api/auth', authRoutes(mongoose, CustomUser));
130
+ ```
131
+
132
+ ---
133
+
134
+ ## Method 3: Extending with Schema Options
135
+
136
+ Add schema options like virtuals, indexes, etc.
137
+
138
+ ```javascript
139
+ import { createCustomUserModel } from 'webortex-auth';
140
+
141
+ const CustomUser = createCustomUserModel(
142
+ mongoose,
143
+ // Additional fields
144
+ {
145
+ firstName: String,
146
+ lastName: String,
147
+ dateOfBirth: Date,
148
+ address: {
149
+ street: String,
150
+ city: String,
151
+ country: String,
152
+ zipCode: String,
153
+ },
154
+ },
155
+ // Schema options
156
+ {
157
+ toJSON: { virtuals: true },
158
+ toObject: { virtuals: true },
159
+ }
160
+ );
161
+
162
+ // Add virtual field
163
+ CustomUser.schema.virtual('fullName').get(function () {
164
+ return `${this.firstName} ${this.lastName}`;
165
+ });
166
+
167
+ // Add index
168
+ CustomUser.schema.index({ email: 1, dateOfBirth: 1 });
169
+
170
+ app.use('/api/auth', authRoutes(mongoose, CustomUser));
171
+ ```
172
+
173
+ ---
174
+
175
+ ## Important Requirements
176
+
177
+ When creating a custom User model, ensure it has:
178
+
179
+ ### Required Fields
180
+ - ✅ `name` (String)
181
+ - ✅ `email` (String, unique)
182
+ - ✅ `password` (String, with `select: false`)
183
+
184
+ ### Required Methods
185
+ - ✅ `comparePassword(candidatePassword)` - Returns Promise<boolean>
186
+
187
+ ### Required Middleware
188
+ - ✅ Pre-save hook to hash password with bcrypt
189
+
190
+ ---
191
+
192
+ ## Using Custom User Model in Your App
193
+
194
+ After setting up a custom User model, you can use it anywhere:
195
+
196
+ ```javascript
197
+ import { createCustomUserModel } from 'webortex-auth';
198
+
199
+ // Create the model
200
+ const User = createCustomUserModel(mongoose, {
201
+ role: { type: String, default: 'user' },
202
+ });
203
+
204
+ // Use it in your routes
205
+ app.get('/api/users', async (req, res) => {
206
+ const users = await User.find().select('-password');
207
+ res.json(users);
208
+ });
209
+
210
+ app.get('/api/users/:id', async (req, res) => {
211
+ const user = await User.findById(req.params.id);
212
+ res.json(user);
213
+ });
214
+
215
+ app.patch('/api/users/:id', async (req, res) => {
216
+ const user = await User.findByIdAndUpdate(
217
+ req.params.id,
218
+ req.body,
219
+ { new: true }
220
+ );
221
+ res.json(user);
222
+ });
223
+ ```
224
+
225
+ ---
226
+
227
+ ## Complete Example
228
+
229
+ ```javascript
230
+ import express from 'express';
231
+ import mongoose from 'mongoose';
232
+ import dotenv from 'dotenv';
233
+ import { authRoutes, createCustomUserModel } from 'webortex-auth';
234
+
235
+ dotenv.config();
236
+
237
+ const app = express();
238
+ app.use(express.json());
239
+
240
+ // Connect to MongoDB
241
+ await mongoose.connect(process.env.MONGO_URI);
242
+
243
+ // Create custom User model
244
+ const User = createCustomUserModel(mongoose, {
245
+ phone: String,
246
+ role: {
247
+ type: String,
248
+ enum: ['user', 'admin'],
249
+ default: 'user',
250
+ },
251
+ avatar: String,
252
+ bio: String,
253
+ socialLinks: {
254
+ twitter: String,
255
+ linkedin: String,
256
+ github: String,
257
+ },
258
+ preferences: {
259
+ newsletter: { type: Boolean, default: true },
260
+ notifications: { type: Boolean, default: true },
261
+ },
262
+ });
263
+
264
+ // Auth routes
265
+ app.use('/api/auth', authRoutes(mongoose, User));
266
+
267
+ // Custom user routes
268
+ app.get('/api/users/me', async (req, res) => {
269
+ // Assuming you have auth middleware that sets req.userId
270
+ const user = await User.findById(req.userId);
271
+ res.json(user);
272
+ });
273
+
274
+ app.patch('/api/users/me', async (req, res) => {
275
+ const user = await User.findByIdAndUpdate(
276
+ req.userId,
277
+ { $set: req.body },
278
+ { new: true, runValidators: true }
279
+ );
280
+ res.json(user);
281
+ });
282
+
283
+ app.listen(3000, () => {
284
+ console.log('Server running on port 3000');
285
+ });
286
+ ```
287
+
288
+ ---
289
+
290
+ ## Tips
291
+
292
+ 1. **Don't modify password field** - The package handles password hashing automatically
293
+ 2. **Use select: false for sensitive fields** - Like the password field
294
+ 3. **Add validation** - Use Mongoose validators for your custom fields
295
+ 4. **Create indexes** - For fields you'll query frequently
296
+ 5. **Use virtuals** - For computed properties
297
+ 6. **Keep it simple** - Start with basic fields and add more as needed
298
+
299
+ ---
300
+
301
+ ## Need Help?
302
+
303
+ If you have questions about custom User models, please open an issue on GitHub!
package/README.md CHANGED
@@ -12,6 +12,7 @@ A production-ready, reusable authentication package for Node.js applications usi
12
12
  - 🎯 **Type Safe** - Clean API with factory functions
13
13
  - 🔄 **Reusable** - Use across multiple projects
14
14
  - 🛡️ **Production Ready** - Comprehensive error handling
15
+ - 🎨 **Customizable** - Extend User model with your own fields
15
16
 
16
17
  ## 📦 Installation
17
18
 
@@ -243,6 +244,30 @@ app.use('/api/auth/login', limiter);
243
244
  app.use('/api/auth', authRoutes(mongoose));
244
245
  ```
245
246
 
247
+ ### Custom User Model
248
+
249
+ Extend the default User model with your own fields:
250
+
251
+ ```javascript
252
+ import { authRoutes, createCustomUserModel } from 'webortex-auth';
253
+
254
+ // Create custom User model with additional fields
255
+ const CustomUser = createCustomUserModel(mongoose, {
256
+ phone: String,
257
+ role: {
258
+ type: String,
259
+ enum: ['user', 'admin'],
260
+ default: 'user',
261
+ },
262
+ avatar: String,
263
+ });
264
+
265
+ // Use with auth routes
266
+ app.use('/api/auth', authRoutes(mongoose, CustomUser));
267
+ ```
268
+
269
+ **📖 For detailed examples, see [CUSTOM_USER_MODEL.md](CUSTOM_USER_MODEL.md)**
270
+
246
271
  ## ⚠️ Common Errors & Fixes
247
272
 
248
273
  ### Error: `buffering timed out after 10000ms`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "webortex-auth",
3
- "version": "1.0.3",
3
+ "version": "1.1.0",
4
4
  "description": "Reusable authentication package for Express + MongoDB with dependency injection",
5
5
  "type": "module",
6
6
  "main": "./src/index.js",
@@ -4,10 +4,11 @@ import { createUserModel } from '../models/User.model.js';
4
4
  /**
5
5
  * Creates authentication controllers with injected mongoose instance
6
6
  * @param {Object} mongoose - Connected mongoose instance from consuming app
7
+ * @param {Model} [customUserModel] - Optional custom User model (if not provided, uses default)
7
8
  * @returns {Object} Authentication controllers (signup, login)
8
9
  */
9
- export const createAuthController = (mongoose) => {
10
- const User = createUserModel(mongoose);
10
+ export const createAuthController = (mongoose, customUserModel = null) => {
11
+ const User = customUserModel || createUserModel(mongoose);
11
12
 
12
13
  /**
13
14
  * Signup Controller
package/src/index.js CHANGED
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export { createAuthRoutes as authRoutes } from './routes/auth.routes.js';
9
- export { createUserModel } from './models/User.model.js';
9
+ export { createUserModel, createCustomUserModel } from './models/User.model.js';
@@ -1,43 +1,53 @@
1
1
  import bcrypt from 'bcryptjs';
2
2
 
3
3
  /**
4
- * Creates User model with injected mongoose instance
5
- * @param {Object} mongoose - Connected mongoose instance from consuming app
6
- * @returns {Model} User model
4
+ * Creates a custom User model by extending the base schema
5
+ * @param {Object} mongoose - Connected mongoose instance
6
+ * @param {Object} additionalFields - Additional schema fields to add
7
+ * @param {Object} [schemaOptions] - Additional schema options
8
+ * @returns {Model} Extended User model
7
9
  */
8
- export const createUserModel = (mongoose) => {
10
+ export const createCustomUserModel = (mongoose, additionalFields = {}, schemaOptions = {}) => {
9
11
  // Prevent model recompilation error
10
12
  if (mongoose.models.User) {
11
13
  return mongoose.models.User;
12
14
  }
13
15
 
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
- },
16
+ // Base user fields
17
+ const baseFields = {
18
+ name: {
19
+ type: String,
20
+ required: [true, 'Name is required'],
21
+ trim: true,
22
+ },
23
+ email: {
24
+ type: String,
25
+ required: [true, 'Email is required'],
26
+ unique: true,
27
+ lowercase: true,
28
+ trim: true,
29
+ match: [
30
+ /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/,
31
+ 'Please provide a valid email',
32
+ ],
33
+ },
34
+ password: {
35
+ type: String,
36
+ required: [true, 'Password is required'],
37
+ minlength: [6, 'Password must be at least 6 characters'],
38
+ select: false, // Don't return password by default
38
39
  },
40
+ };
41
+
42
+ // Merge base fields with additional fields
43
+ const schemaFields = { ...baseFields, ...additionalFields };
44
+
45
+ // Create schema with merged fields
46
+ const userSchema = new mongoose.Schema(
47
+ schemaFields,
39
48
  {
40
49
  timestamps: true,
50
+ ...schemaOptions,
41
51
  }
42
52
  );
43
53
 
@@ -63,3 +73,12 @@ export const createUserModel = (mongoose) => {
63
73
 
64
74
  return mongoose.model('User', userSchema);
65
75
  };
76
+
77
+ /**
78
+ * Creates User model with injected mongoose instance
79
+ * @param {Object} mongoose - Connected mongoose instance from consuming app
80
+ * @returns {Model} User model
81
+ */
82
+ export const createUserModel = (mongoose) => {
83
+ return createCustomUserModel(mongoose);
84
+ };
@@ -4,11 +4,12 @@ import { createAuthController } from '../controllers/auth.controller.js';
4
4
  /**
5
5
  * Creates authentication routes with injected mongoose instance
6
6
  * @param {Object} mongoose - Connected mongoose instance from consuming app
7
+ * @param {Model} [customUserModel] - Optional custom User model (if not provided, uses default)
7
8
  * @returns {Router} Express router with auth routes
8
9
  */
9
- export const createAuthRoutes = (mongoose) => {
10
+ export const createAuthRoutes = (mongoose, customUserModel = null) => {
10
11
  const router = express.Router();
11
- const { signup, login } = createAuthController(mongoose);
12
+ const { signup, login } = createAuthController(mongoose, customUserModel);
12
13
 
13
14
  // POST /signup - Register new user
14
15
  router.post('/signup', signup);