mbkauthe 4.9.0 → 5.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.
Files changed (45) hide show
  1. package/README.md +98 -112
  2. package/docs/README.md +33 -0
  3. package/docs/STYLE.md +40 -0
  4. package/docs/diagrams/auth-processes.mmd +120 -0
  5. package/docs/diagrams/c.md +122 -0
  6. package/docs/{env.md → guides/configuration.md} +2 -1
  7. package/docs/{db.md → guides/database.md} +4 -2
  8. package/docs/images/auth-process.svg +102 -1
  9. package/docs/images/auth-processes.svg +1 -0
  10. package/docs/reference/api/authentication.md +105 -0
  11. package/docs/{api.md → reference/api/endpoints.md} +31 -861
  12. package/docs/reference/api/examples.md +251 -0
  13. package/docs/reference/api/middleware.md +239 -0
  14. package/docs/reference/api/operations.md +52 -0
  15. package/docs/reference/api.md +19 -0
  16. package/docs/{error-messages.md → reference/error-codes.md} +2 -0
  17. package/docs/schema/db.sql +328 -0
  18. package/index.js +5 -3
  19. package/lib/config/cookies.js +84 -18
  20. package/lib/config/index.js +3 -1
  21. package/lib/config/tokenScopes.js +1 -1
  22. package/lib/createTable.js +95 -8
  23. package/lib/db/AuthRepository.js +57 -16
  24. package/lib/db/BaseRepository.js +9 -1
  25. package/lib/db/dialects/postgres.js +1 -1
  26. package/lib/main.js +5 -5
  27. package/lib/middleware/auth.js +201 -218
  28. package/lib/middleware/index.js +13 -14
  29. package/lib/middleware/scopeValidator.js +8 -3
  30. package/lib/pool.js +5 -6
  31. package/lib/routes/auth.js +42 -47
  32. package/lib/routes/dbLogs.js +247 -29
  33. package/lib/routes/misc.js +6 -4
  34. package/lib/routes/oauth.js +19 -23
  35. package/lib/utils/dbQueryLogger.js +485 -80
  36. package/lib/utils/errors.js +1 -1
  37. package/lib/utils/logger.js +12 -0
  38. package/lib/utils/timingSafeToken.js +1 -1
  39. package/package.json +4 -3
  40. package/public/main.css +1 -1
  41. package/test.spec.js +515 -48
  42. package/views/pages/dbLogs.handlebars +618 -420
  43. package/docs/auth-processes.mmd +0 -71
  44. package/docs/db.sql +0 -276
  45. /package/docs/{auth-flows.mmd → diagrams/auth-flows.mmd} +0 -0
@@ -1,127 +1,6 @@
1
- # MBKAuthe API Documentation
1
+ # Endpoints
2
2
 
3
- [ Back to README](../README.md)
4
-
5
- This document provides comprehensive API documentation for MBKAuthe authentication system.
6
-
7
- ---
8
-
9
- ## Table of Contents
10
-
11
- - [Authentication](#authentication)
12
- - [Session Management](#session-management)
13
- - [API Endpoints](#api-endpoints)
14
- - [Public Endpoints](#public-endpoints)
15
- - [Protected Endpoints](#protected-endpoints)
16
- - [OAuth Endpoints](#oauth-endpoints)
17
- - [Information Endpoints](#information-endpoints)
18
- - [Diagnostics (Dev Only)](#diagnostics-dev-only)
19
- - [Additional Endpoints](#additional-endpoints)
20
- - [Middleware Reference](#middleware-reference)
21
- - [Code Examples](#code-examples)
22
-
23
- ---
24
-
25
- ## Authentication
26
-
27
- MBKAuthe supports two authentication methods:
28
-
29
- 1. **Session-based Authentication** - Cookie-based sessions for web applications
30
- 2. **Token-based Authentication** - Persistent API keys for server-to-server communication
31
-
32
- ### Token-based Authentication
33
-
34
- For API clients and external services, use a Bearer token in the `Authorization` header.
35
-
36
- **Header Format:**
37
- ```
38
- Authorization: Bearer <your_api_token>
39
- ```
40
- *Token format: `mbk_` followed by 64 hexadecimal characters.*
41
-
42
- **Behavior:**
43
- - **Stateless:** Validates against the `ApiTokens` table on every request.
44
- - **Expiration:** Tokens can have an optional expiration date.
45
- - **Permissions:** API tokens inherit the permissions of the user who created them.
46
- - **Scopes:** Tokens have a scope (`read-only` or `write`) that controls which HTTP methods are allowed:
47
- - `read-only`: Only GET, HEAD, and OPTIONS requests (safe, read-only operations)
48
- - `write`: All HTTP methods (GET, POST, PUT, DELETE, PATCH, etc.)
49
- - **Usage Tracking:** The system updates the `LastUsed` timestamp on every successful request.
50
-
51
- **Errors:**
52
- - `401 Unauthorized` (Code 1005: `INVALID_AUTH_TOKEN`): Token is malformed or not found.
53
- - `401 Unauthorized` (Code 1006: `API_TOKEN_EXPIRED`): Token exists but has passed its expiration date.
54
- - `403 Forbidden` (Code 1007: `TOKEN_SCOPE_INSUFFICIENT`): Token scope doesn't allow this HTTP method.
55
-
56
- **Example Usage:**
57
-
58
- **1. Backend Implementation (Express):**
59
-
60
- Even when using API tokens, the `validateSession`/`sessVal` middleware hydrates `req.session.user` for consistency, allowing you to use the same route logic for both browser and API clients.
61
-
62
- ```javascript
63
- import { sessVal } from 'mbkauthe';
64
-
65
- app.get('/api/protected-resource', sessVal, (req, res) => {
66
- // Access user info populated from the token
67
- const user = req.session.user; // { id, username, role, ... }
68
-
69
- res.json({
70
- message: `Hello ${user.username}`,
71
- role: user.role
72
- });
73
- });
74
- ```
75
-
76
- **2. Client Request Examples:**
77
-
78
- *cURL:*
79
- ```bash
80
- curl -X GET https://api.yourdomain.com/api/protected-resource \
81
- -H "Authorization: Bearer mbk_7f83a92b1dc..."
82
- ```
83
-
84
- *JavaScript (Fetch):*
85
- ```javascript
86
- const response = await fetch('https://api.yourdomain.com/api/protected-resource', {
87
- headers: {
88
- 'Authorization': 'Bearer mbk_7f83a92b1dc...'
89
- }
90
- });
91
- const data = await response.json();
92
- ```
93
-
94
- **Output:**
95
- ```json
96
- {
97
- "message": "Hello john.doe",
98
- "role": "NormalUser"
99
- }
100
- ```
101
-
102
- ---
103
-
104
- ## Session Management
105
-
106
- ### Session Cookie
107
-
108
- When a user logs in, MBKAuthe creates a session and sets the following cookies:
109
-
110
- | Cookie Name | Description | HttpOnly | Secure | SameSite |
111
- |------------|-------------|----------|--------|----------|
112
- | `mbkauthe.sid` | Session identifier | ✓ | Auto* | lax |
113
- | `sessionId` | Encrypted session token (AES-256-GCM). This cookie is encrypted and treated as an opaque value by clients; do not attempt to parse or rely on the raw cookie contents. Use server endpoints (e.g., `GET /mbkauthe/api/checkSession`, `POST /mbkauthe/api/checkSession` (body) or `POST /mbkauthe/api/verifySession`) to validate or query session information. | ✓ | Auto* | lax |
114
- | `username` | Username | ✗ | Auto* | lax |
115
-
116
- \* `secure` flag is automatically set to `true` in production when `IS_DEPLOYED=true`
117
-
118
- ### Session Lifetime
119
-
120
- - Default: 2 days (configurable via `COOKIE_EXPIRE_TIME`)
121
- - Application sessions are stored in the `Sessions` table in PostgreSQL
122
- - Sessions persist across subdomains in production
123
-
124
- ---
3
+ [Back to API index](../api.md) | [Back to docs index](../../README.md) | [Back to project README](../../../README.md)
125
4
 
126
5
  ## API Endpoints
127
6
 
@@ -291,6 +170,26 @@ Returns recent DB query diagnostics.
291
170
 
292
171
  ---
293
172
 
173
+ #### `POST /mbkauthe/db/reset`
174
+
175
+ Resets the DB query log and counters (dev-only).
176
+
177
+ **Authentication / Access:** Dev-only (mounted when `process.env.env === 'dev'` and `dbLogs=true`).
178
+
179
+ **Request Body:** None required.
180
+
181
+ **Success Response (200 OK):**
182
+ ```json
183
+ {
184
+ "success": true,
185
+ "message": "Query log and count have been reset."
186
+ }
187
+ ```
188
+
189
+ **Behavior:** Clears the in-memory or persisted DB query counters and logs used by the diagnostic UI. Returns `403` when DB logs are disabled.
190
+
191
+ ---
192
+
294
193
  #### `GET /mbkauthe/validate-superadmin`
295
194
 
296
195
  Validates that the current session has `SuperAdmin` role and returns a JSON summary.
@@ -328,6 +227,7 @@ The endpoints below are active in the router but are not fully expanded above. U
328
227
  - `GET /mbkauthe/info.json` and `GET /mbkauthe/i.json` - Info page JSON.
329
228
  - `GET /mbkauthe/ErrorCode` - Error codes page.
330
229
  - `GET /mbkauthe/user/profilepic` - User profile picture proxy.
230
+ - `GET /mbkauthe/` - Mount root; renders the test/home page (alias of `/mbkauthe/test`).
331
231
 
332
232
  **Admin:**
333
233
 
@@ -339,6 +239,12 @@ The endpoints below are active in the router but are not fully expanded above. U
339
239
  - `GET /mbkauthe/main.css`
340
240
  - `GET /mbkauthe/bg.webp`
341
241
 
242
+ Also served at the root level (outside `/mbkauthe`) are site icons:
243
+
244
+ - `GET /icon.svg` - Main application SVG icon (root-level)
245
+ - `GET /favicon.ico` - Fallback favicon (root-level)
246
+ - `GET /icon.png` - Additional icon size (root-level)
247
+
342
248
  ---
343
249
 
344
250
  #### `POST /mbkauthe/api/login`
@@ -671,184 +577,6 @@ fetch('/mbkauthe/api/logout', {
671
577
 
672
578
  ### Multi-Account Endpoints
673
579
 
674
- ---
675
-
676
- #### Token Management Endpoints
677
-
678
- ##### `POST /mbkauthe/api/token`
679
-
680
- Create a new API token for the authenticated user.
681
-
682
- **Rate Limit:** 10 requests per minute
683
-
684
- **Authentication:** Session required (cookie or Bearer token)
685
-
686
- **Request Body:**
687
- ```json
688
- {
689
- "name": "string (required, 1-255 chars, friendly name for the token)",
690
- "expiresDays": "number (optional, 1-365, default 90)",
691
- "scope": "string (optional, 'read-only' or 'write', default 'read-only')",
692
- "allowedApps": "array (optional, app names or ['*'] for all apps)"
693
- }
694
- ```
695
-
696
- **Token Scopes:**
697
- - `read-only`: Allows only read operations (GET, HEAD, OPTIONS methods)
698
- - `write`: Allows all operations (GET, POST, PUT, DELETE, PATCH, etc.)
699
-
700
- **Token Application Access:**
701
- - Omit `allowedApps`: Token inherits from user's allowed apps
702
- - `["app1", "app2"]`: Token restricted to specific apps (must be subset of user's apps for non-SuperAdmin)
703
- - `["*"]`: All user's apps (non-SuperAdmin) or all system apps (SuperAdmin only)
704
- - **SuperAdmin bypass**: SuperAdmin tokens work on any app regardless of `allowedApps` configuration
705
-
706
- **Success Response (201 Created):**
707
- ```json
708
- {
709
- "success": true,
710
- "token": "mbk_7f83a92b1dc4e5a6f89b012c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e",
711
- "tokenId": 42,
712
- "prefix": "mbk_7f83a92",
713
- "name": "My API Token",
714
- "scope": "read-only",
715
- "allowedApps": ["App1", "App2"],
716
- "expiresAt": "2025-04-27T12:34:56.000Z",
717
- "createdAt": "2025-01-27T12:34:56.000Z",
718
- "message": "Token created successfully. Save it now - it won't be shown again."
719
- }
720
- ```
721
-
722
- **Error Responses:**
723
-
724
- | Status Code | Error Code | Message |
725
- |------------|------------|---------|
726
- | 400 | MISSING_REQUIRED_FIELD | Token name is required (1-255 characters) |
727
- | 400 | MISSING_REQUIRED_FIELD | expiresDays must be between 1 and 365 |
728
- | 400 | MISSING_REQUIRED_FIELD | Invalid scope. Available scopes: read-only, write |
729
- | 400 | MISSING_REQUIRED_FIELD | allowedApps must be an array |
730
- | 401 | SESSION_NOT_FOUND | Not authenticated |
731
- | 403 | INSUFFICIENT_PERMISSIONS | Only SuperAdmin can create tokens with '*' (all apps) access |
732
- | 403 | INSUFFICIENT_PERMISSIONS | You don't have access to app 'X' |
733
- | 500 | INTERNAL_SERVER_ERROR | Internal Server Error |
734
-
735
- **Example Requests:**
736
-
737
- *Create a read-only token for specific apps:*
738
- ```javascript
739
- const response = await fetch('/mbkauthe/api/token', {
740
- method: 'POST',
741
- headers: {
742
- 'Content-Type': 'application/json',
743
- 'Authorization': 'Bearer mbk_existing_token...' // or use session cookie
744
- },
745
- body: JSON.stringify({
746
- name: 'CI/CD Pipeline Token',
747
- expiresDays: 30,
748
- scope: 'read-only',
749
- allowedApps: ['App1', 'App2']
750
- })
751
- });
752
- ```
753
-
754
- *Create a write token with inherited app access:*
755
- ```javascript
756
- const response = await fetch('/mbkauthe/api/token', {
757
- method: 'POST',
758
- headers: { 'Content-Type': 'application/json' },
759
- body: JSON.stringify({
760
- name: 'Admin API Token',
761
- scope: 'write'
762
- // allowedApps omitted - inherits from user
763
- })
764
- });
765
- ```
766
-
767
- ---
768
-
769
- ##### `GET /mbkauthe/api/tokens`
770
-
771
- List all API tokens for the authenticated user (token value not included).
772
-
773
- **Rate Limit:** 10 requests per minute
774
-
775
- **Authentication:** Session required (cookie or Bearer token)
776
-
777
- **Success Response (200 OK):**
778
- ```json
779
- {
780
- "success": true,
781
- "tokens": [
782
- {
783
- "id": 42,
784
- "name": "CI/CD Pipeline Token",
785
- "prefix": "mbk_7f83a92",
786
- "scope": "read-only",
787
- "allowedApps": ["App1", "App2"],
788
- "lastUsed": "2025-01-27T10:15:30.000Z",
789
- "createdAt": "2025-01-27T12:34:56.000Z",
790
- "expiresAt": "2025-04-27T12:34:56.000Z",
791
- "expired": false
792
- },
793
- {
794
- "id": 43,
795
- "name": "Admin API Token",
796
- "prefix": "mbk_a1b2c3d",
797
- "scope": "write",
798
- "allowedApps": null,
799
- "lastUsed": null,
800
- "createdAt": "2025-01-26T08:20:15.000Z",
801
- "expiresAt": null,
802
- "expired": false
803
- }
804
- ],
805
- "count": 2
806
- }
807
- ```
808
-
809
- **Note:** `allowedApps: null` means the token inherits from user's allowed apps.
810
-
811
- **Error Responses:**
812
-
813
- | Status Code | Error Code | Message |
814
- |------------|------------|---------|
815
- | 401 | SESSION_NOT_FOUND | Not authenticated |
816
- | 500 | INTERNAL_SERVER_ERROR | Internal Server Error |
817
-
818
- ---
819
-
820
- ##### `DELETE /mbkauthe/api/token/:id`
821
-
822
- Revoke (delete) an API token by its ID.
823
-
824
- **Rate Limit:** 10 requests per minute
825
-
826
- **Authentication:** Session required (cookie or Bearer token)
827
-
828
- **URL Parameters:**
829
- - `id`: Token ID (integer)
830
-
831
- **Success Response (200 OK):**
832
- ```json
833
- {
834
- "success": true,
835
- "message": "Token revoked successfully"
836
- }
837
- ```
838
-
839
- **Error Responses:**
840
-
841
- | Status Code | Error Code | Message |
842
- |------------|------------|---------|
843
- | 400 | MISSING_REQUIRED_FIELD | Invalid token ID |
844
- | 401 | SESSION_NOT_FOUND | Not authenticated |
845
- | 404 | SESSION_NOT_FOUND | Token not found or not owned by you |
846
- | 500 | INTERNAL_SERVER_ERROR | Internal Server Error |
847
-
848
- ---
849
-
850
- ### Multi-Account Endpoints
851
-
852
580
  #### `GET /mbkauthe/accounts`
853
581
 
854
582
  Renders the account switching page, allowing users to switch between remembered accounts on the device.
@@ -1130,6 +858,8 @@ Serves the application's SVG icon file from the root level.
1130
858
 
1131
859
  **Note:** This route is mounted at the root level (not under `/mbkauthe`)
1132
860
 
861
+ **Also served:** `/favicon.ico` and `/icon.png` are provided as additional icon fallbacks at the same root level.
862
+
1133
863
  **Usage:**
1134
864
  ```html
1135
865
  <img src="/icon.svg" alt="App Icon">
@@ -1396,563 +1126,3 @@ Both GitHub and Google OAuth implementations include:
1396
1126
 
1397
1127
  ---
1398
1128
 
1399
- ## Middleware Reference
1400
-
1401
- ### `validateSession`/`sessRole`
1402
-
1403
- Validates that the user has an active session.
1404
-
1405
- **Usage:**
1406
- ```javascript
1407
- import { sessRole } from 'mbkauthe';
1408
-
1409
- app.get('/protected', sessRole, (req, res) => {
1410
- // User is authenticated
1411
- const user = req.session.user;
1412
- // user contains: { id, username, UserName, role, Role, sessionId }
1413
- res.send(`Welcome ${user.username}!`);
1414
- });
1415
- ```
1416
-
1417
- **Behavior:**
1418
- - Checks for active session in `req.session.user`
1419
- - Attempts to restore session from `sessionId` cookie if session not found
1420
- - Validates session against database
1421
- - Checks if user account is still active
1422
- - Verifies user is authorized for the current application
1423
- - Redirects to login page if validation fails
1424
-
1425
- **JSON vs HTML error responses:**
1426
-
1427
- When `validateSession` fails, MBKAuthe will either render an HTML error/login page (browser flow) or return a JSON error response (API/AJAX flow). A request is treated as **JSON** when any of these are true:
1428
-
1429
- - URL/path starts with `/mbkauthe/api/` or `/api/`
1430
- - `X-Requested-With: XMLHttpRequest`
1431
- - `Accept` indicates JSON (e.g., `application/json`) and does not explicitly prefer `text/html`
1432
- - `User-Agent` matches a non-browser client (e.g., `curl`, `wget`, `Postman`, `Insomnia`)
1433
- - `User-Agent: json` (explicitly forces JSON responses)
1434
-
1435
- **Example (force JSON errors on a page route):**
1436
- ```bash
1437
- curl -i -H "User-Agent: json" http://localhost:3000/mbkauthe/test
1438
- ```
1439
-
1440
- ### reloadSessionUser(req, res)
1441
-
1442
- Use this helper when you need to refresh the values stored in `req.session.user` from the authoritative database record (for example, after a profile update that changes FullName, or when session expiration policies are updated).
1443
-
1444
- - Behavior:
1445
- - Validates the session against the database (sessionId, active)
1446
- - Updates `req.session.user` fields: `username`, `role`, `allowedApps`, `fullname`
1447
- - Uses cached `fullName` cookie if available; falls back to querying `profiledata`
1448
- - Syncs `username`, `fullName`, and `sessionId` cookies for client display
1449
- - If the session is invalid (sessionId mismatch, inactive account, or unauthorized), it destroys the session and clears cookies
1450
-
1451
- - Returns: `Promise<boolean>` — `true` if session was refreshed and still valid, `false` if session was invalidated or reload failed.
1452
-
1453
- - Example:
1454
- ```javascript
1455
- import { reloadSessionUser } from 'mbkauthe';
1456
-
1457
- // After updating profile data
1458
- app.post('/mbkauthe/api/update-profile', sessRole, async (req, res) => {
1459
- // ... update profiledata.FullName in DB ...
1460
- const refreshed = await reloadSessionUser(req, res);
1461
- if (!refreshed) {
1462
- return res.status(401).json({ success: false, message: 'Session invalidated' });
1463
- }
1464
- res.json({ success: true, fullname: req.session.user.fullname });
1465
- });
1466
- ```
1467
-
1468
- **Session Object:**
1469
- ```javascript
1470
- req.session.user = {
1471
- id: 1, // User ID
1472
- username: "john.doe", // Username (login name)
1473
- fullname: "John Doe", // Optional display name fetched from profiledata
1474
- role: "NormalUser", // User role
1475
- sessionId: "abc123...", // 64-char hex session ID
1476
- }
1477
- ```
1478
-
1479
- **Session Cookie Sync:**
1480
- - The middleware sets non-httpOnly cookies for client display:
1481
- - `username` — the login username (exposed for UI)
1482
- - `fullName` — the display name (falls back to username if not available)
1483
-
1484
- These cookies allow front-end UI to display a friendly name without making extra requests to the server.
1485
- ---
1486
-
1487
- ### `checkRolePermission(requiredRole, notAllowed)`/`roleChk `
1488
-
1489
- Checks if the authenticated user has the required role.
1490
-
1491
- **Parameters:**
1492
- - `requiredRole` (string) - Required role: `"SuperAdmin"`, `"NormalUser"`, `"Guest"`, `"member"`, or `"Any"`/`"any"`
1493
- - `notAllowed` (string, optional) - Role that is explicitly not allowed
1494
-
1495
- **Usage:**
1496
- ```javascript
1497
- import { sessVal, roleChk } from 'mbkauthe';
1498
-
1499
- // Only SuperAdmin can access
1500
- app.get('/admin', sessVal, roleChk('SuperAdmin'), (req, res) => {
1501
- res.send('Admin panel');
1502
- });
1503
-
1504
- // Any authenticated user except Guest
1505
- app.get('/content', sessVal, roleChk('Any', 'Guest'), (req, res) => {
1506
- res.send('Protected content');
1507
- });
1508
- ```
1509
-
1510
- **Behavior:**
1511
- - Checks if user is authenticated first
1512
- - Fetches user role from database
1513
- - Returns 403 if user has `notAllowed` role
1514
- - Returns 403 if user doesn't have `requiredRole` (unless role is "Any")
1515
- - Calls `next()` if authorized
1516
-
1517
- ---
1518
-
1519
- ### `validateSessionAndRole(requiredRole, notAllowed)`/`sessRole`
1520
-
1521
- Combined middleware for session validation and role checking.
1522
-
1523
- **Parameters:**
1524
- - `requiredRole` (string) - Required role
1525
- - `notAllowed` (string, optional) - Role that is explicitly not allowed
1526
-
1527
- **Usage:**
1528
- ```javascript
1529
- import { sessRole, roleChk } from 'mbkauthe';
1530
-
1531
- // Validate session AND check role in one middleware
1532
- app.get('/moderator', sessRole('SuperAdmin'), (req, res) => {
1533
- res.send('Moderator panel');
1534
- });
1535
- ```
1536
-
1537
- **Equivalent to:**
1538
- ```javascript
1539
- app.get('/moderator', sessVal, roleChk('SuperAdmin'), (req, res) => {
1540
- res.send('Moderator panel');
1541
- });
1542
- ```
1543
-
1544
- ---
1545
-
1546
- ### Strict validation helpers
1547
-
1548
- For endpoints that must reject API token-based authentication and only accept browser session cookies, MBKAuthe exposes two strict helpers:
1549
-
1550
- - `strictValidateSession` — same as `validateSession`, but rejects requests that provide `Authorization` headers (API tokens) and returns `401` when a token is used.
1551
- - `strictValidateSessionAndRole(requiredRole, notAllowed)` — combined helper that behaves like `validateSessionAndRole` but enforces strict (cookie-only) authentication.
1552
-
1553
- **Usage examples:**
1554
- ```javascript
1555
- import { strictValidateSession, strictValidateSessionAndRole } from 'mbkauthe';
1556
-
1557
- // Accept only cookie sessions
1558
- app.get('/sensitive', strictValidateSession, (req, res) => {
1559
- res.send('Sensitive data');
1560
- });
1561
-
1562
- // Validate session AND role, using cookie-only authentication
1563
- app.get('/admin', strictValidateSessionAndRole('SuperAdmin'), (req, res) => {
1564
- res.send('Admin');
1565
- });
1566
- ```
1567
-
1568
- ---
1569
-
1570
- ### Response Utilities
1571
-
1572
- MBKAuthe exports small helpers to assist with page rendering and context:
1573
-
1574
- - `getUserContext(req)` — returns a lightweight context object for templates: `{ userLoggedIn, isuserlogin, username, fullname, role, allowedApps }`.
1575
- - `renderPage(req, res, fileLocation, layout = true, data = {})` — renders a template with the user/context merged into the data; returns a Promise and yields the typical Express `res.render` behavior.
1576
- - `renderError(res, req, options)` — renders the standardized error page; note the signature is `(res, req, options)` and `options` follow the `ErrorRenderOptions` described in the types.
1577
-
1578
- **Example:**
1579
-
1580
- ```javascript
1581
- import { getUserContext, renderPage, renderError } from 'mbkauthe';
1582
-
1583
- app.get('/dashboard', (req, res) => {
1584
- const ctx = getUserContext(req);
1585
- return renderPage(req, res, 'info', true, { greeting: 'Hello', ...ctx });
1586
- });
1587
-
1588
- app.get('/err', (req, res) => {
1589
- return renderError(res, req, {
1590
- layout: false,
1591
- code: 500,
1592
- error: "Internal Server Error",
1593
- message: "Simulated 500 Error",
1594
- details: "This is a simulated 500 error page for testing purposes.",
1595
- pagename: "Home",
1596
- page: "/mbkauthe/login",
1597
- });
1598
- });
1599
- ```
1600
-
1601
- ---
1602
-
1603
- ### `authenticate(token)`
1604
-
1605
- API authentication middleware for server-to-server communication.
1606
-
1607
- **Parameters:**
1608
- - `token` (string) - Secret token for authentication
1609
-
1610
- **Usage:**
1611
- ```javascript
1612
- import { authenticate } from 'mbkauthe';
1613
-
1614
- app.post('/api/data', authenticate(process.env.API_TOKEN), (req, res) => {
1615
- res.json({ data: 'Protected API data' });
1616
- });
1617
- ```
1618
-
1619
- **Headers Required:**
1620
- ```
1621
- Authorization: Bearer your-secret-token
1622
- ```
1623
-
1624
- You can also send the raw token without the `Bearer` prefix.
1625
-
1626
- **Behavior:**
1627
- - Checks `Authorization` header
1628
- - Extracts the token (strips optional `Bearer` prefix)
1629
- - Compares the provided token to the expected token using a timing-safe SHA-256 hash comparison
1630
- - Returns 401 if token doesn't match
1631
-
1632
- ---
1633
-
1634
- ## Error Codes
1635
-
1636
- ### HTTP Status Codes
1637
-
1638
- | Code | Meaning | Usage |
1639
- |------|---------|-------|
1640
- | 200 | OK | Successful request |
1641
- | 400 | Bad Request | Invalid input data |
1642
- | 401 | Unauthorized | Authentication required or failed |
1643
- | 403 | Forbidden | Insufficient permissions |
1644
- | 404 | Not Found | Resource not found |
1645
- | 429 | Too Many Requests | Rate limit exceeded |
1646
- | 500 | Internal Server Error | Server-side error |
1647
-
1648
- ---
1649
-
1650
- ## Code Examples
1651
-
1652
- ### Basic Integration
1653
-
1654
- ```javascript
1655
- import express from 'express';
1656
- import mbkauthe, { validateSession } from 'mbkauthe';
1657
- import dotenv from 'dotenv';
1658
-
1659
- dotenv.config();
1660
-
1661
- // Configure MBKAuthe
1662
- process.env.mbkautheVar = JSON.stringify({
1663
- APP_NAME: process.env.APP_NAME,
1664
- SESSION_SECRET_KEY: process.env.SESSION_SECRET_KEY,
1665
- IS_DEPLOYED: process.env.IS_DEPLOYED,
1666
- DOMAIN: process.env.DOMAIN,
1667
- LOGIN_DB: process.env.LOGIN_DB,
1668
- MBKAUTH_TWO_FA_ENABLE: process.env.MBKAUTH_TWO_FA_ENABLE,
1669
- COOKIE_EXPIRE_TIME: process.env.COOKIE_EXPIRE_TIME || 2,
1670
- loginRedirectURL: '/dashboard'
1671
- });
1672
-
1673
- const app = express();
1674
-
1675
- // Mount MBKAuthe routes
1676
- app.use(mbkauthe);
1677
-
1678
- // Protected route
1679
- app.get('/dashboard', sessVal, (req, res) => {
1680
- res.send(`Welcome ${req.session.user.username}!`);
1681
- });
1682
-
1683
- app.listen(3000, () => {
1684
- console.log('Server running on http://localhost:3000');
1685
- });
1686
- ```
1687
-
1688
- ---
1689
-
1690
- ### Role-Based Access Control
1691
-
1692
- ```javascript
1693
- import { sessVal, roleChk, sessRole } from 'mbkauthe';
1694
-
1695
- // Method 1: Separate middleware
1696
- app.get('/admin',
1697
- sessVal,
1698
- roleChk('SuperAdmin'),
1699
- (req, res) => {
1700
- res.send('Admin panel');
1701
- }
1702
- );
1703
-
1704
- // Method 2: Combined middleware
1705
- app.get('/admin',
1706
- sessRole('SuperAdmin'),
1707
- (req, res) => {
1708
- res.send('Admin panel');
1709
- }
1710
- );
1711
-
1712
- // Allow any role except Guest
1713
- app.get('/content',
1714
- sessVal,
1715
- roleChk('Any', 'Guest'),
1716
- (req, res) => {
1717
- res.send('Content for registered users');
1718
- }
1719
- );
1720
-
1721
- // Multiple roles (using separate middleware)
1722
- app.get('/moderator',
1723
- sessVal,
1724
- (req, res, next) => {
1725
- if (['SuperAdmin', 'NormalUser'].includes(req.session.user.role)) {
1726
- next();
1727
- } else {
1728
- res.status(403).send('Access denied');
1729
- }
1730
- },
1731
- (req, res) => {
1732
- res.send('Moderator panel');
1733
- }
1734
- );
1735
- ```
1736
-
1737
- ---
1738
-
1739
- ### API Authentication
1740
-
1741
- ```javascript
1742
- import { authenticate } from 'mbkauthe';
1743
-
1744
- // Simple token authentication
1745
- app.post('/api/webhook',
1746
- authenticate(process.env.WEBHOOK_SECRET),
1747
- (req, res) => {
1748
- // Process webhook
1749
- res.json({ received: true });
1750
- }
1751
- );
1752
-
1753
- // Admin API with token authentication
1754
- app.post('/api/admin/terminate-sessions',
1755
- authenticate(process.env.MAIN_SECRET_TOKEN),
1756
- async (req, res) => {
1757
- // Terminate all sessions
1758
- res.json({ success: true });
1759
- }
1760
- );
1761
-
1762
- // Protected API endpoint (requires session)
1763
- app.get('/api/user/profile',
1764
- sessVal,
1765
- async (req, res) => {
1766
- const { username } = req.session.user;
1767
-
1768
- // Fetch user profile
1769
- const profile = await getUserProfile(username);
1770
-
1771
- res.json({ success: true, profile });
1772
- }
1773
- );
1774
- ```
1775
-
1776
- ---
1777
-
1778
- ### Client-Side Login
1779
-
1780
- ```javascript
1781
- // Login form submission
1782
- document.getElementById('loginForm').addEventListener('submit', async (e) => {
1783
- e.preventDefault();
1784
-
1785
- const username = document.getElementById('username').value;
1786
- const password = document.getElementById('password').value;
1787
-
1788
- try {
1789
- const response = await fetch('/mbkauthe/api/login', {
1790
- method: 'POST',
1791
- headers: {
1792
- 'Content-Type': 'application/json',
1793
- },
1794
- body: JSON.stringify({ username, password })
1795
- });
1796
-
1797
- const data = await response.json();
1798
-
1799
- if (data.success) {
1800
- if (data.twoFactorRequired) {
1801
- // Redirect to 2FA page
1802
- window.location.href = '/mbkauthe/2fa';
1803
- } else {
1804
- // Login successful, redirect
1805
- window.location.href = data.redirectUrl || '/dashboard';
1806
- }
1807
- } else {
1808
- alert(data.message || 'Login failed');
1809
- }
1810
- } catch (error) {
1811
- console.error('Login error:', error);
1812
- alert('An error occurred during login');
1813
- }
1814
- });
1815
- ```
1816
-
1817
- ---
1818
-
1819
- ### Client-Side Logout
1820
-
1821
- ```javascript
1822
- async function logout() {
1823
- // Get CSRF token from page
1824
- const csrfToken = document.querySelector('[name="_csrf"]').value;
1825
-
1826
- try {
1827
- const response = await fetch('/mbkauthe/api/logout', {
1828
- method: 'POST',
1829
- headers: {
1830
- 'Content-Type': 'application/json',
1831
- },
1832
- body: JSON.stringify({ _csrf: csrfToken })
1833
- });
1834
-
1835
- const data = await response.json();
1836
-
1837
- if (data.success) {
1838
- window.location.href = '/mbkauthe/login';
1839
- } else {
1840
- alert('Logout failed: ' + data.message);
1841
- }
1842
- } catch (error) {
1843
- console.error('Logout error:', error);
1844
- }
1845
- }
1846
- ```
1847
-
1848
- ---
1849
-
1850
- ### Database Access
1851
-
1852
- ```javascript
1853
- import { dblogin } from 'mbkauthe';
1854
-
1855
- // Custom query using the database pool
1856
- app.get('/api/users', sessVal, roleChk('SuperAdmin'), async (req, res) => {
1857
- try {
1858
- const result = await dblogin.query(
1859
- 'SELECT id, "UserName", "Role", "Active" FROM "Users" ORDER BY id'
1860
- );
1861
-
1862
- res.json({
1863
- success: true,
1864
- users: result.rows
1865
- });
1866
- } catch (error) {
1867
- console.error('Database error:', error);
1868
- res.status(500).json({
1869
- success: false,
1870
- message: 'Internal Server Error'
1871
- });
1872
- }
1873
- });
1874
- ```
1875
-
1876
- ---
1877
-
1878
- ### Error Handling
1879
-
1880
- ```javascript
1881
- // Custom error handler
1882
- app.use((err, req, res, next) => {
1883
- console.error('Error:', err);
1884
-
1885
- if (err.code === 'EBADCSRFTOKEN') {
1886
- return res.status(403).json({
1887
- success: false,
1888
- message: 'Invalid CSRF token'
1889
- });
1890
- }
1891
-
1892
- res.status(500).json({
1893
- success: false,
1894
- message: 'Internal Server Error'
1895
- });
1896
- });
1897
-
1898
- // 404 handler
1899
- app.use((req, res) => {
1900
- res.status(404).render('Error/dError.handlebars', {
1901
- layout: false,
1902
- code: 404,
1903
- error: 'Not Found',
1904
- message: 'The requested page was not found.',
1905
- pagename: 'Home',
1906
- page: '/',
1907
- });
1908
- });
1909
- ```
1910
-
1911
- ---
1912
-
1913
- ## Security Best Practices
1914
-
1915
- 1. **Always use HTTPS in production** - Set `IS_DEPLOYED=true` and ensure your server uses SSL/TLS
1916
- 2. **Keep SESSION_SECRET_KEY secure** - Use a strong, randomly generated key
1917
- 3. **Enable 2FA for sensitive applications** - Set `MBKAUTH_TWO_FA_ENABLE=true`
1918
- 4. **Validate all user input** - Never trust client-side data
1919
- 5. **Use rate limiting** - Already implemented for authentication endpoints
1920
- 6. **Keep dependencies updated** - Regularly update npm packages
1921
- 7. **Monitor for security vulnerabilities** - Use `npm audit`
1922
- 8. **Use prepared statements** - Prevent SQL injection (already implemented)
1923
- 9. **Implement proper logging** - Track authentication events
1924
- 10. **Regular security audits** - Review code and configurations
1925
-
1926
- ---
1927
-
1928
- ## Rate Limits
1929
-
1930
- | Endpoint | Limit | Window |
1931
- |----------|-------|--------|
1932
- | `/mbkauthe/api/login` | 8 requests | 1 minute |
1933
- | `/mbkauthe/api/logout` | 10 requests | 1 minute |
1934
- | `/mbkauthe/api/verify-2fa` | 5 requests | 1 minute |
1935
- | `/mbkauthe/api/github/login` | 10 requests | 5 minutes |
1936
- | `/mbkauthe/api/github/login/callback` | 10 requests | 5 minutes |
1937
- | `/mbkauthe/login` | 8 requests | 1 minute |
1938
- | `/mbkauthe/info` | 8 requests | 1 minute |
1939
- | `/mbkauthe/test` | 8 requests | 1 minute |
1940
-
1941
- Rate limits are applied per IP address. Logged-in users are exempt from some rate limits (e.g., login page rate limit).
1942
-
1943
- ---
1944
-
1945
- ## Support
1946
-
1947
- For issues, questions, or contributions:
1948
-
1949
- - **GitHub Issues:** [https://github.com/MIbnEKhalid/mbkauthe/issues](https://github.com/MIbnEKhalid/mbkauthe/issues)
1950
- - **Email:** support@mbktech.org
1951
- - **Documentation:** [https://github.com/MIbnEKhalid/mbkauthe](https://github.com/MIbnEKhalid/mbkauthe)
1952
-
1953
- ---
1954
-
1955
- **Last Updated:** November 17, 2025
1956
- **Version:** 1.4.2
1957
-
1958
- [← Back to README](../README.md)