@latanda/auth-middleware 1.0.1

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/CHANGELOG.md ADDED
@@ -0,0 +1,15 @@
1
+ # Changelog
2
+
3
+ ## 1.0.1 - 2026-05-12
4
+
5
+ - Renamed scope: `@perks/auth-middleware` → `@latanda/auth-middleware`. The old package is deprecated with a redirect message.
6
+ - **Fixed broken `main` field**: 1.0.0 pointed at `lib/index.js` which was never built or committed (`lib/` is gitignored). Changed to `src/index.js` so `require("@latanda/auth-middleware")` actually works. The old `@perks` 1.0.0 was effectively unusable due to this bug.
7
+ - Added explicit `files` field to package.json for predictable npm tarballs.
8
+ - Removed stale `types` field (it pointed at the same nonexistent `lib/index.d.ts`).
9
+ - Fixed author email metadata (was a placeholder).
10
+ - Added npm version, downloads, license, and node badges to README.
11
+ - No API changes.
12
+
13
+ ## 1.0.0 - 2025-10-22
14
+
15
+ - Initial release. JWT auth, RBAC, PostgreSQL integration, Nginx-friendly. Battle-tested at latanda.online.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Narjell Ebanks / La Tanda
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/MIGRATION.md ADDED
@@ -0,0 +1,29 @@
1
+ # Migrating from @perks/auth-middleware to @latanda/auth-middleware
2
+
3
+ The package was renamed in v1.0.1 to align with the La Tanda project brand. No code changes are required other than updating the package name in your dependencies.
4
+
5
+ ## Quick upgrade
6
+
7
+ ```bash
8
+ npm uninstall @perks/auth-middleware
9
+ npm install @latanda/auth-middleware
10
+ ```
11
+
12
+ ## require() / import changes
13
+
14
+ ```js
15
+ // Before
16
+ const auth = require('@perks/auth-middleware');
17
+ // After
18
+ const auth = require('@latanda/auth-middleware');
19
+ ```
20
+
21
+ The exported API is identical between 1.0.0 and 1.0.1.
22
+
23
+ ## Why the rename?
24
+
25
+ `@perks` was a personal npm scope. `@latanda` is the project scope used across the La Tanda ecosystem (whitepaper, platform, future packages like `@latanda/cv-refiner` and `@latanda/tanda-engine`). Aligning the package name with the brand prevents confusion and makes future ecosystem packages discoverable under one scope.
26
+
27
+ ## Deprecation of @perks/auth-middleware
28
+
29
+ `@perks/auth-middleware@1.0.0` will remain on the registry but is deprecated with a message pointing to this package. Existing installs will continue to work; please migrate at your convenience.
package/README.md ADDED
@@ -0,0 +1,438 @@
1
+ # @latanda/auth-middleware
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@latanda/auth-middleware.svg)](https://www.npmjs.com/package/@latanda/auth-middleware)
4
+ [![npm downloads](https://img.shields.io/npm/dm/@latanda/auth-middleware.svg)](https://www.npmjs.com/package/@latanda/auth-middleware)
5
+ [![license](https://img.shields.io/npm/l/@latanda/auth-middleware.svg)](https://github.com/INDIGOAZUL/latanda-auth-middleware/blob/main/LICENSE)
6
+ [![node](https://img.shields.io/node/v/@latanda/auth-middleware.svg)](https://nodejs.org)
7
+
8
+ [![ci](https://github.com/INDIGOAZUL/latanda-auth-middleware/actions/workflows/test.yml/badge.svg)](https://github.com/INDIGOAZUL/latanda-auth-middleware/actions/workflows/test.yml)
9
+
10
+ **Production-ready JWT authentication middleware for Node.js + PostgreSQL + Nginx**
11
+
12
+ Battle-tested with 30+ users at [latanda.online](https://latanda.online) ✨
13
+
14
+ ## Migration from @perks/auth-middleware
15
+
16
+ This package was previously published as `@perks/auth-middleware`. The scope was renamed to `@latanda` in v1.0.1 to align with the La Tanda project brand. The API is unchanged — only the package name and import path differ. See [MIGRATION.md](MIGRATION.md) for full details.
17
+
18
+ ```bash
19
+ npm uninstall @perks/auth-middleware && npm install @latanda/auth-middleware
20
+ ```
21
+
22
+ ```js
23
+ // Before: const auth = require('@perks/auth-middleware');
24
+ // After: const auth = require('@latanda/auth-middleware');
25
+ ```
26
+
27
+ ## Features
28
+
29
+ - ✅ **JWT Token Generation & Validation** - Secure HS256 tokens with comprehensive claim validation
30
+ - ✅ **Role-Based Access Control (RBAC)** - Pre-configured roles: ADMIN, MIT, IT, USER
31
+ - ✅ **Express Middleware** - Drop-in authentication for Express.js apps
32
+ - ✅ **PostgreSQL Integration** - Production-ready database schema included
33
+ - ✅ **Nginx Compatible** - Works seamlessly with Nginx reverse proxy
34
+ - ✅ **Token Refresh** - Automatic token refresh with expiration detection
35
+ - ✅ **Permission System** - Granular permission checks beyond roles
36
+ - ✅ **Resource Ownership** - Enforce users can only access their own resources
37
+ - ✅ **Audit Logging** - Track authentication events for security monitoring
38
+ - ✅ **Zero Dependencies** - Only requires `jsonwebtoken`, `bcrypt`, and `pg`
39
+
40
+ ## Quick Start (5 minutes to secure auth)
41
+
42
+ ### Installation
43
+
44
+ ```bash
45
+ npm install @latanda/auth-middleware jsonwebtoken bcrypt pg
46
+ ```
47
+
48
+ ### 1. Set up PostgreSQL
49
+
50
+ ```bash
51
+ # Run the schema migration
52
+ psql -U your_user -d your_database -f node_modules/@latanda/auth-middleware/sql/schema.sql
53
+ ```
54
+
55
+ ### 2. Add to your Express app
56
+
57
+ ```javascript
58
+ const express = require('express');
59
+ const { createAuthMiddleware, requireRole } = require('@latanda/auth-middleware');
60
+
61
+ const app = express();
62
+
63
+ // Protect all API routes
64
+ app.use('/api/*', createAuthMiddleware({
65
+ jwtSecret: process.env.JWT_SECRET // Store this in .env file!
66
+ }));
67
+
68
+ // Require ADMIN role for admin routes
69
+ app.use('/api/admin/*', requireRole('ADMIN'));
70
+
71
+ // Your protected routes
72
+ app.get('/api/profile', (req, res) => {
73
+ // req.user is automatically populated with authenticated user
74
+ res.json({
75
+ success: true,
76
+ user: req.user // { id, email, role, permissions }
77
+ });
78
+ });
79
+
80
+ app.listen(3000, () => console.log('Secure API running on port 3000'));
81
+ ```
82
+
83
+ ### 3. Generate tokens on login
84
+
85
+ ```javascript
86
+ const { generateToken } = require('@latanda/auth-middleware');
87
+ const bcrypt = require('bcrypt');
88
+
89
+ app.post('/auth/login', async (req, res) => {
90
+ const { email, password } = req.body;
91
+
92
+ // Get user from database
93
+ const user = await db.query('SELECT * FROM users WHERE email = $1', [email]);
94
+
95
+ if (!user || !await bcrypt.compare(password, user.password_hash)) {
96
+ return res.status(401).json({ error: 'Invalid credentials' });
97
+ }
98
+
99
+ // Generate JWT token
100
+ const token = generateToken(user, process.env.JWT_SECRET);
101
+
102
+ res.json({
103
+ success: true,
104
+ token,
105
+ user: { id: user.id, email: user.email, role: user.role }
106
+ });
107
+ });
108
+ ```
109
+
110
+ **That's it!** Your API is now secured with production-ready JWT authentication.
111
+
112
+ ## Case Study: La Tanda
113
+
114
+ [La Tanda](https://latanda.online) is a Web3 tanda (rotating savings and credit association) platform serving 30+ users across 16+ groups with real financial transactions.
115
+
116
+ **What we use this middleware for:**
117
+
118
+ - ✅ **Secure user authentication** - JWT tokens with 8-hour expiration
119
+ - ✅ **Role-based access** - ADMIN (platform management), MIT (group coordinators), USER (members)
120
+ - ✅ **API protection** - All 85+ API endpoints secured
121
+ - ✅ **Transaction security** - Ensure users can only access their own transactions
122
+ - ✅ **Admin panel** - Restricted to ADMIN role with full audit logging
123
+
124
+ **Results:**
125
+ - 🔒 Zero authentication-related security incidents
126
+ - ⚡ Sub-100ms JWT validation performance
127
+ - 📊 Complete audit trail of all auth events
128
+ - 🚀 Seamless integration with Nginx reverse proxy
129
+
130
+ ## Full Documentation
131
+
132
+ ### API Reference
133
+
134
+ #### JWT Functions
135
+
136
+ ```javascript
137
+ const { generateToken, validateToken, refreshToken } = require('@latanda/auth-middleware');
138
+
139
+ // Generate a token
140
+ const token = generateToken(user, jwtSecret, {
141
+ expiresIn: '8h', // Default: 8 hours
142
+ issuer: 'your-app.com',
143
+ audience: 'your-app'
144
+ });
145
+
146
+ // Validate a token
147
+ const validation = validateToken(token, jwtSecret);
148
+ if (validation.valid) {
149
+ console.log('User:', validation.user_id, validation.email, validation.role);
150
+ } else {
151
+ console.error('Invalid token:', validation.error);
152
+ }
153
+
154
+ // Refresh a token (if expiring soon)
155
+ const refreshResult = refreshToken(oldToken, jwtSecret);
156
+ if (refreshResult.success) {
157
+ console.log('New token:', refreshResult.token);
158
+ }
159
+ ```
160
+
161
+ #### RBAC Functions
162
+
163
+ ```javascript
164
+ const { hasPermission, hasRoleLevel, ROLES } = require('@latanda/auth-middleware');
165
+
166
+ // Check if user has permission
167
+ if (hasPermission('ADMIN', 'user_management')) {
168
+ // User has permission
169
+ }
170
+
171
+ // Check if role meets minimum level
172
+ if (hasRoleLevel('MIT', 'USER')) { // true - MIT is higher than USER
173
+ // Access granted
174
+ }
175
+
176
+ // View all roles and permissions
177
+ console.log(ROLES);
178
+ /*
179
+ {
180
+ ADMIN: { level: 100, permissions: [...] },
181
+ MIT: { level: 50, permissions: [...] },
182
+ IT: { level: 75, permissions: [...] },
183
+ USER: { level: 10, permissions: [...] }
184
+ }
185
+ */
186
+ ```
187
+
188
+ #### Middleware
189
+
190
+ ```javascript
191
+ const {
192
+ createAuthMiddleware,
193
+ requirePermission,
194
+ requireRole,
195
+ requireOwnership,
196
+ optionalAuth
197
+ } = require('@latanda/auth-middleware');
198
+
199
+ // Basic authentication (required)
200
+ app.use('/api/*', createAuthMiddleware({ jwtSecret: process.env.JWT_SECRET }));
201
+
202
+ // Require specific permission
203
+ app.post('/api/users', requirePermission('user_management'), (req, res) => {
204
+ // Only users with 'user_management' permission can access
205
+ });
206
+
207
+ // Require specific role or higher
208
+ app.use('/api/admin/*', requireRole('ADMIN'));
209
+ app.use('/api/groups/create', requireRole('MIT')); // MIT or ADMIN
210
+
211
+ // Enforce resource ownership
212
+ app.get('/api/transactions/:userId', requireOwnership(req => req.params.userId), (req, res) => {
213
+ // Users can only view their own transactions (unless ADMIN)
214
+ });
215
+
216
+ // Optional authentication (works with or without token)
217
+ app.get('/api/public/stats', optionalAuth({ jwtSecret: process.env.JWT_SECRET }), (req, res) => {
218
+ if (req.user) {
219
+ // Show personalized stats
220
+ } else {
221
+ // Show public stats
222
+ }
223
+ });
224
+ ```
225
+
226
+ ### Roles and Permissions
227
+
228
+ #### Pre-configured Roles
229
+
230
+ | Role | Level | Permissions |
231
+ |------|-------|-------------|
232
+ | **ADMIN** | 100 | `full_access`, `user_management`, `system_config`, `approve_deposits`, `manage_groups`, `view_analytics`, `manage_roles`, `delete_users`, `system_settings` |
233
+ | **IT** | 75 | `view_system_logs`, `debug_access`, `api_access`, `view_analytics`, `technical_support` |
234
+ | **MIT** | 50 | `create_groups`, `manage_own_groups`, `approve_members`, `view_group_analytics`, `edit_group_settings` |
235
+ | **USER** | 10 | `view_own_profile`, `edit_own_profile`, `join_groups`, `make_payments`, `view_own_transactions` |
236
+
237
+ #### Custom Permissions
238
+
239
+ You can add custom permissions to the database:
240
+
241
+ ```sql
242
+ INSERT INTO user_permissions (user_id, permission, granted_by)
243
+ VALUES (123, 'beta_access', 1);
244
+ ```
245
+
246
+ Then check in your code:
247
+
248
+ ```javascript
249
+ if (req.user.permissions.includes('beta_access')) {
250
+ // Show beta features
251
+ }
252
+ ```
253
+
254
+ ### Database Schema
255
+
256
+ The included PostgreSQL schema provides:
257
+
258
+ - ✅ **users** table - User accounts with bcrypt password hashes
259
+ - ✅ **sessions** table - Active JWT token tracking (optional, for revocation)
260
+ - ✅ **user_permissions** table - Custom per-user permissions
261
+ - ✅ **auth_audit_log** table - Authentication event audit trail
262
+
263
+ See `sql/schema.sql` for full details.
264
+
265
+ ### Nginx Integration
266
+
267
+ This middleware works seamlessly with Nginx reverse proxy:
268
+
269
+ ```nginx
270
+ # /etc/nginx/sites-available/your-app
271
+ location /api/ {
272
+ proxy_pass http://localhost:3000/api/;
273
+ proxy_set_header Host $host;
274
+ proxy_set_header X-Real-IP $remote_addr;
275
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
276
+ proxy_set_header X-Forwarded-Proto $scheme;
277
+
278
+ # CORS headers for JWT
279
+ add_header Access-Control-Allow-Origin * always;
280
+ add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
281
+ add_header Access-Control-Allow-Headers "Authorization, Content-Type" always;
282
+
283
+ if ($request_method = OPTIONS) {
284
+ return 204;
285
+ }
286
+ }
287
+ ```
288
+
289
+ Then your frontend can make authenticated requests:
290
+
291
+ ```javascript
292
+ fetch('https://your-app.com/api/profile', {
293
+ headers: {
294
+ 'Authorization': `Bearer ${token}`,
295
+ 'Content-Type': 'application/json'
296
+ }
297
+ })
298
+ ```
299
+
300
+ ## Advanced Usage
301
+
302
+ ### Custom Unauthorized Handler
303
+
304
+ ```javascript
305
+ app.use('/api/*', createAuthMiddleware({
306
+ jwtSecret: process.env.JWT_SECRET,
307
+ onUnauthorized: (req, res, error) => {
308
+ // Custom error handling
309
+ console.error('Auth failed:', error);
310
+ res.status(401).json({
311
+ success: false,
312
+ error: 'Custom error message',
313
+ code: error.code
314
+ });
315
+ }
316
+ }));
317
+ ```
318
+
319
+ ### Token Refresh Strategy
320
+
321
+ ```javascript
322
+ const { isTokenExpiringSoon, refreshToken } = require('@latanda/auth-middleware');
323
+
324
+ app.post('/api/refresh-token', (req, res) => {
325
+ const token = req.headers.authorization?.substring(7);
326
+
327
+ if (isTokenExpiringSoon(token, 15)) { // Refresh if expires within 15 min
328
+ const result = refreshToken(token, process.env.JWT_SECRET);
329
+ if (result.success) {
330
+ return res.json({ success: true, token: result.token });
331
+ }
332
+ }
333
+
334
+ res.json({ success: false, error: 'Token not eligible for refresh' });
335
+ });
336
+ ```
337
+
338
+ ### Group Ownership Example (La Tanda use case)
339
+
340
+ ```javascript
341
+ const { canPerformGroupAction } = require('@latanda/auth-middleware');
342
+
343
+ app.post('/api/groups/:groupId/approve-member', async (req, res) => {
344
+ const group = await db.query('SELECT * FROM groups WHERE id = $1', [req.params.groupId]);
345
+
346
+ // Check if user can approve members in this group
347
+ if (!canPerformGroupAction(req.user.id, group, req.user.role, 'approve_members')) {
348
+ return res.status(403).json({ error: 'Not authorized to approve members' });
349
+ }
350
+
351
+ // Approve member...
352
+ });
353
+ ```
354
+
355
+ ## Examples
356
+
357
+ See the `examples/` directory for complete working examples:
358
+
359
+ - **basic-usage.js** - Simple Express app with JWT auth
360
+ - **role-based-routing.js** - Different routes for different roles
361
+ - **refresh-token-flow.js** - Automatic token refresh implementation
362
+ - **nginx-integration/** - Complete Nginx + Express + PostgreSQL setup
363
+
364
+ ## Testing
365
+
366
+ ```bash
367
+ npm test
368
+ ```
369
+
370
+ ## Security Considerations
371
+
372
+ 🔒 **Always use HTTPS in production** - JWT tokens are bearer tokens and should be transmitted securely
373
+
374
+ 🔒 **Store JWT_SECRET securely** - Use environment variables, never commit secrets
375
+
376
+ 🔒 **Set appropriate token expiration** - Balance security (shorter) vs user experience (longer)
377
+
378
+ 🔒 **Implement token refresh** - Allow users to stay logged in without re-authentication
379
+
380
+ 🔒 **Monitor audit logs** - Watch for suspicious authentication patterns
381
+
382
+ 🔒 **Use bcrypt for passwords** - Never store plain-text passwords
383
+
384
+ ## 💰 Support This Project
385
+
386
+ If this package saves you time and helps secure your application, consider supporting its development!
387
+
388
+ [![Ko-fi](https://img.shields.io/badge/Ko--fi-Buy%20me%20a%20coffee-ff5e5b?logo=ko-fi&logoColor=white)](https://ko-fi.com/ebanks)
389
+ [![PayPal](https://img.shields.io/badge/PayPal-Donate-00457C?logo=paypal&logoColor=white)](https://paypal.me/narjell)
390
+ [![Open Collective](https://img.shields.io/badge/Open%20Collective-Support-7fadf2?logo=opencollective&logoColor=white)](https://opencollective.com/latanda-auth-middleware)
391
+
392
+ **Why support?**
393
+ - ✅ Ongoing maintenance and security updates
394
+ - ✅ New features based on community feedback
395
+ - ✅ Comprehensive documentation and examples
396
+ - ✅ Priority support for sponsors
397
+
398
+ **Other ways to help:**
399
+ - ⭐ Star this repo on GitHub
400
+ - 🐛 Report bugs and suggest features
401
+ - 📝 Improve documentation
402
+ - 🔀 Submit pull requests
403
+
404
+ ### 💼 Need Help?
405
+
406
+ **Professional services available:**
407
+ - 📧 Implementation consulting
408
+ - 🔧 Custom feature development
409
+ - 🏢 Enterprise support contracts
410
+
411
+ Contact: ebanksnigel@gmail.com
412
+
413
+ ## Contributing
414
+
415
+ Contributions welcome! See [CONTRIBUTING.md](CONTRIBUTING.md)
416
+
417
+ ## License
418
+
419
+ MIT © Narjell Ebanks
420
+
421
+ ## Support
422
+
423
+ - 📖 [Full Documentation](https://github.com/INDIGOAZUL/latanda-auth-middleware/wiki)
424
+ - 🐛 [Report Issues](https://github.com/INDIGOAZUL/latanda-auth-middleware/issues)
425
+ - 💬 [Discussions](https://github.com/INDIGOAZUL/latanda-auth-middleware/discussions)
426
+ - ⭐ [Star on GitHub](https://github.com/INDIGOAZUL/latanda-auth-middleware)
427
+
428
+ ## Acknowledgments
429
+
430
+ Extracted from the [La Tanda](https://latanda.online) Web3 platform - a production tanda (ROSCA) system serving real users with real money.
431
+
432
+ Special thanks to the La Tanda community for battle-testing this authentication system!
433
+
434
+ ---
435
+
436
+ **Built with ❤️ by the La Tanda team**
437
+
438
+ [GitHub](https://github.com/INDIGOAZUL/latanda-auth-middleware) • [npm](https://www.npmjs.com/package/@latanda/auth-middleware) • [La Tanda Platform](https://latanda.online)
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Basic Usage Example for @latanda/auth-middleware
3
+ *
4
+ * This example shows how to set up a simple Express server
5
+ * with JWT authentication in under 50 lines of code.
6
+ */
7
+
8
+ const express = require('express');
9
+ const {
10
+ createAuthMiddleware,
11
+ generateToken,
12
+ requireRole
13
+ } = require('@latanda/auth-middleware');
14
+
15
+ const app = express();
16
+ app.use(express.json());
17
+
18
+ // Configuration
19
+ const JWT_SECRET = process.env.JWT_SECRET || 'your-secret-key-change-this-in-production';
20
+
21
+ // ===== PUBLIC ROUTES =====
22
+
23
+ // Health check (no auth required)
24
+ app.get('/health', (req, res) => {
25
+ res.json({ status: 'ok', authenticated: false });
26
+ });
27
+
28
+ // Login endpoint (generates JWT token)
29
+ app.post('/auth/login', (req, res) => {
30
+ const { email, password } = req.body;
31
+
32
+ // TODO: Validate credentials against database
33
+ // For demo purposes, we'll accept any email/password
34
+ const user = {
35
+ id: '123',
36
+ email,
37
+ role: 'USER',
38
+ permissions: []
39
+ };
40
+
41
+ // Generate JWT token
42
+ const token = generateToken(user, JWT_SECRET, {
43
+ expiresIn: '8h'
44
+ });
45
+
46
+ res.json({
47
+ success: true,
48
+ token,
49
+ user: { id: user.id, email: user.email, role: user.role }
50
+ });
51
+ });
52
+
53
+ // ===== PROTECTED ROUTES =====
54
+
55
+ // Apply authentication middleware to all /api/* routes
56
+ app.use('/api/*', createAuthMiddleware({
57
+ jwtSecret: JWT_SECRET
58
+ }));
59
+
60
+ // Protected profile route (any authenticated user)
61
+ app.get('/api/profile', (req, res) => {
62
+ res.json({
63
+ success: true,
64
+ user: req.user // Automatically populated by middleware
65
+ });
66
+ });
67
+
68
+ // Protected route for ADMIN only
69
+ app.get('/api/admin/users', requireRole('ADMIN'), (req, res) => {
70
+ res.json({
71
+ success: true,
72
+ message: 'Admin access granted',
73
+ users: [] // TODO: Fetch from database
74
+ });
75
+ });
76
+
77
+ // ===== START SERVER =====
78
+
79
+ const PORT = process.env.PORT || 3000;
80
+ app.listen(PORT, () => {
81
+ console.log(`✅ Server running on http://localhost:${PORT}`);
82
+ console.log(`\n📝 Try these commands:\n`);
83
+ console.log(`# 1. Login to get token`);
84
+ console.log(`curl -X POST http://localhost:${PORT}/auth/login \\`);
85
+ console.log(` -H "Content-Type: application/json" \\`);
86
+ console.log(` -d '{"email":"test@example.com","password":"test123"}'\n`);
87
+ console.log(`# 2. Use token to access protected route`);
88
+ console.log(`curl http://localhost:${PORT}/api/profile \\`);
89
+ console.log(` -H "Authorization: Bearer <TOKEN_FROM_STEP_1>"\n`);
90
+ });
package/package.json ADDED
@@ -0,0 +1,66 @@
1
+ {
2
+ "name": "@latanda/auth-middleware",
3
+ "version": "1.0.1",
4
+ "description": "Production-ready JWT authentication middleware for Node.js + PostgreSQL + Nginx. Battle-tested with 30+ users at latanda.online",
5
+ "main": "src/index.js",
6
+ "files": [
7
+ "src",
8
+ "sql",
9
+ "examples",
10
+ "README.md",
11
+ "CHANGELOG.md",
12
+ "MIGRATION.md",
13
+ "LICENSE"
14
+ ],
15
+ "scripts": {
16
+ "test": "jest",
17
+ "example": "node examples/basic-usage.js"
18
+ },
19
+ "keywords": [
20
+ "authentication",
21
+ "jwt",
22
+ "postgresql",
23
+ "nginx",
24
+ "sessions",
25
+ "middleware",
26
+ "express",
27
+ "security",
28
+ "rbac",
29
+ "role-based-access-control",
30
+ "latanda",
31
+ "production-ready"
32
+ ],
33
+ "author": "Narjell Ebanks <ebanksnigel@gmail.com>",
34
+ "license": "MIT",
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "https://github.com/INDIGOAZUL/latanda-auth-middleware.git"
38
+ },
39
+ "bugs": {
40
+ "url": "https://github.com/INDIGOAZUL/latanda-auth-middleware/issues"
41
+ },
42
+ "homepage": "https://github.com/INDIGOAZUL/latanda-auth-middleware#readme",
43
+ "publishConfig": {
44
+ "access": "public"
45
+ },
46
+ "dependencies": {
47
+ "jsonwebtoken": "^9.0.2",
48
+ "bcrypt": "^5.1.1",
49
+ "pg": "^8.11.3"
50
+ },
51
+ "devDependencies": {
52
+ "@types/node": "^20.10.0",
53
+ "@types/jsonwebtoken": "^9.0.5",
54
+ "@types/bcrypt": "^5.0.2",
55
+ "@types/pg": "^8.10.9",
56
+ "typescript": "^5.3.0",
57
+ "jest": "^29.7.0",
58
+ "@types/jest": "^29.5.11"
59
+ },
60
+ "peerDependencies": {
61
+ "express": "^4.18.0 || ^5.0.0"
62
+ },
63
+ "engines": {
64
+ "node": ">=16.0.0"
65
+ }
66
+ }