hazo_auth 1.6.1 → 1.6.4
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/README.md +259 -1
- package/SETUP_CHECKLIST.md +89 -3
- package/dist/app/api/hazo_auth/me/route.d.ts +30 -1
- package/dist/app/api/hazo_auth/me/route.d.ts.map +1 -1
- package/dist/app/api/hazo_auth/me/route.js +76 -16
- package/dist/cli/init.d.ts.map +1 -1
- package/dist/cli/init.js +5 -0
- package/dist/client.d.ts +8 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +25 -0
- package/dist/components/layouts/email_verification/index.d.ts +2 -1
- package/dist/components/layouts/email_verification/index.d.ts.map +1 -1
- package/dist/components/layouts/email_verification/index.js +3 -2
- package/dist/components/layouts/forgot_password/index.d.ts +3 -1
- package/dist/components/layouts/forgot_password/index.d.ts.map +1 -1
- package/dist/components/layouts/forgot_password/index.js +3 -2
- package/dist/components/layouts/my_settings/components/editable_field.js +1 -1
- package/dist/components/layouts/my_settings/components/password_change_dialog.js +1 -1
- package/dist/components/layouts/my_settings/components/profile_picture_display.js +1 -1
- package/dist/components/layouts/my_settings/components/profile_picture_gravatar_tab.js +1 -1
- package/dist/components/layouts/my_settings/components/profile_picture_library_tab.js +4 -4
- package/dist/components/layouts/my_settings/components/profile_picture_upload_tab.js +4 -4
- package/dist/components/layouts/my_settings/index.js +1 -1
- package/dist/components/layouts/shared/components/profile_pic_menu.d.ts +6 -2
- package/dist/components/layouts/shared/components/profile_pic_menu.d.ts.map +1 -1
- package/dist/components/layouts/shared/components/profile_pic_menu.js +41 -6
- package/dist/components/layouts/shared/components/profile_pic_menu_wrapper.d.ts +4 -2
- package/dist/components/layouts/shared/components/profile_pic_menu_wrapper.d.ts.map +1 -1
- package/dist/components/layouts/shared/components/profile_pic_menu_wrapper.js +3 -3
- package/dist/components/layouts/shared/components/sidebar_layout_wrapper.d.ts.map +1 -1
- package/dist/components/layouts/shared/components/sidebar_layout_wrapper.js +2 -2
- package/dist/components/layouts/shared/hooks/use_auth_status.d.ts +3 -0
- package/dist/components/layouts/shared/hooks/use_auth_status.d.ts.map +1 -1
- package/dist/components/layouts/shared/hooks/use_auth_status.js +4 -0
- package/dist/lib/auth_utility_config.server.js +2 -2
- package/dist/lib/services/user_profiles_cache.d.ts +76 -0
- package/dist/lib/services/user_profiles_cache.d.ts.map +1 -0
- package/dist/lib/services/user_profiles_cache.js +141 -0
- package/dist/lib/services/user_profiles_service.d.ts +17 -0
- package/dist/lib/services/user_profiles_service.d.ts.map +1 -1
- package/dist/lib/services/user_profiles_service.js +136 -44
- package/dist/lib/user_profiles_config.server.d.ts +15 -0
- package/dist/lib/user_profiles_config.server.d.ts.map +1 -0
- package/dist/lib/user_profiles_config.server.js +23 -0
- package/hazo_auth_config.example.ini +25 -5
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -106,6 +106,132 @@ import { hazo_get_auth } from "hazo_auth/lib/auth/hazo_get_auth.server";
|
|
|
106
106
|
|
|
107
107
|
---
|
|
108
108
|
|
|
109
|
+
## Required Dependencies
|
|
110
|
+
|
|
111
|
+
hazo_auth uses shadcn/ui components. Install the required dependencies in your project:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
# Required for all auth pages
|
|
115
|
+
npx shadcn@latest add button input label
|
|
116
|
+
|
|
117
|
+
# Required for My Settings page
|
|
118
|
+
npx shadcn@latest add dialog tabs switch avatar dropdown-menu
|
|
119
|
+
|
|
120
|
+
# Required for toast notifications
|
|
121
|
+
npx shadcn@latest add sonner
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
**Add Toaster to your app layout:**
|
|
125
|
+
|
|
126
|
+
```tsx
|
|
127
|
+
// app/layout.tsx
|
|
128
|
+
import { Toaster } from "sonner";
|
|
129
|
+
|
|
130
|
+
export default function RootLayout({ children }) {
|
|
131
|
+
return (
|
|
132
|
+
<html>
|
|
133
|
+
<body>
|
|
134
|
+
{children}
|
|
135
|
+
<Toaster />
|
|
136
|
+
</body>
|
|
137
|
+
</html>
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Client vs Server Imports
|
|
145
|
+
|
|
146
|
+
hazo_auth provides separate entry points for client and server code to avoid bundling Node.js modules in the browser:
|
|
147
|
+
|
|
148
|
+
### Client Components
|
|
149
|
+
|
|
150
|
+
For client components (browser-safe, no Node.js dependencies):
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
// Use hazo_auth/client for client components
|
|
154
|
+
import {
|
|
155
|
+
ProfilePicMenu,
|
|
156
|
+
use_auth_status,
|
|
157
|
+
use_hazo_auth,
|
|
158
|
+
cn
|
|
159
|
+
} from "hazo_auth/client";
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Server Components / API Routes
|
|
163
|
+
|
|
164
|
+
For server-side code (API routes, Server Components):
|
|
165
|
+
|
|
166
|
+
```typescript
|
|
167
|
+
// Use the main hazo_auth export for server-side code
|
|
168
|
+
import { hazo_get_auth, get_config_value } from "hazo_auth";
|
|
169
|
+
import { hazo_get_user_profiles } from "hazo_auth";
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Why This Matters
|
|
173
|
+
|
|
174
|
+
If you import from the main `hazo_auth` entry in a client component, you'll get bundling errors like:
|
|
175
|
+
```
|
|
176
|
+
Module not found: Can't resolve 'fs'
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Use `hazo_auth/client` to avoid this.
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## Dark Mode / Theming
|
|
184
|
+
|
|
185
|
+
hazo_auth supports dark mode via CSS custom properties. To enable dark mode:
|
|
186
|
+
|
|
187
|
+
### 1. Import the theme CSS
|
|
188
|
+
|
|
189
|
+
Copy the variables file to your project:
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
cp node_modules/hazo_auth/src/styles/hazo-auth-variables.css ./app/hazo-auth-theme.css
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Import in your `globals.css`:
|
|
196
|
+
|
|
197
|
+
```css
|
|
198
|
+
@import "./hazo-auth-theme.css";
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### 2. CSS Variables Reference
|
|
202
|
+
|
|
203
|
+
You can customize the theme by overriding these variables:
|
|
204
|
+
|
|
205
|
+
```css
|
|
206
|
+
:root {
|
|
207
|
+
/* Backgrounds */
|
|
208
|
+
--hazo-bg-subtle: #f8fafc; /* Light background */
|
|
209
|
+
--hazo-bg-muted: #f1f5f9; /* Slightly darker background */
|
|
210
|
+
|
|
211
|
+
/* Text */
|
|
212
|
+
--hazo-text-primary: #0f172a; /* Primary text */
|
|
213
|
+
--hazo-text-secondary: #334155; /* Secondary text */
|
|
214
|
+
--hazo-text-muted: #64748b; /* Muted/subtle text */
|
|
215
|
+
|
|
216
|
+
/* Borders */
|
|
217
|
+
--hazo-border: #e2e8f0; /* Standard border */
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
.dark {
|
|
221
|
+
/* Dark mode overrides */
|
|
222
|
+
--hazo-bg-subtle: #18181b;
|
|
223
|
+
--hazo-bg-muted: #27272a;
|
|
224
|
+
--hazo-text-primary: #fafafa;
|
|
225
|
+
--hazo-text-secondary: #d4d4d8;
|
|
226
|
+
--hazo-text-muted: #a1a1aa;
|
|
227
|
+
--hazo-border: #3f3f46;
|
|
228
|
+
}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
The dark class is typically added by next-themes or similar theme providers.
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
109
235
|
## Configuration Setup
|
|
110
236
|
|
|
111
237
|
After installing the package, you need to set up configuration files in your project root:
|
|
@@ -554,6 +680,76 @@ layout_mode = standalone
|
|
|
554
680
|
|
|
555
681
|
The `hazo_auth` package provides a comprehensive authentication and authorization system with role-based access control (RBAC). The main authentication utility is `hazo_get_auth`, which provides user details, permissions, and permission checking with built-in caching and rate limiting.
|
|
556
682
|
|
|
683
|
+
### Client-Side API Endpoint (Recommended)
|
|
684
|
+
|
|
685
|
+
#### `/api/hazo_auth/me` (GET) - Standardized User Info Endpoint
|
|
686
|
+
|
|
687
|
+
**⚠️ IMPORTANT: Use this endpoint for all client-side authentication checks. It always returns the same standardized format with permissions.**
|
|
688
|
+
|
|
689
|
+
This is the **standardized endpoint** that ensures consistent response format across all projects. It always includes permissions and user information in a unified structure.
|
|
690
|
+
|
|
691
|
+
**Endpoint:** `GET /api/hazo_auth/me`
|
|
692
|
+
|
|
693
|
+
**Response Format (Authenticated):**
|
|
694
|
+
```typescript
|
|
695
|
+
{
|
|
696
|
+
authenticated: true,
|
|
697
|
+
// Top-level fields (for backward compatibility)
|
|
698
|
+
user_id: string,
|
|
699
|
+
email: string,
|
|
700
|
+
name: string | null,
|
|
701
|
+
email_verified: boolean,
|
|
702
|
+
last_logon: string | undefined,
|
|
703
|
+
profile_picture_url: string | null,
|
|
704
|
+
profile_source: "upload" | "library" | "gravatar" | "custom" | undefined,
|
|
705
|
+
// Permissions (always included)
|
|
706
|
+
user: {
|
|
707
|
+
id: string,
|
|
708
|
+
email_address: string,
|
|
709
|
+
name: string | null,
|
|
710
|
+
is_active: boolean,
|
|
711
|
+
profile_picture_url: string | null,
|
|
712
|
+
},
|
|
713
|
+
permissions: string[],
|
|
714
|
+
permission_ok: boolean,
|
|
715
|
+
missing_permissions?: string[],
|
|
716
|
+
}
|
|
717
|
+
```
|
|
718
|
+
|
|
719
|
+
**Response Format (Not Authenticated):**
|
|
720
|
+
```typescript
|
|
721
|
+
{
|
|
722
|
+
authenticated: false
|
|
723
|
+
}
|
|
724
|
+
```
|
|
725
|
+
|
|
726
|
+
**Example Usage:**
|
|
727
|
+
|
|
728
|
+
```typescript
|
|
729
|
+
// Client-side (React component)
|
|
730
|
+
const response = await fetch("/api/hazo_auth/me", {
|
|
731
|
+
method: "GET",
|
|
732
|
+
credentials: "include",
|
|
733
|
+
});
|
|
734
|
+
|
|
735
|
+
const data = await response.json();
|
|
736
|
+
|
|
737
|
+
if (data.authenticated) {
|
|
738
|
+
console.log("User:", data.user);
|
|
739
|
+
console.log("Email:", data.email);
|
|
740
|
+
console.log("Permissions:", data.permissions);
|
|
741
|
+
console.log("Permission OK:", data.permission_ok);
|
|
742
|
+
}
|
|
743
|
+
```
|
|
744
|
+
|
|
745
|
+
**Why Use `/api/hazo_auth/me`?**
|
|
746
|
+
- ✅ **Standardized format** - Always returns the same structure
|
|
747
|
+
- ✅ **Always includes permissions** - No need for separate permission checks
|
|
748
|
+
- ✅ **Backward compatible** - Top-level fields work with existing code
|
|
749
|
+
- ✅ **Single source of truth** - Prevents downstream variations
|
|
750
|
+
|
|
751
|
+
**Note:** The `use_auth_status` hook automatically uses this endpoint and includes permissions in its return value.
|
|
752
|
+
|
|
557
753
|
### Server-Side Functions
|
|
558
754
|
|
|
559
755
|
#### `hazo_get_auth` (Recommended)
|
|
@@ -791,13 +987,22 @@ enable_friendly_error_messages = true
|
|
|
791
987
|
## Profile Picture Menu Widget
|
|
792
988
|
|
|
793
989
|
The Profile Picture Menu is a versatile component for navbar or sidebar that automatically displays:
|
|
794
|
-
- **When authenticated**: User's profile picture with a dropdown menu containing user info, settings link, logout, and custom menu items
|
|
990
|
+
- **When authenticated**: User's profile picture with a dropdown menu (navbar) or sidebar menu (sidebar) containing user info, settings link, logout, and custom menu items
|
|
795
991
|
- **When not authenticated**: Sign Up and Sign In buttons (or a single button, configurable)
|
|
796
992
|
|
|
993
|
+
### Variants
|
|
994
|
+
|
|
995
|
+
The component supports two rendering variants:
|
|
996
|
+
|
|
997
|
+
- **`dropdown`** (default): Renders as a clickable avatar that opens a dropdown menu. Use this for navbar/header contexts.
|
|
998
|
+
- **`sidebar`**: Shows profile picture and name in a sidebar group. Clicking opens a dropdown menu with account actions. Use this inside `SidebarContent` for sidebar navigation.
|
|
999
|
+
|
|
797
1000
|
### Basic Usage (Recommended)
|
|
798
1001
|
|
|
799
1002
|
Use the `ProfilePicMenuWrapper` component which automatically loads configuration from `hazo_auth_config.ini`:
|
|
800
1003
|
|
|
1004
|
+
#### Dropdown Variant (Navbar/Header)
|
|
1005
|
+
|
|
801
1006
|
```typescript
|
|
802
1007
|
// In your navbar or layout component
|
|
803
1008
|
import { ProfilePicMenuWrapper } from "hazo_auth/components/layouts/shared/components/profile_pic_menu_wrapper";
|
|
@@ -809,12 +1014,65 @@ export function Navbar() {
|
|
|
809
1014
|
<ProfilePicMenuWrapper
|
|
810
1015
|
avatar_size="default" // "sm" | "default" | "lg"
|
|
811
1016
|
className="ml-auto"
|
|
1017
|
+
// variant="dropdown" is the default
|
|
812
1018
|
/>
|
|
813
1019
|
</nav>
|
|
814
1020
|
);
|
|
815
1021
|
}
|
|
816
1022
|
```
|
|
817
1023
|
|
|
1024
|
+
#### Sidebar Variant
|
|
1025
|
+
|
|
1026
|
+
The sidebar variant shows only the profile picture and name. Clicking opens a dropdown menu with account actions:
|
|
1027
|
+
|
|
1028
|
+
```typescript
|
|
1029
|
+
// In your sidebar component
|
|
1030
|
+
import { ProfilePicMenu } from "hazo_auth/components/layouts/shared";
|
|
1031
|
+
import { SidebarContent } from "hazo_auth/components/ui/sidebar";
|
|
1032
|
+
|
|
1033
|
+
export function Sidebar() {
|
|
1034
|
+
return (
|
|
1035
|
+
<SidebarContent>
|
|
1036
|
+
{/* Other sidebar groups */}
|
|
1037
|
+
|
|
1038
|
+
{/* Profile menu as sidebar variant - shows avatar + name, clicking opens dropdown */}
|
|
1039
|
+
<ProfilePicMenu
|
|
1040
|
+
variant="sidebar"
|
|
1041
|
+
avatar_size="sm"
|
|
1042
|
+
sidebar_group_label="Account" // Optional: defaults to "Account"
|
|
1043
|
+
className="mt-auto" // Optional: push to bottom
|
|
1044
|
+
/>
|
|
1045
|
+
</SidebarContent>
|
|
1046
|
+
);
|
|
1047
|
+
}
|
|
1048
|
+
```
|
|
1049
|
+
|
|
1050
|
+
### Direct Usage (Advanced)
|
|
1051
|
+
|
|
1052
|
+
If you need more control, use `ProfilePicMenu` directly:
|
|
1053
|
+
|
|
1054
|
+
```typescript
|
|
1055
|
+
import { ProfilePicMenu } from "hazo_auth/components/layouts/shared";
|
|
1056
|
+
|
|
1057
|
+
// Dropdown variant (navbar)
|
|
1058
|
+
<ProfilePicMenu
|
|
1059
|
+
variant="dropdown"
|
|
1060
|
+
avatar_size="sm"
|
|
1061
|
+
settings_path="/settings"
|
|
1062
|
+
logout_path="/api/logout"
|
|
1063
|
+
/>
|
|
1064
|
+
|
|
1065
|
+
// Sidebar variant
|
|
1066
|
+
<ProfilePicMenu
|
|
1067
|
+
variant="sidebar"
|
|
1068
|
+
avatar_size="sm"
|
|
1069
|
+
sidebar_group_label="My Account"
|
|
1070
|
+
custom_menu_items={[
|
|
1071
|
+
{ type: "link", label: "Dashboard", href: "/dashboard", order: 1, id: "dashboard" }
|
|
1072
|
+
]}
|
|
1073
|
+
/>
|
|
1074
|
+
```
|
|
1075
|
+
|
|
818
1076
|
### Configuration
|
|
819
1077
|
|
|
820
1078
|
```ini
|
package/SETUP_CHECKLIST.md
CHANGED
|
@@ -60,7 +60,61 @@ ls node_modules/hazo_auth/package.json
|
|
|
60
60
|
# Expected: file exists
|
|
61
61
|
```
|
|
62
62
|
|
|
63
|
-
### Step 1.2:
|
|
63
|
+
### Step 1.2: Install Required shadcn/ui Components
|
|
64
|
+
|
|
65
|
+
hazo_auth uses shadcn/ui components. Install the required dependencies:
|
|
66
|
+
|
|
67
|
+
**For all auth pages (login, register, etc.):**
|
|
68
|
+
```bash
|
|
69
|
+
npx shadcn@latest add button input label
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**For My Settings page:**
|
|
73
|
+
```bash
|
|
74
|
+
npx shadcn@latest add dialog tabs switch avatar dropdown-menu
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**For toast notifications:**
|
|
78
|
+
```bash
|
|
79
|
+
npx shadcn@latest add sonner
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
**Add Toaster to your app layout:**
|
|
83
|
+
|
|
84
|
+
Edit `app/layout.tsx` and add the Toaster component:
|
|
85
|
+
|
|
86
|
+
```tsx
|
|
87
|
+
import { Toaster } from "sonner";
|
|
88
|
+
|
|
89
|
+
export default function RootLayout({ children }) {
|
|
90
|
+
return (
|
|
91
|
+
<html>
|
|
92
|
+
<body>
|
|
93
|
+
{children}
|
|
94
|
+
<Toaster />
|
|
95
|
+
</body>
|
|
96
|
+
</html>
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Step 1.4: Enable Dark Mode Support (Optional)
|
|
102
|
+
|
|
103
|
+
hazo_auth components support dark mode via CSS custom properties. Add the CSS variables to your global styles:
|
|
104
|
+
|
|
105
|
+
**Copy the CSS variables file:**
|
|
106
|
+
```bash
|
|
107
|
+
cp node_modules/hazo_auth/src/styles/hazo-auth-variables.css ./app/hazo-auth-theme.css
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
**Import in your global styles (`app/globals.css`):**
|
|
111
|
+
```css
|
|
112
|
+
@import "./hazo-auth-theme.css";
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Or add the variables directly to your CSS - see the file for all available variables.
|
|
116
|
+
|
|
117
|
+
### Step 1.5: Initialize project (Recommended)
|
|
64
118
|
|
|
65
119
|
Use the CLI to automatically set up directories and copy config files:
|
|
66
120
|
|
|
@@ -562,19 +616,51 @@ export default function CustomLoginPage() {
|
|
|
562
616
|
|
|
563
617
|
Run these tests to verify your setup is working correctly.
|
|
564
618
|
|
|
565
|
-
### Test 1: API Health Check
|
|
619
|
+
### Test 1: API Health Check - Standardized `/api/hazo_auth/me` Endpoint
|
|
620
|
+
|
|
621
|
+
**⚠️ IMPORTANT: Use `/api/hazo_auth/me` for all client-side authentication checks. It always returns a standardized format with permissions.**
|
|
566
622
|
|
|
567
623
|
```bash
|
|
568
624
|
curl -s http://localhost:3000/api/hazo_auth/me | jq
|
|
569
625
|
```
|
|
570
626
|
|
|
571
|
-
**Expected response:**
|
|
627
|
+
**Expected response (not authenticated):**
|
|
572
628
|
```json
|
|
573
629
|
{
|
|
574
630
|
"authenticated": false
|
|
575
631
|
}
|
|
576
632
|
```
|
|
577
633
|
|
|
634
|
+
**Expected response (authenticated - standardized format):**
|
|
635
|
+
```json
|
|
636
|
+
{
|
|
637
|
+
"authenticated": true,
|
|
638
|
+
"user_id": "28fe0aff-29c7-407e-b92e-bf11a6a3332f",
|
|
639
|
+
"email": "test@example.com",
|
|
640
|
+
"name": "Test User",
|
|
641
|
+
"email_verified": false,
|
|
642
|
+
"last_logon": "2025-01-27T16:18:00.054Z",
|
|
643
|
+
"profile_picture_url": "https://gravatar.com/avatar/...",
|
|
644
|
+
"profile_source": "gravatar",
|
|
645
|
+
"user": {
|
|
646
|
+
"id": "28fe0aff-29c7-407e-b92e-bf11a6a3332f",
|
|
647
|
+
"email_address": "test@example.com",
|
|
648
|
+
"name": "Test User",
|
|
649
|
+
"is_active": true,
|
|
650
|
+
"profile_picture_url": "https://gravatar.com/avatar/..."
|
|
651
|
+
},
|
|
652
|
+
"permissions": [],
|
|
653
|
+
"permission_ok": true
|
|
654
|
+
}
|
|
655
|
+
```
|
|
656
|
+
|
|
657
|
+
**Key Points:**
|
|
658
|
+
- ✅ Always returns the same standardized format
|
|
659
|
+
- ✅ Always includes `permissions` and `permission_ok` fields
|
|
660
|
+
- ✅ Top-level fields (`user_id`, `email`, `name`) for backward compatibility
|
|
661
|
+
- ✅ `user` object contains full user details
|
|
662
|
+
- ✅ Use this endpoint instead of `/api/hazo_auth/get_auth` for client-side code
|
|
663
|
+
|
|
578
664
|
### Test 2: Registration API
|
|
579
665
|
|
|
580
666
|
```bash
|
|
@@ -1,3 +1,32 @@
|
|
|
1
1
|
import { NextRequest, NextResponse } from "next/server";
|
|
2
|
-
|
|
2
|
+
/**
|
|
3
|
+
* GET /api/hazo_auth/me
|
|
4
|
+
*
|
|
5
|
+
* Standardized endpoint that returns authenticated user information with permissions.
|
|
6
|
+
* Always returns the same format to prevent downstream variations.
|
|
7
|
+
*
|
|
8
|
+
* Response format (authenticated):
|
|
9
|
+
* {
|
|
10
|
+
* authenticated: true,
|
|
11
|
+
* user_id: string,
|
|
12
|
+
* email: string,
|
|
13
|
+
* name: string | null,
|
|
14
|
+
* email_verified: boolean,
|
|
15
|
+
* last_logon: string | undefined,
|
|
16
|
+
* profile_picture_url: string | null,
|
|
17
|
+
* profile_source: "upload" | "library" | "gravatar" | "custom" | undefined,
|
|
18
|
+
* user: { id, email_address, name, is_active, profile_picture_url },
|
|
19
|
+
* permissions: string[],
|
|
20
|
+
* permission_ok: boolean,
|
|
21
|
+
* missing_permissions?: string[],
|
|
22
|
+
* }
|
|
23
|
+
*
|
|
24
|
+
* Response format (not authenticated):
|
|
25
|
+
* {
|
|
26
|
+
* authenticated: false
|
|
27
|
+
* }
|
|
28
|
+
*/
|
|
29
|
+
export declare function GET(request: NextRequest): Promise<NextResponse<{
|
|
30
|
+
authenticated: boolean;
|
|
31
|
+
}>>;
|
|
3
32
|
//# sourceMappingURL=route.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../../src/app/api/hazo_auth/me/route.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../../src/app/api/hazo_auth/me/route.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AASxD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAsB,GAAG,CAAC,OAAO,EAAE,WAAW;;IA0E7C"}
|
|
@@ -1,33 +1,93 @@
|
|
|
1
|
-
// file_description: API route to get current authenticated user information
|
|
1
|
+
// file_description: API route to get current authenticated user information with permissions
|
|
2
|
+
// This is the standardized endpoint that always returns the same format including permissions
|
|
2
3
|
// section: imports
|
|
3
4
|
import { NextResponse } from "next/server";
|
|
4
|
-
import {
|
|
5
|
+
import { hazo_get_auth } from "../../../../lib/auth/hazo_get_auth.server";
|
|
6
|
+
import { get_hazo_connect_instance } from "../../../../lib/hazo_connect_instance.server";
|
|
7
|
+
import { createCrudService } from "hazo_connect/server";
|
|
8
|
+
import { map_db_source_to_ui } from "../../../../lib/services/profile_picture_source_mapper";
|
|
9
|
+
import { create_app_logger } from "../../../../lib/app_logger";
|
|
10
|
+
import { get_filename, get_line_number } from "../../../../lib/utils/api_route_helpers";
|
|
5
11
|
// section: api_handler
|
|
12
|
+
/**
|
|
13
|
+
* GET /api/hazo_auth/me
|
|
14
|
+
*
|
|
15
|
+
* Standardized endpoint that returns authenticated user information with permissions.
|
|
16
|
+
* Always returns the same format to prevent downstream variations.
|
|
17
|
+
*
|
|
18
|
+
* Response format (authenticated):
|
|
19
|
+
* {
|
|
20
|
+
* authenticated: true,
|
|
21
|
+
* user_id: string,
|
|
22
|
+
* email: string,
|
|
23
|
+
* name: string | null,
|
|
24
|
+
* email_verified: boolean,
|
|
25
|
+
* last_logon: string | undefined,
|
|
26
|
+
* profile_picture_url: string | null,
|
|
27
|
+
* profile_source: "upload" | "library" | "gravatar" | "custom" | undefined,
|
|
28
|
+
* user: { id, email_address, name, is_active, profile_picture_url },
|
|
29
|
+
* permissions: string[],
|
|
30
|
+
* permission_ok: boolean,
|
|
31
|
+
* missing_permissions?: string[],
|
|
32
|
+
* }
|
|
33
|
+
*
|
|
34
|
+
* Response format (not authenticated):
|
|
35
|
+
* {
|
|
36
|
+
* authenticated: false
|
|
37
|
+
* }
|
|
38
|
+
*/
|
|
6
39
|
export async function GET(request) {
|
|
40
|
+
const logger = create_app_logger();
|
|
7
41
|
try {
|
|
8
|
-
// Use
|
|
9
|
-
const
|
|
10
|
-
// If response is provided, it means cookies were cleared (invalid auth)
|
|
11
|
-
if (response) {
|
|
12
|
-
return response;
|
|
13
|
-
}
|
|
42
|
+
// Use hazo_get_auth to get user with permissions
|
|
43
|
+
const auth_result = await hazo_get_auth(request);
|
|
14
44
|
// If not authenticated, return false
|
|
15
45
|
if (!auth_result.authenticated) {
|
|
16
46
|
return NextResponse.json({ authenticated: false }, { status: 200 });
|
|
17
47
|
}
|
|
18
|
-
//
|
|
48
|
+
// Fetch additional user fields from database (email_verified, last_logon, profile_source)
|
|
49
|
+
const hazoConnect = get_hazo_connect_instance();
|
|
50
|
+
const users_service = createCrudService(hazoConnect, "hazo_users");
|
|
51
|
+
const users = await users_service.findBy({ id: auth_result.user.id });
|
|
52
|
+
if (!Array.isArray(users) || users.length === 0) {
|
|
53
|
+
logger.warn("me_endpoint_user_not_found", {
|
|
54
|
+
filename: get_filename(),
|
|
55
|
+
line_number: get_line_number(),
|
|
56
|
+
user_id: auth_result.user.id,
|
|
57
|
+
message: "User found in auth but not in database",
|
|
58
|
+
});
|
|
59
|
+
return NextResponse.json({ authenticated: false }, { status: 200 });
|
|
60
|
+
}
|
|
61
|
+
const user_db = users[0];
|
|
62
|
+
// Map database profile_source to UI representation
|
|
63
|
+
const profile_source_db = user_db.profile_source;
|
|
64
|
+
const profile_source_ui = profile_source_db ? map_db_source_to_ui(profile_source_db) : undefined;
|
|
65
|
+
// Return unified format with all fields
|
|
19
66
|
return NextResponse.json({
|
|
20
67
|
authenticated: true,
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
68
|
+
// Top-level fields for backward compatibility
|
|
69
|
+
user_id: auth_result.user.id,
|
|
70
|
+
email: auth_result.user.email_address,
|
|
71
|
+
name: auth_result.user.name,
|
|
72
|
+
email_verified: user_db.email_verified === true,
|
|
73
|
+
last_logon: user_db.last_logon || undefined,
|
|
74
|
+
profile_picture_url: auth_result.user.profile_picture_url,
|
|
75
|
+
profile_source: profile_source_ui,
|
|
76
|
+
// Permissions and user object (always included)
|
|
77
|
+
user: auth_result.user,
|
|
78
|
+
permissions: auth_result.permissions,
|
|
79
|
+
permission_ok: auth_result.permission_ok,
|
|
80
|
+
missing_permissions: auth_result.missing_permissions,
|
|
28
81
|
}, { status: 200 });
|
|
29
82
|
}
|
|
30
83
|
catch (error) {
|
|
84
|
+
const error_message = error instanceof Error ? error.message : "Unknown error";
|
|
85
|
+
logger.error("me_endpoint_error", {
|
|
86
|
+
filename: get_filename(),
|
|
87
|
+
line_number: get_line_number(),
|
|
88
|
+
error_message,
|
|
89
|
+
error_stack: error instanceof Error ? error.stack : undefined,
|
|
90
|
+
});
|
|
31
91
|
// On error, assume not authenticated
|
|
32
92
|
return NextResponse.json({ authenticated: false }, { status: 200 });
|
|
33
93
|
}
|
package/dist/cli/init.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"AA2IA,wBAAgB,WAAW,IAAI,IAAI,CAkHlC"}
|
package/dist/cli/init.js
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
// file_description: init command for hazo_auth
|
|
2
2
|
// Creates directories and copies config files to consuming projects
|
|
3
|
+
import { fileURLToPath } from "url";
|
|
3
4
|
import * as fs from "fs";
|
|
4
5
|
import * as path from "path";
|
|
6
|
+
// section: esm_shim
|
|
7
|
+
// ESM-compatible __dirname shim
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
+
const __dirname = path.dirname(__filename);
|
|
5
10
|
// section: constants
|
|
6
11
|
const REQUIRED_DIRECTORIES = [
|
|
7
12
|
"public/profile_pictures/library",
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export * from "./components/index";
|
|
2
|
+
export { cn, merge_class_names } from "./lib/utils";
|
|
3
|
+
export * from "./lib/auth/auth_types";
|
|
4
|
+
export { use_auth_status, trigger_auth_status_refresh } from "./components/layouts/shared/hooks/use_auth_status";
|
|
5
|
+
export { use_hazo_auth, trigger_hazo_auth_refresh } from "./components/layouts/shared/hooks/use_hazo_auth";
|
|
6
|
+
export type { UseHazoAuthOptions, UseHazoAuthResult } from "./components/layouts/shared/hooks/use_hazo_auth";
|
|
7
|
+
export * from "./components/layouts/shared/utils/validation";
|
|
8
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAYA,cAAc,oBAAoB,CAAC;AAInC,OAAO,EAAE,EAAE,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAIpD,cAAc,uBAAuB,CAAC;AAItC,OAAO,EAAE,eAAe,EAAE,2BAA2B,EAAE,MAAM,mDAAmD,CAAC;AACjH,OAAO,EAAE,aAAa,EAAE,yBAAyB,EAAE,MAAM,iDAAiD,CAAC;AAC3G,YAAY,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,iDAAiD,CAAC;AAI7G,cAAc,8CAA8C,CAAC"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// file_description: client-safe exports for hazo_auth package
|
|
2
|
+
// This file exports only modules that are safe to use in client components (browser)
|
|
3
|
+
// It excludes any server-side Node.js dependencies (fs, path, database, etc.)
|
|
4
|
+
//
|
|
5
|
+
// USAGE:
|
|
6
|
+
// import { ProfilePicMenu, use_auth_status, cn } from "hazo_auth/client";
|
|
7
|
+
//
|
|
8
|
+
// For server-side code (API routes, Server Components), use:
|
|
9
|
+
// import { hazo_get_auth, get_config_value } from "hazo_auth";
|
|
10
|
+
// section: component_exports
|
|
11
|
+
// All UI and layout components are client-safe
|
|
12
|
+
export * from "./components/index";
|
|
13
|
+
// section: utility_exports
|
|
14
|
+
// CSS utility functions
|
|
15
|
+
export { cn, merge_class_names } from "./lib/utils";
|
|
16
|
+
// section: type_exports
|
|
17
|
+
// Type definitions are always safe (erased at runtime)
|
|
18
|
+
export * from "./lib/auth/auth_types";
|
|
19
|
+
// section: client_hook_exports
|
|
20
|
+
// Re-export from shared hooks (these are already "use client" components)
|
|
21
|
+
export { use_auth_status, trigger_auth_status_refresh } from "./components/layouts/shared/hooks/use_auth_status";
|
|
22
|
+
export { use_hazo_auth, trigger_hazo_auth_refresh } from "./components/layouts/shared/hooks/use_hazo_auth";
|
|
23
|
+
// section: validation_exports
|
|
24
|
+
// Client-side validation utilities
|
|
25
|
+
export * from "./components/layouts/shared/utils/validation";
|
|
@@ -12,6 +12,7 @@ export type EmailVerificationLayoutProps<TClient = unknown> = {
|
|
|
12
12
|
error_labels?: Partial<EmailVerificationErrorLabels>;
|
|
13
13
|
redirect_delay?: number;
|
|
14
14
|
login_path?: string;
|
|
15
|
+
sign_in_label?: string;
|
|
15
16
|
already_logged_in_message?: string;
|
|
16
17
|
showLogoutButton?: boolean;
|
|
17
18
|
showReturnHomeButton?: boolean;
|
|
@@ -19,5 +20,5 @@ export type EmailVerificationLayoutProps<TClient = unknown> = {
|
|
|
19
20
|
returnHomePath?: string;
|
|
20
21
|
data_client: LayoutDataClient<TClient>;
|
|
21
22
|
};
|
|
22
|
-
export default function email_verification_layout<TClient>({ image_src, image_alt, image_background_color, field_overrides, labels, button_colors, success_labels, error_labels, redirect_delay, login_path, data_client, already_logged_in_message, showLogoutButton, showReturnHomeButton, returnHomeButtonLabel, returnHomePath, }: EmailVerificationLayoutProps<TClient>): import("react/jsx-runtime").JSX.Element;
|
|
23
|
+
export default function email_verification_layout<TClient>({ image_src, image_alt, image_background_color, field_overrides, labels, button_colors, success_labels, error_labels, redirect_delay, login_path, sign_in_label, data_client, already_logged_in_message, showLogoutButton, showReturnHomeButton, returnHomeButtonLabel, returnHomePath, }: EmailVerificationLayoutProps<TClient>): import("react/jsx-runtime").JSX.Element;
|
|
23
24
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/layouts/email_verification/index.tsx"],"names":[],"mappings":"AAWA,OAAO,EACL,KAAK,sBAAsB,EAC3B,KAAK,uBAAuB,EAC5B,KAAK,oBAAoB,EAC1B,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EAOL,KAAK,8BAA8B,EACnC,KAAK,4BAA4B,EAClC,MAAM,0CAA0C,CAAC;AAKlD,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/layouts/email_verification/index.tsx"],"names":[],"mappings":"AAWA,OAAO,EACL,KAAK,sBAAsB,EAC3B,KAAK,uBAAuB,EAC5B,KAAK,oBAAoB,EAC1B,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EAOL,KAAK,8BAA8B,EACnC,KAAK,4BAA4B,EAClC,MAAM,0CAA0C,CAAC;AAKlD,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAM1E,MAAM,MAAM,4BAA4B,CAAC,OAAO,GAAG,OAAO,IAAI;IAC5D,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,eAAe,CAAC,EAAE,uBAAuB,CAAC;IAC1C,MAAM,CAAC,EAAE,oBAAoB,CAAC;IAC9B,aAAa,CAAC,EAAE,sBAAsB,CAAC;IACvC,cAAc,CAAC,EAAE,OAAO,CAAC,8BAA8B,CAAC,CAAC;IACzD,YAAY,CAAC,EAAE,OAAO,CAAC,4BAA4B,CAAC,CAAC;IACrD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,yBAAyB,CAAC,EAAE,MAAM,CAAC;IACnC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAC;CACxC,CAAC;AASF,MAAM,CAAC,OAAO,UAAU,yBAAyB,CAAC,OAAO,EAAE,EACzD,SAAS,EACT,SAAS,EACT,sBAAkC,EAClC,eAAe,EACf,MAAM,EACN,aAAa,EACb,cAAc,EACd,YAAY,EACZ,cAAkB,EAClB,UAA+B,EAC/B,aAAyB,EACzB,WAAW,EACX,yBAAyB,EACzB,gBAAuB,EACvB,oBAA4B,EAC5B,qBAAqC,EACrC,cAAoB,GACrB,EAAE,4BAA4B,CAAC,OAAO,CAAC,2CAkOvC"}
|