@xeplr/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.
Files changed (51) hide show
  1. package/LICENSE +21 -0
  2. package/bin/migrate.js +95 -0
  3. package/bin/server.js +35 -0
  4. package/index.js +165 -0
  5. package/lib/accessMiddleware.js +79 -0
  6. package/lib/accessService.js +188 -0
  7. package/lib/adminRouter.js +387 -0
  8. package/lib/authHelper.js +63 -0
  9. package/lib/authMiddleware.js +31 -0
  10. package/lib/authRouter.js +192 -0
  11. package/lib/authService.js +194 -0
  12. package/lib/sessionService.js +210 -0
  13. package/migrations/0001_users.js +22 -0
  14. package/migrations/0002_menus.js +16 -0
  15. package/migrations/0003_apis.js +16 -0
  16. package/migrations/0004_uiPages.js +16 -0
  17. package/migrations/0005_uiElements.js +16 -0
  18. package/migrations/0006_roles.js +15 -0
  19. package/migrations/0007_apisRolesMapping.js +16 -0
  20. package/migrations/0008_uiPagesRolesMapping.js +16 -0
  21. package/migrations/0009_uiElementsRolesMapping.js +16 -0
  22. package/migrations/0010_menuRolesMapping.js +16 -0
  23. package/migrations/0011_userRolesMapping.js +16 -0
  24. package/migrations/0012_users_add_reset_token.js +13 -0
  25. package/migrations/0013_add_isPublic.js +27 -0
  26. package/migrations/0014_users_add_activation_token.js +13 -0
  27. package/migrations/0015_add_mt_columns.js +41 -0
  28. package/migrations/0016_tenants.js +23 -0
  29. package/migrations/0017_userTenantsMapping.js +20 -0
  30. package/models/Api.js +45 -0
  31. package/models/ApisRolesMapping.js +29 -0
  32. package/models/Menu.js +45 -0
  33. package/models/MenuRolesMapping.js +29 -0
  34. package/models/Role.js +89 -0
  35. package/models/Tenant.js +63 -0
  36. package/models/UiElement.js +44 -0
  37. package/models/UiElementsRolesMapping.js +29 -0
  38. package/models/UiPage.js +45 -0
  39. package/models/UiPagesRolesMapping.js +29 -0
  40. package/models/User.js +76 -0
  41. package/models/UserRolesMapping.js +29 -0
  42. package/models/UserTenantsMapping.js +30 -0
  43. package/models/index.js +29 -0
  44. package/package.json +31 -0
  45. package/seeds/001_roles.js +26 -0
  46. package/seeds/002_apis.js +70 -0
  47. package/seeds/003_pages.js +41 -0
  48. package/seeds/004_elements.js +46 -0
  49. package/seeds/005_menus.js +35 -0
  50. package/seeds/006_default_tenant.js +50 -0
  51. package/seeds/zzz_admin_access.js +49 -0
@@ -0,0 +1,29 @@
1
+ const User = require('./User');
2
+ const Menu = require('./Menu');
3
+ const Api = require('./Api');
4
+ const UiPage = require('./UiPage');
5
+ const UiElement = require('./UiElement');
6
+ const Role = require('./Role');
7
+ const ApisRolesMapping = require('./ApisRolesMapping');
8
+ const UiPagesRolesMapping = require('./UiPagesRolesMapping');
9
+ const UiElementsRolesMapping = require('./UiElementsRolesMapping');
10
+ const MenuRolesMapping = require('./MenuRolesMapping');
11
+ const UserRolesMapping = require('./UserRolesMapping');
12
+ const Tenant = require('./Tenant');
13
+ const UserTenantsMapping = require('./UserTenantsMapping');
14
+
15
+ module.exports = {
16
+ User,
17
+ Menu,
18
+ Api,
19
+ UiPage,
20
+ UiElement,
21
+ Role,
22
+ ApisRolesMapping,
23
+ UiPagesRolesMapping,
24
+ UiElementsRolesMapping,
25
+ MenuRolesMapping,
26
+ UserRolesMapping,
27
+ Tenant,
28
+ UserTenantsMapping
29
+ };
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "@xeplr/auth",
3
+ "version": "1.0.0",
4
+ "description": "Pluggable authentication service: register, login, forgot/reset password, RBAC, multi-tenancy",
5
+ "main": "index.js",
6
+ "files": ["index.js", "lib/", "bin/", "models/", "migrations/", "seeds/"],
7
+ "bin": {
8
+ "xeplr-auth-migrate": "./bin/migrate.js",
9
+ "xeplr-auth-server": "./bin/server.js"
10
+ },
11
+ "exports": {
12
+ ".": "./index.js",
13
+ "./bin/server": "./bin/server.js",
14
+ "./package.json": "./package.json"
15
+ },
16
+ "keywords": ["auth", "authentication", "jwt", "rbac", "express", "middleware", "multi-tenancy"],
17
+ "author": "xeplr",
18
+ "license": "MIT",
19
+ "repository": { "type": "git", "url": "https://github.com/Xeplr/xeplr-auth" },
20
+ "publishConfig": { "access": "public" },
21
+ "dependencies": {
22
+ "bcrypt": "^6.0.0",
23
+ "jsonwebtoken": "^9.0.3",
24
+ "@xeplr/base-apis": "^1.0.0",
25
+ "@xeplr/db": "^1.0.0",
26
+ "@xeplr/utils": "^1.0.0"
27
+ },
28
+ "peerDependencies": {
29
+ "express": "^4.0.0 || ^5.0.0"
30
+ }
31
+ }
@@ -0,0 +1,26 @@
1
+ var crypto = require('crypto');
2
+
3
+ function generateId() {
4
+ return crypto.randomBytes(12).toString('hex').substring(0, 25);
5
+ }
6
+
7
+ var now = new Date().toISOString();
8
+ var MT_ALL = '*';
9
+
10
+ var ROLES = ['Super Admin', 'Admin', 'Editor', 'Viewer'];
11
+
12
+ exports.seed = async function(knex) {
13
+ for (var i = 0; i < ROLES.length; i++) {
14
+ var exists = await knex('roles').where({ name: ROLES[i] }).first();
15
+ if (!exists) {
16
+ await knex('roles').insert({
17
+ id: generateId(),
18
+ name: ROLES[i],
19
+ isActive: true,
20
+ recordCreatedDate: now,
21
+ recordModifiedDate: now,
22
+ mtId1: MT_ALL
23
+ });
24
+ }
25
+ }
26
+ };
@@ -0,0 +1,70 @@
1
+ var crypto = require('crypto');
2
+
3
+ function generateId() {
4
+ return crypto.randomBytes(12).toString('hex').substring(0, 25);
5
+ }
6
+
7
+ var now = new Date().toISOString();
8
+ var MT_ALL = '*';
9
+
10
+ var APIS = [
11
+ // Auth APIs (public — no role needed)
12
+ { name: '/auth/api/register', apiGroup: '', isPublic: true },
13
+ { name: '/auth/api/activate', apiGroup: '', isPublic: true },
14
+ { name: '/auth/api/login', apiGroup: '', isPublic: true },
15
+ { name: '/auth/api/forgot-password', apiGroup: '', isPublic: true },
16
+ { name: '/auth/api/reset-password', apiGroup: '', isPublic: true },
17
+ { name: '/auth/api/refresh', apiGroup: '', isPublic: true },
18
+ { name: '/auth/api/logout', apiGroup: '', isPublic: true },
19
+ { name: '/auth/api/me', apiGroup: 'account:view', isPublic: false },
20
+
21
+ // Admin APIs — user/role management
22
+ { name: '/auth/api/admin/users', apiGroup: 'users:view', isPublic: false },
23
+ { name: '/auth/api/admin/roles', apiGroup: 'users:view', isPublic: false },
24
+ { name: '/auth/api/admin/user-role', apiGroup: 'users:edit', isPublic: false },
25
+ { name: '/auth/api/admin/access-items', apiGroup: 'access:view', isPublic: false },
26
+ { name: '/auth/api/admin/access-role', apiGroup: 'access:edit', isPublic: false },
27
+ { name: '/auth/api/admin/module-role', apiGroup: 'access:edit', isPublic: false },
28
+
29
+ // Admin APIs — tenant management
30
+ { name: '/auth/api/admin/tenants', apiGroup: 'tenants:view', isPublic: false },
31
+ { name: '/auth/api/admin/tenants/save', apiGroup: 'tenants:edit', isPublic: false },
32
+ { name: '/auth/api/admin/tenants/delete', apiGroup: 'tenants:delete', isPublic: false },
33
+ { name: '/auth/api/admin/tenants/assign-user', apiGroup: 'tenants:edit', isPublic: false },
34
+
35
+ // Admin APIs — master settings
36
+ { name: '/auth/api/admin/master/roles', apiGroup: 'settings:view', isPublic: false },
37
+ { name: '/auth/api/admin/master/roles/save', apiGroup: 'settings:edit', isPublic: false },
38
+ { name: '/auth/api/admin/master/roles/delete', apiGroup: 'settings:delete', isPublic: false },
39
+ { name: '/auth/api/admin/master/apis', apiGroup: 'settings:view', isPublic: false },
40
+ { name: '/auth/api/admin/master/apis/save', apiGroup: 'settings:edit', isPublic: false },
41
+ { name: '/auth/api/admin/master/apis/delete', apiGroup: 'settings:delete', isPublic: false },
42
+ { name: '/auth/api/admin/master/pages', apiGroup: 'settings:view', isPublic: false },
43
+ { name: '/auth/api/admin/master/pages/save', apiGroup: 'settings:edit', isPublic: false },
44
+ { name: '/auth/api/admin/master/pages/delete', apiGroup: 'settings:delete', isPublic: false },
45
+ { name: '/auth/api/admin/master/elements', apiGroup: 'settings:view', isPublic: false },
46
+ { name: '/auth/api/admin/master/elements/save', apiGroup: 'settings:edit', isPublic: false },
47
+ { name: '/auth/api/admin/master/elements/delete', apiGroup: 'settings:delete', isPublic: false },
48
+ { name: '/auth/api/admin/master/menus', apiGroup: 'settings:view', isPublic: false },
49
+ { name: '/auth/api/admin/master/menus/save', apiGroup: 'settings:edit', isPublic: false },
50
+ { name: '/auth/api/admin/master/menus/delete', apiGroup: 'settings:delete', isPublic: false },
51
+ ];
52
+
53
+ exports.seed = async function(knex) {
54
+ for (var i = 0; i < APIS.length; i++) {
55
+ var api = APIS[i];
56
+ var exists = await knex('apis').where({ name: api.name }).first();
57
+ if (!exists) {
58
+ await knex('apis').insert({
59
+ id: generateId(),
60
+ name: api.name,
61
+ apiGroup: api.apiGroup,
62
+ isPublic: api.isPublic,
63
+ isActive: true,
64
+ recordCreatedDate: now,
65
+ recordModifiedDate: now,
66
+ mtId1: MT_ALL
67
+ });
68
+ }
69
+ }
70
+ };
@@ -0,0 +1,41 @@
1
+ var crypto = require('crypto');
2
+
3
+ function generateId() {
4
+ return crypto.randomBytes(12).toString('hex').substring(0, 25);
5
+ }
6
+
7
+ var now = new Date().toISOString();
8
+ var MT_ALL = '*';
9
+
10
+ var PAGES = [
11
+ { name: 'Login', uiPagesGroup: '', isPublic: true },
12
+ { name: 'Register', uiPagesGroup: '', isPublic: true },
13
+ { name: 'Forgot Password', uiPagesGroup: '', isPublic: true },
14
+ { name: 'Reset Password', uiPagesGroup: '', isPublic: true },
15
+ { name: 'Activate Account', uiPagesGroup: '', isPublic: true },
16
+ { name: 'Profile', uiPagesGroup: 'account:view', isPublic: false },
17
+ { name: 'Change Password', uiPagesGroup: 'account:edit', isPublic: false },
18
+ { name: 'User Roles', uiPagesGroup: 'users:view', isPublic: false },
19
+ { name: 'Access Matrix', uiPagesGroup: 'access:view', isPublic: false },
20
+ { name: 'Master Settings', uiPagesGroup: 'settings:view', isPublic: false },
21
+ { name: 'Tenant Management', uiPagesGroup: 'tenants:view', isPublic: false },
22
+ ];
23
+
24
+ exports.seed = async function(knex) {
25
+ for (var i = 0; i < PAGES.length; i++) {
26
+ var page = PAGES[i];
27
+ var exists = await knex('uiPages').where({ name: page.name }).first();
28
+ if (!exists) {
29
+ await knex('uiPages').insert({
30
+ id: generateId(),
31
+ name: page.name,
32
+ uiPagesGroup: page.uiPagesGroup,
33
+ isPublic: page.isPublic,
34
+ isActive: true,
35
+ recordCreatedDate: now,
36
+ recordModifiedDate: now,
37
+ mtId1: MT_ALL
38
+ });
39
+ }
40
+ }
41
+ };
@@ -0,0 +1,46 @@
1
+ var crypto = require('crypto');
2
+
3
+ function generateId() {
4
+ return crypto.randomBytes(12).toString('hex').substring(0, 25);
5
+ }
6
+
7
+ var now = new Date().toISOString();
8
+ var MT_ALL = '*';
9
+
10
+ var ELEMENTS = [
11
+ { name: 'Assign Role Button', uiElementsGroup: 'users:edit' },
12
+ { name: 'Remove Role Button', uiElementsGroup: 'users:edit' },
13
+ { name: 'Toggle Access Checkbox', uiElementsGroup: 'access:edit' },
14
+ { name: 'Toggle Module Access Checkbox', uiElementsGroup: 'access:edit' },
15
+ { name: 'Add Role Button', uiElementsGroup: 'settings:edit' },
16
+ { name: 'Delete Role Button', uiElementsGroup: 'settings:delete' },
17
+ { name: 'Add API Button', uiElementsGroup: 'settings:edit' },
18
+ { name: 'Delete API Button', uiElementsGroup: 'settings:delete' },
19
+ { name: 'Add Page Button', uiElementsGroup: 'settings:edit' },
20
+ { name: 'Delete Page Button', uiElementsGroup: 'settings:delete' },
21
+ { name: 'Add Element Button', uiElementsGroup: 'settings:edit' },
22
+ { name: 'Delete Element Button', uiElementsGroup: 'settings:delete' },
23
+ { name: 'Add Menu Button', uiElementsGroup: 'settings:edit' },
24
+ { name: 'Delete Menu Button', uiElementsGroup: 'settings:delete' },
25
+ { name: 'Add Tenant Button', uiElementsGroup: 'tenants:edit' },
26
+ { name: 'Delete Tenant Button', uiElementsGroup: 'tenants:delete' },
27
+ { name: 'Assign User Tenant', uiElementsGroup: 'tenants:edit' },
28
+ ];
29
+
30
+ exports.seed = async function(knex) {
31
+ for (var i = 0; i < ELEMENTS.length; i++) {
32
+ var el = ELEMENTS[i];
33
+ var exists = await knex('uiElements').where({ name: el.name }).first();
34
+ if (!exists) {
35
+ await knex('uiElements').insert({
36
+ id: generateId(),
37
+ name: el.name,
38
+ uiElementsGroup: el.uiElementsGroup,
39
+ isActive: true,
40
+ recordCreatedDate: now,
41
+ recordModifiedDate: now,
42
+ mtId1: MT_ALL
43
+ });
44
+ }
45
+ }
46
+ };
@@ -0,0 +1,35 @@
1
+ var crypto = require('crypto');
2
+
3
+ function generateId() {
4
+ return crypto.randomBytes(12).toString('hex').substring(0, 25);
5
+ }
6
+
7
+ var now = new Date().toISOString();
8
+ var MT_ALL = '*';
9
+
10
+ var MENUS = [
11
+ { name: 'Profile', menuGroup: 'account:view', isPublic: false },
12
+ { name: 'User Roles', menuGroup: 'users:view', isPublic: false },
13
+ { name: 'Access Matrix', menuGroup: 'access:view', isPublic: false },
14
+ { name: 'Master Settings', menuGroup: 'settings:view', isPublic: false },
15
+ { name: 'Tenant Management', menuGroup: 'tenants:view', isPublic: false },
16
+ ];
17
+
18
+ exports.seed = async function(knex) {
19
+ for (var i = 0; i < MENUS.length; i++) {
20
+ var menu = MENUS[i];
21
+ var exists = await knex('menus').where({ name: menu.name }).first();
22
+ if (!exists) {
23
+ await knex('menus').insert({
24
+ id: generateId(),
25
+ name: menu.name,
26
+ menuGroup: menu.menuGroup,
27
+ isPublic: menu.isPublic,
28
+ isActive: true,
29
+ recordCreatedDate: now,
30
+ recordModifiedDate: now,
31
+ mtId1: MT_ALL
32
+ });
33
+ }
34
+ }
35
+ };
@@ -0,0 +1,50 @@
1
+ var crypto = require('crypto');
2
+
3
+ function generateId() {
4
+ return crypto.randomBytes(12).toString('hex').substring(0, 25);
5
+ }
6
+
7
+ var now = new Date().toISOString();
8
+ var MT_ALL = '*';
9
+ var DEFAULT_TENANT_NAME = 'Default';
10
+ var DEFAULT_TENANT_CODE = 'default';
11
+
12
+ exports.seed = async function(knex) {
13
+ // Create default tenant if not exists
14
+ var tenant = await knex('tenants').where({ code: DEFAULT_TENANT_CODE }).first();
15
+ if (!tenant) {
16
+ var tenantId = generateId();
17
+ await knex('tenants').insert({
18
+ id: tenantId,
19
+ name: DEFAULT_TENANT_NAME,
20
+ code: DEFAULT_TENANT_CODE,
21
+ level: 1,
22
+ description: 'Default tenant',
23
+ mtId1: MT_ALL,
24
+ isActive: true,
25
+ recordCreatedDate: now,
26
+ recordModifiedDate: now
27
+ });
28
+ tenant = { id: tenantId };
29
+ }
30
+
31
+ // Assign all Super Admin users to the default tenant
32
+ var superAdminRole = await knex('roles').where({ name: 'Super Admin' }).first();
33
+ if (!superAdminRole) return;
34
+
35
+ var superAdminMappings = await knex('userRolesMapping').where({ roleId: superAdminRole.id });
36
+ for (var i = 0; i < superAdminMappings.length; i++) {
37
+ var userId = superAdminMappings[i].userId;
38
+ var exists = await knex('userTenantsMapping').where({ userId: userId, tenantId: tenant.id }).first();
39
+ if (!exists) {
40
+ await knex('userTenantsMapping').insert({
41
+ id: generateId(),
42
+ userId: userId,
43
+ tenantId: tenant.id,
44
+ isActive: true,
45
+ recordCreatedDate: now,
46
+ recordModifiedDate: now
47
+ });
48
+ }
49
+ }
50
+ };
@@ -0,0 +1,49 @@
1
+ var crypto = require('crypto');
2
+
3
+ function generateId() {
4
+ return crypto.randomBytes(12).toString('hex').substring(0, 25);
5
+ }
6
+
7
+ var now = new Date().toISOString();
8
+ var MT_ALL = '*';
9
+
10
+ var ADMIN_ROLES = ['Super Admin', 'Admin'];
11
+
12
+ var MAPPINGS = [
13
+ { table: 'apisRolesMapping', source: 'apis', fk: 'apiId' },
14
+ { table: 'uiPagesRolesMapping', source: 'uiPages', fk: 'uiPageId' },
15
+ { table: 'uiElementsRolesMapping', source: 'uiElements', fk: 'uiElementId' },
16
+ { table: 'menuRolesMapping', source: 'menus', fk: 'menuId' },
17
+ ];
18
+
19
+ exports.seed = async function(knex) {
20
+ var roles = await knex('roles').whereIn('name', ADMIN_ROLES).select('id', 'name');
21
+ if (roles.length === 0) return;
22
+
23
+ for (var m = 0; m < MAPPINGS.length; m++) {
24
+ var mapping = MAPPINGS[m];
25
+ var items = await knex(mapping.source).select('id');
26
+
27
+ for (var r = 0; r < roles.length; r++) {
28
+ var roleId = roles[r].id;
29
+
30
+ for (var i = 0; i < items.length; i++) {
31
+ var where = { roleId: roleId };
32
+ where[mapping.fk] = items[i].id;
33
+
34
+ var exists = await knex(mapping.table).where(where).first();
35
+ if (!exists) {
36
+ var row = {
37
+ id: generateId(),
38
+ roleId: roleId,
39
+ recordCreatedDate: now,
40
+ recordModifiedDate: now,
41
+ mtId1: MT_ALL
42
+ };
43
+ row[mapping.fk] = items[i].id;
44
+ await knex(mapping.table).insert(row);
45
+ }
46
+ }
47
+ }
48
+ }
49
+ };