hazo_auth 4.4.1 → 4.5.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 (94) hide show
  1. package/README.md +207 -5
  2. package/SETUP_CHECKLIST.md +1 -1
  3. package/cli-src/lib/auth/auth_types.ts +22 -0
  4. package/cli-src/lib/auth/hazo_get_auth.server.ts +25 -1
  5. package/cli-src/lib/auth/session_token_validator.edge.ts +1 -0
  6. package/cli-src/lib/config/default_config.ts +36 -0
  7. package/cli-src/lib/navbar_config.server.ts +129 -0
  8. package/cli-src/lib/scope_hierarchy_config.server.ts +3 -14
  9. package/cli-src/lib/services/registration_service.ts +12 -0
  10. package/cli-src/lib/services/scope_labels_service.ts +21 -21
  11. package/cli-src/lib/services/scope_service.ts +15 -11
  12. package/cli-src/lib/services/session_token_service.ts +1 -0
  13. package/cli-src/lib/ui_shell_config.server.ts +15 -0
  14. package/cli-src/lib/user_types_config.server.ts +178 -0
  15. package/dist/app/api/hazo_auth/me/route.d.ts.map +1 -1
  16. package/dist/app/api/hazo_auth/me/route.js +17 -0
  17. package/dist/app/api/hazo_auth/org_management/orgs/route.d.ts +26 -0
  18. package/dist/app/api/hazo_auth/org_management/orgs/route.d.ts.map +1 -0
  19. package/dist/app/api/hazo_auth/org_management/orgs/route.js +315 -0
  20. package/dist/app/api/hazo_auth/user_management/users/route.d.ts +11 -1
  21. package/dist/app/api/hazo_auth/user_management/users/route.d.ts.map +1 -1
  22. package/dist/app/api/hazo_auth/user_management/users/route.js +121 -16
  23. package/dist/components/layouts/my_settings/components/profile_picture_library_tab.d.ts.map +1 -1
  24. package/dist/components/layouts/my_settings/components/profile_picture_library_tab.js +8 -14
  25. package/dist/components/layouts/rbac_test/index.d.ts +1 -3
  26. package/dist/components/layouts/rbac_test/index.d.ts.map +1 -1
  27. package/dist/components/layouts/rbac_test/index.js +2 -2
  28. package/dist/components/layouts/shared/components/auth_navbar.d.ts +26 -0
  29. package/dist/components/layouts/shared/components/auth_navbar.d.ts.map +1 -0
  30. package/dist/components/layouts/shared/components/auth_navbar.js +14 -0
  31. package/dist/components/layouts/shared/components/auth_page_shell.d.ts +3 -1
  32. package/dist/components/layouts/shared/components/auth_page_shell.d.ts.map +1 -1
  33. package/dist/components/layouts/shared/components/auth_page_shell.js +17 -2
  34. package/dist/components/layouts/shared/components/standalone_layout_wrapper.d.ts +6 -1
  35. package/dist/components/layouts/shared/components/standalone_layout_wrapper.d.ts.map +1 -1
  36. package/dist/components/layouts/shared/components/standalone_layout_wrapper.js +7 -2
  37. package/dist/components/layouts/shared/index.d.ts +2 -0
  38. package/dist/components/layouts/shared/index.d.ts.map +1 -1
  39. package/dist/components/layouts/shared/index.js +1 -0
  40. package/dist/components/layouts/user_management/components/scope_hierarchy_tab.d.ts +3 -2
  41. package/dist/components/layouts/user_management/components/scope_hierarchy_tab.d.ts.map +1 -1
  42. package/dist/components/layouts/user_management/components/scope_hierarchy_tab.js +45 -18
  43. package/dist/components/layouts/user_management/components/scope_labels_tab.d.ts +3 -2
  44. package/dist/components/layouts/user_management/components/scope_labels_tab.d.ts.map +1 -1
  45. package/dist/components/layouts/user_management/components/scope_labels_tab.js +48 -20
  46. package/dist/components/layouts/user_management/components/user_scopes_tab.d.ts.map +1 -1
  47. package/dist/components/layouts/user_management/components/user_scopes_tab.js +1 -1
  48. package/dist/components/layouts/user_management/index.d.ts +11 -3
  49. package/dist/components/layouts/user_management/index.d.ts.map +1 -1
  50. package/dist/components/layouts/user_management/index.js +52 -5
  51. package/dist/components/ui/user-type-badge.d.ts +23 -0
  52. package/dist/components/ui/user-type-badge.d.ts.map +1 -0
  53. package/dist/components/ui/user-type-badge.js +42 -0
  54. package/dist/lib/auth/auth_types.d.ts +17 -0
  55. package/dist/lib/auth/auth_types.d.ts.map +1 -1
  56. package/dist/lib/auth/auth_types.js +11 -0
  57. package/dist/lib/auth/hazo_get_auth.server.d.ts.map +1 -1
  58. package/dist/lib/auth/hazo_get_auth.server.js +21 -1
  59. package/dist/lib/config/default_config.d.ts +60 -0
  60. package/dist/lib/config/default_config.d.ts.map +1 -1
  61. package/dist/lib/config/default_config.js +34 -0
  62. package/dist/lib/navbar_config.server.d.ts +36 -0
  63. package/dist/lib/navbar_config.server.d.ts.map +1 -0
  64. package/dist/lib/navbar_config.server.js +45 -0
  65. package/dist/lib/scope_hierarchy_config.server.d.ts +3 -7
  66. package/dist/lib/scope_hierarchy_config.server.d.ts.map +1 -1
  67. package/dist/lib/scope_hierarchy_config.server.js +1 -10
  68. package/dist/lib/services/registration_service.d.ts.map +1 -1
  69. package/dist/lib/services/registration_service.js +8 -0
  70. package/dist/lib/services/scope_labels_service.d.ts +7 -7
  71. package/dist/lib/services/scope_labels_service.d.ts.map +1 -1
  72. package/dist/lib/services/scope_labels_service.js +20 -20
  73. package/dist/lib/services/scope_service.d.ts +8 -5
  74. package/dist/lib/services/scope_service.d.ts.map +1 -1
  75. package/dist/lib/services/scope_service.js +9 -8
  76. package/dist/lib/ui_shell_config.server.d.ts +5 -0
  77. package/dist/lib/ui_shell_config.server.d.ts.map +1 -1
  78. package/dist/lib/ui_shell_config.server.js +5 -0
  79. package/dist/lib/user_types_config.server.d.ts +56 -0
  80. package/dist/lib/user_types_config.server.d.ts.map +1 -0
  81. package/dist/lib/user_types_config.server.js +100 -0
  82. package/dist/server/routes/index.d.ts +1 -0
  83. package/dist/server/routes/index.d.ts.map +1 -1
  84. package/dist/server/routes/index.js +2 -0
  85. package/dist/server/routes/org_management_orgs.d.ts +2 -0
  86. package/dist/server/routes/org_management_orgs.d.ts.map +1 -0
  87. package/dist/server/routes/org_management_orgs.js +2 -0
  88. package/hazo_auth_config.example.ini +9 -0
  89. package/package.json +1 -1
  90. package/cli-src/server/logging/logger_service.ts +0 -56
  91. /package/public/profile_pictures/library/Cars/{050 - citroe/314/210n_c3.jpeg" → 050 - citro/303/253n_c3.jpeg"} +0 -0
  92. /package/public/profile_pictures/library/Cars/{064 - lamborghini_huraca/314/201n.jpeg" → 064 - lamborghini_hurac/303/241n.jpeg"} +0 -0
  93. /package/public/profile_pictures/library/Cars/{099 - citroe/314/210n_2cv_(classic).jpeg" → 099 - citro/303/253n_2cv_(classic).jpeg"} +0 -0
  94. /package/public/profile_pictures/library/Cars/{131 - lamborghini_huraca/314/201n_sto.jpeg" → 131 - lamborghini_hurac/303/241n_sto.jpeg"} +0 -0
package/README.md CHANGED
@@ -29,6 +29,7 @@ A reusable authentication UI component package powered by Next.js, TailwindCSS,
29
29
  - [Authentication Service](#authentication-service)
30
30
  - [Proxy/Middleware Authentication](#proxymiddleware-authentication)
31
31
  - [Profile Picture Menu Widget](#profile-picture-menu-widget)
32
+ - [User Types (Optional Feature)](#user-types-optional-feature)
32
33
  - [User Profile Service](#user-profile-service)
33
34
  - [Local Development](#local-development)
34
35
 
@@ -1030,6 +1031,35 @@ export { GET, POST, PUT } from "hazo_auth/server/routes";
1030
1031
  - **UI Enhancement**: The Roles tab uses a tag-based UI for better readability. Each role displays permissions as inline tags/chips (showing up to 4, with "+N more" to expand). Edit permissions via an interactive dialog with Select All/Unselect All buttons.
1031
1032
  - **User Roles:** Get user roles, assign roles to users, bulk update user role assignments
1032
1033
 
1034
+ ---
1035
+
1036
+ ### Organization Management Component
1037
+
1038
+ The `OrgManagementLayout` component provides an admin interface for managing the organization hierarchy when multi-tenancy is enabled. It requires the org_management API routes to be set up in your project.
1039
+
1040
+ **Required Permissions:**
1041
+ - `hazo_perm_org_management` - CRUD operations on organizations
1042
+ - `hazo_org_global_admin` - View/manage all organizations across the system (optional, for global admins)
1043
+
1044
+ **Required API Routes:**
1045
+ The `OrgManagementLayout` component requires the following API route to be created in your project:
1046
+
1047
+ ```typescript
1048
+ // app/api/hazo_auth/org_management/orgs/route.ts
1049
+ export {
1050
+ orgManagementOrgsGET as GET,
1051
+ orgManagementOrgsPOST as POST,
1052
+ orgManagementOrgsPATCH as PATCH,
1053
+ orgManagementOrgsDELETE as DELETE
1054
+ } from "hazo_auth/server/routes";
1055
+ ```
1056
+
1057
+ **Note:** This route is automatically created when you run `npx hazo_auth generate-routes`. The route handles:
1058
+ - **GET:** List organizations (with `action=tree` query parameter for hierarchical tree structure)
1059
+ - **POST:** Create new organization
1060
+ - **PATCH:** Update existing organization (name, user_limit, active status)
1061
+ - **DELETE:** Soft delete organization (sets active=false, does not remove from database)
1062
+
1033
1063
  **Example Usage:**
1034
1064
 
1035
1065
  ```tsx
@@ -1055,7 +1085,8 @@ By default, the pages render inside the "test workspace" sidebar so you can quic
1055
1085
  ```ini
1056
1086
  [hazo_auth__ui_shell]
1057
1087
  # Options: test_sidebar | standalone
1058
- layout_mode = standalone
1088
+ layout_mode = standalone
1089
+ vertical_center = auto # 'auto' enables vertical centering when navbar is present
1059
1090
  # Optional tweaks for the standalone header wrapper/classes:
1060
1091
  # standalone_heading = Welcome back
1061
1092
  # standalone_description = Your description here
@@ -1065,8 +1096,52 @@ layout_mode = standalone
1065
1096
 
1066
1097
  - `test_sidebar`: keeps the developer sidebar (perfect for the demo workspace or Storybook screenshots).
1067
1098
  - `standalone`: renders the page body directly so it inherits your own app shell, layout, and theme tokens.
1099
+ - `vertical_center`: controls vertical centering of auth content (`auto` enables centering when navbar is present)
1068
1100
  - The wrapper and content class overrides let you align spacing/borders with your design system without editing package code.
1069
1101
 
1102
+ ### Authentication Page Navbar
1103
+
1104
+ When using `layout_mode = standalone`, you can enable a configurable navbar that appears on all auth pages:
1105
+
1106
+ ```ini
1107
+ [hazo_auth__navbar]
1108
+ enable_navbar = true # Show navbar on auth pages
1109
+ logo_path = /logo.png # Path to logo image
1110
+ logo_width = 32 # Logo width in pixels
1111
+ logo_height = 32 # Logo height in pixels
1112
+ company_name = My Company # Company name (links to home)
1113
+ home_path = / # URL for logo and company name link
1114
+ home_label = Home # Label for home link
1115
+ show_home_link = true # Show "Home" link on right side
1116
+ background_color = # Custom background (optional)
1117
+ text_color = # Custom text color (optional)
1118
+ height = 64 # Navbar height in pixels
1119
+ ```
1120
+
1121
+ The navbar provides consistent branding across authentication pages with your company logo, name, and optional home link. It automatically vertically centers auth content when enabled.
1122
+
1123
+ **Customize via props:**
1124
+ ```typescript
1125
+ import { LoginLayout } from "hazo_auth/components/layouts/login";
1126
+
1127
+ export default function Page() {
1128
+ return (
1129
+ <LoginLayout
1130
+ navbar={{
1131
+ logo_path: "/custom-logo.svg",
1132
+ company_name: "Acme Corp",
1133
+ background_color: "#1a1a1a",
1134
+ }}
1135
+ />
1136
+ );
1137
+ }
1138
+ ```
1139
+
1140
+ **Disable for specific pages:**
1141
+ ```typescript
1142
+ <LoginLayout navbar={{ enable_navbar: false }} />
1143
+ ```
1144
+
1070
1145
  ---
1071
1146
 
1072
1147
  ## Authentication Service
@@ -1479,7 +1554,7 @@ Add the following to your `hazo_auth_config.ini`:
1479
1554
  ```ini
1480
1555
  [hazo_auth__scope_hierarchy]
1481
1556
  enable_hrbac = true
1482
- default_org = my_organization # Optional: default organization for single-tenant apps
1557
+ # Note: No default_org needed - org determined from user authentication
1483
1558
  scope_cache_ttl_minutes = 15
1484
1559
  scope_cache_max_entries = 5000
1485
1560
 
@@ -1586,16 +1661,14 @@ The `RbacTestLayout` component provides a comprehensive testing interface for ad
1586
1661
  ```typescript
1587
1662
  // app/admin/rbac-test/page.tsx
1588
1663
  import { RbacTestLayout } from "hazo_auth/components/layouts/rbac_test";
1589
- import { is_hrbac_enabled, get_default_org } from "hazo_auth/lib/scope_hierarchy_config.server";
1664
+ import { is_hrbac_enabled } from "hazo_auth/lib/scope_hierarchy_config.server";
1590
1665
 
1591
1666
  export default function RbacTestPage() {
1592
1667
  const hrbacEnabled = is_hrbac_enabled();
1593
- const defaultOrg = get_default_org();
1594
1668
 
1595
1669
  return (
1596
1670
  <RbacTestLayout
1597
1671
  hrbacEnabled={hrbacEnabled}
1598
- defaultOrg={defaultOrg}
1599
1672
  />
1600
1673
  );
1601
1674
  }
@@ -1785,6 +1858,135 @@ custom_menu_items = info:Phone:+1234567890:3,separator:2,link:My Account:/accoun
1785
1858
 
1786
1859
  ---
1787
1860
 
1861
+ ## User Types (Optional Feature)
1862
+
1863
+ hazo_auth provides an optional user type categorization system for classifying users with visual badge indicators. This feature is useful for applications managing multiple user personas (e.g., "Client" vs "Tax Agent", "Internal" vs "External", "Premium" vs "Standard").
1864
+
1865
+ ### Overview
1866
+
1867
+ - **Config-based**: Define types in `hazo_auth_config.ini` (no UI management needed)
1868
+ - **Single type per user**: Mutually exclusive categories (not tags)
1869
+ - **Visual badges**: Color-coded badges with preset or custom hex colors
1870
+ - **Zero impact when disabled**: Optional feature, disabled by default
1871
+ - **Separate from RBAC**: Types are labels, roles control permissions
1872
+
1873
+ ### Quick Start
1874
+
1875
+ 1. **Enable in configuration** (`hazo_auth_config.ini`):
1876
+ ```ini
1877
+ [hazo_auth__user_types]
1878
+ enable_user_types = true
1879
+ default_user_type = standard
1880
+ user_type_1 = standard:Standard User:blue
1881
+ user_type_2 = client:Client:green
1882
+ user_type_3 = agent:Tax Agent:orange
1883
+ ```
1884
+
1885
+ 2. **Run database migration**:
1886
+ ```bash
1887
+ npm run migrate migrations/007_add_user_type_to_hazo_users.sql
1888
+ ```
1889
+
1890
+ 3. **Use in User Management**:
1891
+ ```typescript
1892
+ import { UserManagementLayout } from "hazo_auth/components/layouts/user_management";
1893
+
1894
+ <UserManagementLayout
1895
+ userTypesEnabled={true}
1896
+ availableUserTypes={[
1897
+ { key: "standard", label: "Standard User", badge_color: "blue" },
1898
+ { key: "client", label: "Client", badge_color: "green" }
1899
+ ]}
1900
+ />
1901
+ ```
1902
+
1903
+ ### Configuration Format
1904
+
1905
+ Each user type is defined as `key:label:badge_color`:
1906
+ - **key**: Unique identifier stored in database (e.g., "client")
1907
+ - **label**: Display name shown in UI (e.g., "Client")
1908
+ - **badge_color**: Preset color name (blue, green, red, yellow, purple, gray, orange, pink) or hex code (#4CAF50)
1909
+
1910
+ ### API Changes
1911
+
1912
+ **`/api/hazo_auth/me` now includes user type info**:
1913
+ ```typescript
1914
+ {
1915
+ authenticated: true,
1916
+ // ... existing fields
1917
+ user_type: "client", // User's type key
1918
+ user_type_info: { // Type details
1919
+ key: "client",
1920
+ label: "Client",
1921
+ badge_color: "green"
1922
+ }
1923
+ }
1924
+ ```
1925
+
1926
+ **New endpoint `/api/hazo_auth/user_management/user_types`** (GET):
1927
+ Returns user types configuration for populating dropdowns.
1928
+
1929
+ ### UserTypeBadge Component
1930
+
1931
+ Display user types with color-coded badges:
1932
+
1933
+ ```typescript
1934
+ import { UserTypeBadge } from "hazo_auth/components/ui/user-type-badge";
1935
+
1936
+ <UserTypeBadge
1937
+ type="client"
1938
+ label="Client"
1939
+ badge_color="green"
1940
+ variant="badge" // or "text" for plain text
1941
+ />
1942
+ ```
1943
+
1944
+ ### Example Configurations
1945
+
1946
+ **Simple Premium/Standard tiers**:
1947
+ ```ini
1948
+ [hazo_auth__user_types]
1949
+ enable_user_types = true
1950
+ default_user_type = standard
1951
+ user_type_1 = standard:Standard:blue
1952
+ user_type_2 = premium:Premium:#FFD700
1953
+ ```
1954
+
1955
+ **Tax accounting personas**:
1956
+ ```ini
1957
+ [hazo_auth__user_types]
1958
+ enable_user_types = true
1959
+ user_type_1 = client:Client:green
1960
+ user_type_2 = tax_agent:Tax Agent:orange
1961
+ user_type_3 = bookkeeper:Bookkeeper:blue
1962
+ ```
1963
+
1964
+ ### Key Differences from RBAC
1965
+
1966
+ | Feature | User Types | Roles |
1967
+ |---------|-----------|-------|
1968
+ | **Purpose** | Categorize/label users | Control permissions |
1969
+ | **Configuration** | INI file | Database + UI |
1970
+ | **Assignment** | One type per user | Multiple roles per user |
1971
+ | **Example** | "Client", "Agent" | "Admin", "Editor" |
1972
+ | **Use case** | Visual identification | Access control |
1973
+
1974
+ A user can have type "Client" with role "Admin" - types and roles are independent.
1975
+
1976
+ ### Default Type Assignment
1977
+
1978
+ New registrations automatically receive the `default_user_type` when configured:
1979
+
1980
+ ```ini
1981
+ [hazo_auth__user_types]
1982
+ enable_user_types = true
1983
+ default_user_type = standard # New users get "standard" type
1984
+ ```
1985
+
1986
+ For full documentation, see `CLAUDE.md` or `TECHDOC.md`.
1987
+
1988
+ ---
1989
+
1788
1990
  ## User Profile Service
1789
1991
 
1790
1992
  The `hazo_auth` package provides a batch user profile retrieval service for applications that need basic user information, such as chat applications or user lists.
@@ -1171,7 +1171,7 @@ Add to your `hazo_auth_config.ini`:
1171
1171
  ```ini
1172
1172
  [hazo_auth__scope_hierarchy]
1173
1173
  enable_hrbac = true
1174
- default_org = my_organization
1174
+ # Note: No default_org needed - org determined from user authentication
1175
1175
  scope_cache_ttl_minutes = 15
1176
1176
  scope_cache_max_entries = 5000
1177
1177
 
@@ -32,6 +32,7 @@ export type ScopeAccessInfo = {
32
32
  * Result type for hazo_get_auth function
33
33
  * Returns authenticated state with user data and permissions, or unauthenticated state
34
34
  * Optionally includes scope access information when HRBAC is used
35
+ * Optionally includes org_ok when require_org option is used
35
36
  */
36
37
  export type HazoAuthResult =
37
38
  | {
@@ -43,6 +44,8 @@ export type HazoAuthResult =
43
44
  // HRBAC scope access fields (only present when scope options are provided)
44
45
  scope_ok?: boolean;
45
46
  scope_access_via?: ScopeAccessInfo;
47
+ // Multi-tenancy org check (only present when require_org option is used)
48
+ org_ok?: boolean;
46
49
  }
47
50
  | {
48
51
  authenticated: false;
@@ -50,6 +53,7 @@ export type HazoAuthResult =
50
53
  permissions: [];
51
54
  permission_ok: false;
52
55
  scope_ok?: false;
56
+ org_ok?: false;
53
57
  };
54
58
 
55
59
  /**
@@ -82,6 +86,13 @@ export type HazoAuthOptions = {
82
86
  * Used if scope_id is not provided
83
87
  */
84
88
  scope_seq?: string;
89
+ // Multi-tenancy options
90
+ /**
91
+ * If true, throws OrgRequiredError when user has no org_id assigned
92
+ * Only checked when multi-tenancy is enabled
93
+ * If false or not set (default), org_id is optional and org fields may be null
94
+ */
95
+ require_org?: boolean;
85
96
  };
86
97
 
87
98
  /**
@@ -115,3 +126,14 @@ export class ScopeAccessError extends Error {
115
126
  }
116
127
  }
117
128
 
129
+ /**
130
+ * Custom error class for missing organization assignment
131
+ * Thrown when require_org: true is set but user has no org_id assigned
132
+ */
133
+ export class OrgRequiredError extends Error {
134
+ constructor(public user_id: string) {
135
+ super(`User ${user_id} is not assigned to an organization`);
136
+ this.name = "OrgRequiredError";
137
+ }
138
+ }
139
+
@@ -6,7 +6,7 @@ import { createCrudService } from "hazo_connect/server";
6
6
  import { create_app_logger } from "../app_logger.js";
7
7
  import { get_filename, get_line_number } from "../utils/api_route_helpers.js";
8
8
  import type { HazoAuthResult, HazoAuthUser, HazoAuthOptions, ScopeAccessInfo } from "./auth_types";
9
- import { PermissionError, ScopeAccessError } from "./auth_types.js";
9
+ import { PermissionError, ScopeAccessError, OrgRequiredError } from "./auth_types.js";
10
10
  import { get_auth_cache } from "./auth_cache.js";
11
11
  import { get_scope_cache, type UserScopeEntry } from "./scope_cache.js";
12
12
  import { get_rate_limiter } from "./auth_rate_limiter.js";
@@ -570,6 +570,29 @@ export async function hazo_get_auth(
570
570
  }
571
571
  }
572
572
 
573
+ // Check org requirement if specified (only when multi-tenancy is enabled)
574
+ let org_ok: boolean | undefined;
575
+
576
+ if (options?.require_org && is_multi_tenancy_enabled()) {
577
+ org_ok = !!user.org_id;
578
+
579
+ if (!org_ok) {
580
+ // Log org requirement failure if permission logging is enabled
581
+ if (config.log_permission_denials) {
582
+ const client_ip = get_client_ip(request);
583
+ logger.warn("auth_utility_org_required_missing", {
584
+ filename: get_filename(),
585
+ line_number: get_line_number(),
586
+ user_id: user.id,
587
+ ip: client_ip,
588
+ });
589
+ }
590
+
591
+ // Always throw error when org is required but missing
592
+ throw new OrgRequiredError(user.id);
593
+ }
594
+ }
595
+
573
596
  return {
574
597
  authenticated: true,
575
598
  user,
@@ -578,6 +601,7 @@ export async function hazo_get_auth(
578
601
  missing_permissions,
579
602
  scope_ok,
580
603
  scope_access_via,
604
+ org_ok,
581
605
  };
582
606
  }
583
607
 
@@ -93,3 +93,4 @@ export async function validate_session_cookie(
93
93
 
94
94
 
95
95
 
96
+
@@ -177,6 +177,40 @@ export const DEFAULT_MULTI_TENANCY = {
177
177
  default_user_limit: 0,
178
178
  } as const;
179
179
 
180
+ // section: navbar
181
+ export const DEFAULT_NAVBAR = {
182
+ /** Enable navbar on auth pages */
183
+ enable_navbar: true,
184
+ /** Logo image path (default: /logo.png in public folder) */
185
+ logo_path: "/logo.png",
186
+ /** Logo width in pixels */
187
+ logo_width: 32,
188
+ /** Logo height in pixels */
189
+ logo_height: 32,
190
+ /** Company/application name displayed next to logo */
191
+ company_name: "",
192
+ /** Home link path */
193
+ home_path: "/",
194
+ /** Home link label */
195
+ home_label: "Home",
196
+ /** Show home link */
197
+ show_home_link: true,
198
+ /** Navbar background color (empty = transparent/inherit) */
199
+ background_color: "",
200
+ /** Navbar text color (empty = inherit) */
201
+ text_color: "",
202
+ /** Navbar height in pixels */
203
+ height: 64,
204
+ } as const;
205
+
206
+ // section: user_types
207
+ export const DEFAULT_USER_TYPES = {
208
+ /** Enable user types feature (default: false) */
209
+ enable_user_types: false,
210
+ /** Default user type for new users (empty = no default) */
211
+ default_user_type: "",
212
+ } as const;
213
+
180
214
  // section: dev_lock
181
215
  export const DEFAULT_DEV_LOCK = {
182
216
  /** Enable the development lock screen (also requires HAZO_AUTH_DEV_LOCK_ENABLED env var) */
@@ -234,6 +268,8 @@ export const HAZO_AUTH_DEFAULTS = {
234
268
  oauth: DEFAULT_OAUTH,
235
269
  devLock: DEFAULT_DEV_LOCK,
236
270
  multiTenancy: DEFAULT_MULTI_TENANCY,
271
+ navbar: DEFAULT_NAVBAR,
272
+ userTypes: DEFAULT_USER_TYPES,
237
273
  } as const;
238
274
 
239
275
  // section: types
@@ -0,0 +1,129 @@
1
+ // file_description: server-only helper to read navbar configuration from hazo_auth_config.ini
2
+ // section: imports
3
+ import { get_config_value, get_config_boolean, get_config_number } from "./config/config_loader.server.js";
4
+ import { DEFAULT_NAVBAR } from "./config/default_config.js";
5
+
6
+ // section: types
7
+ export type NavbarConfig = {
8
+ /** Enable navbar on auth pages */
9
+ enable_navbar: boolean;
10
+ /** Logo image path */
11
+ logo_path: string;
12
+ /** Logo width in pixels */
13
+ logo_width: number;
14
+ /** Logo height in pixels */
15
+ logo_height: number;
16
+ /** Company/application name displayed next to logo */
17
+ company_name: string;
18
+ /** Home link path */
19
+ home_path: string;
20
+ /** Home link label */
21
+ home_label: string;
22
+ /** Show home link */
23
+ show_home_link: boolean;
24
+ /** Navbar background color (empty = inherit) */
25
+ background_color: string;
26
+ /** Navbar text color (empty = inherit) */
27
+ text_color: string;
28
+ /** Navbar height in pixels */
29
+ height: number;
30
+ };
31
+
32
+ // section: constants
33
+ const SECTION_NAME = "hazo_auth__navbar";
34
+
35
+ // section: helpers
36
+ /**
37
+ * Reads navbar configuration from hazo_auth_config.ini file
38
+ * Falls back to defaults if hazo_auth_config.ini is not found or section is missing
39
+ * @returns Navbar configuration options
40
+ */
41
+ export function get_navbar_config(): NavbarConfig {
42
+ const enable_navbar = get_config_boolean(
43
+ SECTION_NAME,
44
+ "enable_navbar",
45
+ DEFAULT_NAVBAR.enable_navbar
46
+ );
47
+
48
+ const logo_path = get_config_value(
49
+ SECTION_NAME,
50
+ "logo_path",
51
+ DEFAULT_NAVBAR.logo_path
52
+ );
53
+
54
+ const logo_width = get_config_number(
55
+ SECTION_NAME,
56
+ "logo_width",
57
+ DEFAULT_NAVBAR.logo_width
58
+ );
59
+
60
+ const logo_height = get_config_number(
61
+ SECTION_NAME,
62
+ "logo_height",
63
+ DEFAULT_NAVBAR.logo_height
64
+ );
65
+
66
+ const company_name = get_config_value(
67
+ SECTION_NAME,
68
+ "company_name",
69
+ DEFAULT_NAVBAR.company_name
70
+ );
71
+
72
+ const home_path = get_config_value(
73
+ SECTION_NAME,
74
+ "home_path",
75
+ DEFAULT_NAVBAR.home_path
76
+ );
77
+
78
+ const home_label = get_config_value(
79
+ SECTION_NAME,
80
+ "home_label",
81
+ DEFAULT_NAVBAR.home_label
82
+ );
83
+
84
+ const show_home_link = get_config_boolean(
85
+ SECTION_NAME,
86
+ "show_home_link",
87
+ DEFAULT_NAVBAR.show_home_link
88
+ );
89
+
90
+ const background_color = get_config_value(
91
+ SECTION_NAME,
92
+ "background_color",
93
+ DEFAULT_NAVBAR.background_color
94
+ );
95
+
96
+ const text_color = get_config_value(
97
+ SECTION_NAME,
98
+ "text_color",
99
+ DEFAULT_NAVBAR.text_color
100
+ );
101
+
102
+ const height = get_config_number(
103
+ SECTION_NAME,
104
+ "height",
105
+ DEFAULT_NAVBAR.height
106
+ );
107
+
108
+ return {
109
+ enable_navbar,
110
+ logo_path,
111
+ logo_width,
112
+ logo_height,
113
+ company_name,
114
+ home_path,
115
+ home_label,
116
+ show_home_link,
117
+ background_color,
118
+ text_color,
119
+ height,
120
+ };
121
+ }
122
+
123
+ /**
124
+ * Helper to check if navbar is enabled in config
125
+ * @returns true if navbar is enabled
126
+ */
127
+ export function is_navbar_enabled(): boolean {
128
+ return get_config_boolean(SECTION_NAME, "enable_navbar", DEFAULT_NAVBAR.enable_navbar);
129
+ }
@@ -13,12 +13,12 @@ import { SCOPE_LEVELS } from "./services/scope_service.js";
13
13
 
14
14
  /**
15
15
  * Scope hierarchy configuration options for HRBAC
16
+ * Note: Scopes are now connected to organizations via org_id and root_org_id
17
+ * foreign keys referencing the hazo_org table.
16
18
  */
17
19
  export type ScopeHierarchyConfig = {
18
20
  /** Whether HRBAC is enabled (default: false) */
19
21
  enable_hrbac: boolean;
20
- /** Default organization for single-tenant apps (optional) */
21
- default_org: string;
22
22
  /** Cache TTL in minutes for scope lookups (default: 15) */
23
23
  scope_cache_ttl_minutes: number;
24
24
  /** Maximum entries in scope cache (default: 5000) */
@@ -88,15 +88,13 @@ function get_default_labels(): Record<ScopeLevel, string> {
88
88
  /**
89
89
  * Reads HRBAC scope hierarchy configuration from hazo_auth_config.ini file
90
90
  * Falls back to defaults if config file is not found or section is missing
91
+ * Note: Scopes are now connected to organizations via org_id/root_org_id FK references
91
92
  * @returns Scope hierarchy configuration options
92
93
  */
93
94
  export function get_scope_hierarchy_config(): ScopeHierarchyConfig {
94
95
  // Core HRBAC enablement
95
96
  const enable_hrbac = get_config_boolean(SECTION_NAME, "enable_hrbac", false);
96
97
 
97
- // Default organization for single-tenant apps
98
- const default_org = get_config_value(SECTION_NAME, "default_org", "");
99
-
100
98
  // Cache settings
101
99
  const scope_cache_ttl_minutes = get_config_number(
102
100
  SECTION_NAME,
@@ -118,7 +116,6 @@ export function get_scope_hierarchy_config(): ScopeHierarchyConfig {
118
116
 
119
117
  return {
120
118
  enable_hrbac,
121
- default_org,
122
119
  scope_cache_ttl_minutes,
123
120
  scope_cache_max_entries,
124
121
  active_levels,
@@ -134,14 +131,6 @@ export function is_hrbac_enabled(): boolean {
134
131
  return get_config_boolean(SECTION_NAME, "enable_hrbac", false);
135
132
  }
136
133
 
137
- /**
138
- * Gets the default organization from config
139
- * Returns empty string if not configured (multi-tenant mode)
140
- */
141
- export function get_default_org(): string {
142
- return get_config_value(SECTION_NAME, "default_org", "");
143
- }
144
-
145
134
  /**
146
135
  * Gets the default label for a scope level
147
136
  */
@@ -12,6 +12,10 @@ import { create_app_logger } from "../app_logger.js";
12
12
  import { send_template_email } from "./email_service.js";
13
13
  import { sanitize_error_for_user } from "../utils/error_sanitizer.js";
14
14
  import { get_filename, get_line_number } from "../utils/api_route_helpers.js";
15
+ import {
16
+ is_user_types_enabled,
17
+ get_default_user_type,
18
+ } from "../user_types_config.server.js";
15
19
 
16
20
  // section: types
17
21
  export type RegistrationData = {
@@ -100,6 +104,14 @@ export async function register_user(
100
104
  }
101
105
  }
102
106
 
107
+ // Set default user type if feature is enabled and default is configured
108
+ if (is_user_types_enabled()) {
109
+ const default_type = get_default_user_type();
110
+ if (default_type) {
111
+ insert_data.user_type = default_type;
112
+ }
113
+ }
114
+
103
115
  const inserted_users = await users_service.insert(insert_data);
104
116
 
105
117
  // Verify insertion was successful