hazo_auth 4.1.0 → 4.2.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.
- package/README.md +230 -0
- package/SETUP_CHECKLIST.md +202 -0
- package/dist/app/api/hazo_auth/forgot_password/route.d.ts.map +1 -1
- package/dist/app/api/hazo_auth/forgot_password/route.js +15 -0
- package/dist/app/api/hazo_auth/logout/route.d.ts.map +1 -1
- package/dist/app/api/hazo_auth/logout/route.js +31 -0
- package/dist/app/api/hazo_auth/me/route.d.ts.map +1 -1
- package/dist/app/api/hazo_auth/me/route.js +10 -0
- package/dist/components/layouts/forgot_password/hooks/use_forgot_password_form.d.ts +2 -0
- package/dist/components/layouts/forgot_password/hooks/use_forgot_password_form.d.ts.map +1 -1
- package/dist/components/layouts/forgot_password/hooks/use_forgot_password_form.js +8 -0
- package/dist/components/layouts/forgot_password/index.d.ts +7 -1
- package/dist/components/layouts/forgot_password/index.d.ts.map +1 -1
- package/dist/components/layouts/forgot_password/index.js +7 -2
- package/dist/components/layouts/login/index.d.ts +13 -1
- package/dist/components/layouts/login/index.d.ts.map +1 -1
- package/dist/components/layouts/login/index.js +11 -2
- package/dist/components/layouts/my_settings/components/connected_accounts_section.d.ts +17 -0
- package/dist/components/layouts/my_settings/components/connected_accounts_section.d.ts.map +1 -0
- package/dist/components/layouts/my_settings/components/connected_accounts_section.js +17 -0
- package/dist/components/layouts/my_settings/components/set_password_section.d.ts +26 -0
- package/dist/components/layouts/my_settings/components/set_password_section.d.ts.map +1 -0
- package/dist/components/layouts/my_settings/components/set_password_section.js +127 -0
- package/dist/components/layouts/my_settings/hooks/use_my_settings.d.ts +3 -0
- package/dist/components/layouts/my_settings/hooks/use_my_settings.d.ts.map +1 -1
- package/dist/components/layouts/my_settings/hooks/use_my_settings.js +9 -0
- package/dist/components/layouts/my_settings/index.d.ts.map +1 -1
- package/dist/components/layouts/my_settings/index.js +4 -2
- package/dist/components/layouts/shared/components/google_icon.d.ts +12 -0
- package/dist/components/layouts/shared/components/google_icon.d.ts.map +1 -0
- package/dist/components/layouts/shared/components/google_icon.js +9 -0
- package/dist/components/layouts/shared/components/google_sign_in_button.d.ts +21 -0
- package/dist/components/layouts/shared/components/google_sign_in_button.d.ts.map +1 -0
- package/dist/components/layouts/shared/components/google_sign_in_button.js +50 -0
- package/dist/components/layouts/shared/components/oauth_divider.d.ts +13 -0
- package/dist/components/layouts/shared/components/oauth_divider.d.ts.map +1 -0
- package/dist/components/layouts/shared/components/oauth_divider.js +13 -0
- 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/components/layouts/shared/index.d.ts +5 -0
- package/dist/components/layouts/shared/index.d.ts.map +1 -1
- package/dist/components/layouts/shared/index.js +3 -0
- package/dist/components/ui/button.d.ts +1 -1
- package/dist/lib/auth/nextauth_config.d.ts +34 -0
- package/dist/lib/auth/nextauth_config.d.ts.map +1 -0
- package/dist/lib/auth/nextauth_config.js +171 -0
- package/dist/lib/config/default_config.d.ts +24 -0
- package/dist/lib/config/default_config.d.ts.map +1 -1
- package/dist/lib/config/default_config.js +14 -0
- package/dist/lib/index.d.ts +2 -0
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/index.js +1 -0
- package/dist/lib/login_config.server.d.ts +3 -0
- package/dist/lib/login_config.server.d.ts.map +1 -1
- package/dist/lib/login_config.server.js +4 -0
- package/dist/lib/oauth_config.server.d.ts +29 -0
- package/dist/lib/oauth_config.server.d.ts.map +1 -0
- package/dist/lib/oauth_config.server.js +40 -0
- package/dist/lib/services/login_service.d.ts.map +1 -1
- package/dist/lib/services/login_service.js +16 -1
- package/dist/lib/services/oauth_service.d.ts +88 -0
- package/dist/lib/services/oauth_service.d.ts.map +1 -0
- package/dist/lib/services/oauth_service.js +376 -0
- package/dist/lib/services/password_reset_service.d.ts +2 -0
- package/dist/lib/services/password_reset_service.d.ts.map +1 -1
- package/dist/lib/services/password_reset_service.js +10 -0
- package/dist/lib/services/registration_service.d.ts.map +1 -1
- package/dist/lib/services/registration_service.js +1 -0
- package/dist/lib/utils/password_validator.d.ts +13 -0
- package/dist/lib/utils/password_validator.d.ts.map +1 -0
- package/dist/lib/utils/password_validator.js +36 -0
- package/dist/server_pages/login.d.ts.map +1 -1
- package/dist/server_pages/login.js +6 -1
- package/dist/server_pages/login_client_wrapper.d.ts +5 -2
- package/dist/server_pages/login_client_wrapper.d.ts.map +1 -1
- package/dist/server_pages/login_client_wrapper.js +2 -2
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -24,6 +24,7 @@ A reusable authentication UI component package powered by Next.js, TailwindCSS,
|
|
|
24
24
|
- [Quick Start](#quick-start)
|
|
25
25
|
- [Configuration Setup](#configuration-setup)
|
|
26
26
|
- [Database Setup](#database-setup)
|
|
27
|
+
- [Google OAuth Setup](#google-oauth-setup)
|
|
27
28
|
- [Using Components](#using-components)
|
|
28
29
|
- [Authentication Service](#authentication-service)
|
|
29
30
|
- [Proxy/Middleware Authentication](#proxymiddleware-authentication)
|
|
@@ -366,6 +367,19 @@ cp node_modules/hazo_auth/hazo_notify_config.example.ini ./hazo_notify_config.in
|
|
|
366
367
|
|
|
367
368
|
**Note:** `JWT_SECRET` is required for JWT session token functionality (used for Edge-compatible proxy/middleware authentication). Generate a secure random string at least 32 characters long.
|
|
368
369
|
|
|
370
|
+
**For Google OAuth (optional):**
|
|
371
|
+
```env
|
|
372
|
+
# NextAuth.js configuration (required for OAuth)
|
|
373
|
+
NEXTAUTH_SECRET=your_secure_random_string_at_least_32_characters
|
|
374
|
+
NEXTAUTH_URL=http://localhost:3000 # Change to production URL in production
|
|
375
|
+
|
|
376
|
+
# Google OAuth credentials (from Google Cloud Console)
|
|
377
|
+
HAZO_AUTH_GOOGLE_CLIENT_ID=your_google_client_id
|
|
378
|
+
HAZO_AUTH_GOOGLE_CLIENT_SECRET=your_google_client_secret
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
See [Google OAuth Setup](#google-oauth-setup) for detailed instructions.
|
|
382
|
+
|
|
369
383
|
**Important:** The configuration files must be located in your project root directory (where `process.cwd()` points to), not inside `node_modules`. The package reads configuration from `process.cwd()` at runtime, so storing them elsewhere (including `node_modules/hazo_auth`) will break runtime access.
|
|
370
384
|
|
|
371
385
|
---
|
|
@@ -672,6 +686,222 @@ npx tsx scripts/apply_migration.ts
|
|
|
672
686
|
|
|
673
687
|
---
|
|
674
688
|
|
|
689
|
+
## Google OAuth Setup
|
|
690
|
+
|
|
691
|
+
hazo_auth supports Google Sign-In via NextAuth.js v4, allowing users to authenticate with their Google accounts.
|
|
692
|
+
|
|
693
|
+
### Features
|
|
694
|
+
|
|
695
|
+
- **Dual authentication**: Users can have BOTH Google OAuth and email/password login
|
|
696
|
+
- **Auto-linking**: Automatically links Google login to existing unverified email/password accounts
|
|
697
|
+
- **Graceful degradation**: Login page adapts based on enabled authentication methods
|
|
698
|
+
- **Set password feature**: Google-only users can add a password later via My Settings
|
|
699
|
+
- **Profile data**: Full name and profile picture automatically populated from Google
|
|
700
|
+
|
|
701
|
+
### Step 1: Get Google OAuth Credentials
|
|
702
|
+
|
|
703
|
+
1. Go to [Google Cloud Console](https://console.cloud.google.com/)
|
|
704
|
+
2. Create a project or select an existing project
|
|
705
|
+
3. Enable Google+ API (or Google Identity Services)
|
|
706
|
+
4. Navigate to **Credentials** → **Create Credentials** → **OAuth 2.0 Client ID**
|
|
707
|
+
5. Configure OAuth consent screen if prompted
|
|
708
|
+
6. Set **Application type** to "Web application"
|
|
709
|
+
7. Add **Authorized JavaScript origins**:
|
|
710
|
+
- Development: `http://localhost:3000`
|
|
711
|
+
- Production: `https://yourdomain.com`
|
|
712
|
+
8. Add **Authorized redirect URIs**:
|
|
713
|
+
- Development: `http://localhost:3000/api/auth/callback/google`
|
|
714
|
+
- Production: `https://yourdomain.com/api/auth/callback/google`
|
|
715
|
+
9. Copy the **Client ID** and **Client Secret**
|
|
716
|
+
|
|
717
|
+
### Step 2: Add Environment Variables
|
|
718
|
+
|
|
719
|
+
Add to your `.env.local`:
|
|
720
|
+
|
|
721
|
+
```env
|
|
722
|
+
# NextAuth.js configuration (REQUIRED for OAuth)
|
|
723
|
+
NEXTAUTH_SECRET=your_secure_random_string_at_least_32_characters
|
|
724
|
+
NEXTAUTH_URL=http://localhost:3000 # Change to production URL in production
|
|
725
|
+
|
|
726
|
+
# Google OAuth credentials (from Google Cloud Console)
|
|
727
|
+
HAZO_AUTH_GOOGLE_CLIENT_ID=your_google_client_id_from_step_1
|
|
728
|
+
HAZO_AUTH_GOOGLE_CLIENT_SECRET=your_google_client_secret_from_step_1
|
|
729
|
+
```
|
|
730
|
+
|
|
731
|
+
**Generate NEXTAUTH_SECRET:**
|
|
732
|
+
```bash
|
|
733
|
+
openssl rand -base64 32
|
|
734
|
+
```
|
|
735
|
+
|
|
736
|
+
### Step 3: Run Database Migration
|
|
737
|
+
|
|
738
|
+
Add OAuth fields to the `hazo_users` table:
|
|
739
|
+
|
|
740
|
+
```bash
|
|
741
|
+
npm run migrate migrations/005_add_oauth_fields_to_hazo_users.sql
|
|
742
|
+
```
|
|
743
|
+
|
|
744
|
+
This migration adds:
|
|
745
|
+
- `google_id` - Google's unique user ID (TEXT, UNIQUE)
|
|
746
|
+
- `auth_providers` - Tracks authentication methods: 'email', 'google', or 'email,google'
|
|
747
|
+
- Index on `google_id` for fast OAuth lookups
|
|
748
|
+
|
|
749
|
+
**Manual migration (if needed):**
|
|
750
|
+
|
|
751
|
+
**PostgreSQL:**
|
|
752
|
+
```sql
|
|
753
|
+
ALTER TABLE hazo_users
|
|
754
|
+
ADD COLUMN google_id TEXT UNIQUE;
|
|
755
|
+
|
|
756
|
+
ALTER TABLE hazo_users
|
|
757
|
+
ADD COLUMN auth_providers TEXT DEFAULT 'email';
|
|
758
|
+
|
|
759
|
+
CREATE INDEX IF NOT EXISTS idx_hazo_users_google_id ON hazo_users(google_id);
|
|
760
|
+
```
|
|
761
|
+
|
|
762
|
+
**SQLite:**
|
|
763
|
+
```sql
|
|
764
|
+
ALTER TABLE hazo_users
|
|
765
|
+
ADD COLUMN google_id TEXT;
|
|
766
|
+
|
|
767
|
+
ALTER TABLE hazo_users
|
|
768
|
+
ADD COLUMN auth_providers TEXT DEFAULT 'email';
|
|
769
|
+
|
|
770
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_hazo_users_google_id_unique ON hazo_users(google_id);
|
|
771
|
+
CREATE INDEX IF NOT EXISTS idx_hazo_users_google_id ON hazo_users(google_id);
|
|
772
|
+
```
|
|
773
|
+
|
|
774
|
+
### Step 4: Configure OAuth in hazo_auth_config.ini
|
|
775
|
+
|
|
776
|
+
```ini
|
|
777
|
+
[hazo_auth__oauth]
|
|
778
|
+
# Enable Google OAuth login (default: true)
|
|
779
|
+
enable_google = true
|
|
780
|
+
|
|
781
|
+
# Enable traditional email/password login (default: true)
|
|
782
|
+
enable_email_password = true
|
|
783
|
+
|
|
784
|
+
# Auto-link Google login to existing unverified email/password accounts (default: true)
|
|
785
|
+
auto_link_unverified_accounts = true
|
|
786
|
+
|
|
787
|
+
# Customize button text (optional)
|
|
788
|
+
google_button_text = Continue with Google
|
|
789
|
+
oauth_divider_text = or
|
|
790
|
+
```
|
|
791
|
+
|
|
792
|
+
### Step 5: Create NextAuth API Routes
|
|
793
|
+
|
|
794
|
+
Create `app/api/auth/[...nextauth]/route.ts`:
|
|
795
|
+
|
|
796
|
+
```typescript
|
|
797
|
+
export { GET, POST } from "hazo_auth/server/routes/nextauth";
|
|
798
|
+
```
|
|
799
|
+
|
|
800
|
+
Create `app/api/hazo_auth/oauth/google/callback/route.ts`:
|
|
801
|
+
|
|
802
|
+
```typescript
|
|
803
|
+
export { GET } from "hazo_auth/server/routes/oauth_google_callback";
|
|
804
|
+
```
|
|
805
|
+
|
|
806
|
+
Create `app/api/hazo_auth/set_password/route.ts`:
|
|
807
|
+
|
|
808
|
+
```typescript
|
|
809
|
+
export { POST } from "hazo_auth/server/routes/set_password";
|
|
810
|
+
```
|
|
811
|
+
|
|
812
|
+
**Or use the CLI generator:**
|
|
813
|
+
```bash
|
|
814
|
+
npx hazo_auth generate-routes --oauth
|
|
815
|
+
```
|
|
816
|
+
|
|
817
|
+
### Step 6: Test Google OAuth
|
|
818
|
+
|
|
819
|
+
1. Start your dev server: `npm run dev`
|
|
820
|
+
2. Visit `http://localhost:3000/hazo_auth/login`
|
|
821
|
+
3. You should see the "Sign in with Google" button
|
|
822
|
+
4. Click it and authenticate with your Google account
|
|
823
|
+
5. You'll be redirected back and logged in
|
|
824
|
+
|
|
825
|
+
### User Flows
|
|
826
|
+
|
|
827
|
+
**New User - Google Sign-In:**
|
|
828
|
+
- User clicks "Sign in with Google"
|
|
829
|
+
- Authenticates with Google
|
|
830
|
+
- Account created with Google profile data (email, name, profile picture)
|
|
831
|
+
- Email is automatically verified
|
|
832
|
+
- User can log in with Google anytime
|
|
833
|
+
|
|
834
|
+
**Existing Unverified User - Google Sign-In:**
|
|
835
|
+
- User has email/password account but hasn't verified email
|
|
836
|
+
- Clicks "Sign in with Google" with same email
|
|
837
|
+
- System auto-links Google account (if `auto_link_unverified_accounts = true`)
|
|
838
|
+
- Email becomes verified
|
|
839
|
+
- User can now log in with EITHER Google OR email/password
|
|
840
|
+
|
|
841
|
+
**Google-Only User Adds Password:**
|
|
842
|
+
- Google-only user visits My Settings
|
|
843
|
+
- "Set Password" section appears
|
|
844
|
+
- User sets a password
|
|
845
|
+
- User can now log in with EITHER method
|
|
846
|
+
|
|
847
|
+
**Google-Only User Tries Forgot Password:**
|
|
848
|
+
- User registered with Google tries "Forgot Password"
|
|
849
|
+
- System shows: "You registered with Google. Please sign in with Google instead."
|
|
850
|
+
|
|
851
|
+
### Configuration Options
|
|
852
|
+
|
|
853
|
+
**Disable email/password login (Google-only):**
|
|
854
|
+
```ini
|
|
855
|
+
[hazo_auth__oauth]
|
|
856
|
+
enable_google = true
|
|
857
|
+
enable_email_password = false
|
|
858
|
+
```
|
|
859
|
+
|
|
860
|
+
**Disable Google OAuth (email/password only):**
|
|
861
|
+
```ini
|
|
862
|
+
[hazo_auth__oauth]
|
|
863
|
+
enable_google = false
|
|
864
|
+
enable_email_password = true
|
|
865
|
+
```
|
|
866
|
+
|
|
867
|
+
### API Response Changes
|
|
868
|
+
|
|
869
|
+
The `/api/hazo_auth/me` endpoint now includes OAuth status:
|
|
870
|
+
|
|
871
|
+
```typescript
|
|
872
|
+
{
|
|
873
|
+
authenticated: true,
|
|
874
|
+
// ... existing fields
|
|
875
|
+
auth_providers: "email,google", // NEW: Tracks authentication methods
|
|
876
|
+
has_password: true, // NEW: Whether user has password set
|
|
877
|
+
google_connected: true, // NEW: Whether Google account is linked
|
|
878
|
+
}
|
|
879
|
+
```
|
|
880
|
+
|
|
881
|
+
### Dependencies
|
|
882
|
+
|
|
883
|
+
Google OAuth adds one new dependency:
|
|
884
|
+
- `next-auth@^4.24.11` - NextAuth.js for OAuth handling (automatically installed with hazo_auth)
|
|
885
|
+
|
|
886
|
+
### Troubleshooting
|
|
887
|
+
|
|
888
|
+
**"Sign in with Google" button not showing:**
|
|
889
|
+
- Verify `enable_google = true` in `[hazo_auth__oauth]` section
|
|
890
|
+
- Check `HAZO_AUTH_GOOGLE_CLIENT_ID` and `HAZO_AUTH_GOOGLE_CLIENT_SECRET` are set
|
|
891
|
+
- Check `NEXTAUTH_URL` matches your current URL
|
|
892
|
+
|
|
893
|
+
**OAuth callback error:**
|
|
894
|
+
- Verify redirect URI in Google Cloud Console matches exactly: `http://localhost:3000/api/auth/callback/google`
|
|
895
|
+
- Check `NEXTAUTH_SECRET` is set and at least 32 characters
|
|
896
|
+
- Verify API routes are created: `/api/auth/[...nextauth]/route.ts` and `/api/hazo_auth/oauth/google/callback/route.ts`
|
|
897
|
+
|
|
898
|
+
**User created but not logged in:**
|
|
899
|
+
- Check browser console for errors
|
|
900
|
+
- Verify `/api/hazo_auth/oauth/google/callback` route exists
|
|
901
|
+
- Check server logs for errors during session creation
|
|
902
|
+
|
|
903
|
+
---
|
|
904
|
+
|
|
675
905
|
## Using Components
|
|
676
906
|
|
|
677
907
|
### Package Exports
|
package/SETUP_CHECKLIST.md
CHANGED
|
@@ -492,6 +492,169 @@ This script will:
|
|
|
492
492
|
|
|
493
493
|
---
|
|
494
494
|
|
|
495
|
+
## Phase 3.2: Google OAuth Setup (Optional)
|
|
496
|
+
|
|
497
|
+
Google OAuth Sign-In allows users to authenticate with their Google accounts. This section is optional - skip if you don't need OAuth.
|
|
498
|
+
|
|
499
|
+
### Step 3.2.1: Get Google OAuth Credentials
|
|
500
|
+
|
|
501
|
+
1. Go to [Google Cloud Console](https://console.cloud.google.com/)
|
|
502
|
+
2. Create a project or select an existing project
|
|
503
|
+
3. Enable **Google+ API** (or Google Identity Services)
|
|
504
|
+
4. Navigate to **Credentials** → **Create Credentials** → **OAuth 2.0 Client ID**
|
|
505
|
+
5. Configure OAuth consent screen if prompted
|
|
506
|
+
6. Set **Application type** to "Web application"
|
|
507
|
+
7. Add **Authorized JavaScript origins**:
|
|
508
|
+
- Development: `http://localhost:3000`
|
|
509
|
+
- Production: `https://yourdomain.com`
|
|
510
|
+
8. Add **Authorized redirect URIs**:
|
|
511
|
+
- Development: `http://localhost:3000/api/auth/callback/google`
|
|
512
|
+
- Production: `https://yourdomain.com/api/auth/callback/google`
|
|
513
|
+
9. Copy the **Client ID** and **Client Secret**
|
|
514
|
+
|
|
515
|
+
### Step 3.2.2: Add OAuth Environment Variables
|
|
516
|
+
|
|
517
|
+
Add to your `.env.local`:
|
|
518
|
+
|
|
519
|
+
```env
|
|
520
|
+
# NextAuth.js configuration (REQUIRED for OAuth)
|
|
521
|
+
NEXTAUTH_SECRET=your_secure_random_string_at_least_32_characters
|
|
522
|
+
NEXTAUTH_URL=http://localhost:3000 # Change to production URL in production
|
|
523
|
+
|
|
524
|
+
# Google OAuth credentials (from Google Cloud Console)
|
|
525
|
+
HAZO_AUTH_GOOGLE_CLIENT_ID=your_google_client_id_from_step_1
|
|
526
|
+
HAZO_AUTH_GOOGLE_CLIENT_SECRET=your_google_client_secret_from_step_1
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
**Generate NEXTAUTH_SECRET:**
|
|
530
|
+
```bash
|
|
531
|
+
openssl rand -base64 32
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
### Step 3.2.3: Run OAuth Database Migration
|
|
535
|
+
|
|
536
|
+
Add OAuth fields to the `hazo_users` table:
|
|
537
|
+
|
|
538
|
+
```bash
|
|
539
|
+
npm run migrate migrations/005_add_oauth_fields_to_hazo_users.sql
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
**Verify migration applied:**
|
|
543
|
+
|
|
544
|
+
**PostgreSQL:**
|
|
545
|
+
```sql
|
|
546
|
+
SELECT column_name FROM information_schema.columns
|
|
547
|
+
WHERE table_name = 'hazo_users'
|
|
548
|
+
AND column_name IN ('google_id', 'auth_providers');
|
|
549
|
+
-- Expected: 2 rows returned
|
|
550
|
+
```
|
|
551
|
+
|
|
552
|
+
**SQLite:**
|
|
553
|
+
```bash
|
|
554
|
+
sqlite3 data/hazo_auth.sqlite ".schema hazo_users" | grep -E "google_id|auth_providers"
|
|
555
|
+
# Expected: google_id TEXT UNIQUE, auth_providers TEXT DEFAULT 'email'
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
**Manual migration (if needed):**
|
|
559
|
+
|
|
560
|
+
**PostgreSQL:**
|
|
561
|
+
```sql
|
|
562
|
+
ALTER TABLE hazo_users ADD COLUMN google_id TEXT UNIQUE;
|
|
563
|
+
ALTER TABLE hazo_users ADD COLUMN auth_providers TEXT DEFAULT 'email';
|
|
564
|
+
CREATE INDEX IF NOT EXISTS idx_hazo_users_google_id ON hazo_users(google_id);
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
**SQLite:**
|
|
568
|
+
```sql
|
|
569
|
+
ALTER TABLE hazo_users ADD COLUMN google_id TEXT;
|
|
570
|
+
ALTER TABLE hazo_users ADD COLUMN auth_providers TEXT DEFAULT 'email';
|
|
571
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_hazo_users_google_id_unique ON hazo_users(google_id);
|
|
572
|
+
CREATE INDEX IF NOT EXISTS idx_hazo_users_google_id ON hazo_users(google_id);
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
### Step 3.2.4: Configure OAuth in hazo_auth_config.ini
|
|
576
|
+
|
|
577
|
+
Add (or modify) the OAuth section:
|
|
578
|
+
|
|
579
|
+
```ini
|
|
580
|
+
[hazo_auth__oauth]
|
|
581
|
+
# Enable Google OAuth login (default: true)
|
|
582
|
+
enable_google = true
|
|
583
|
+
|
|
584
|
+
# Enable traditional email/password login (default: true)
|
|
585
|
+
enable_email_password = true
|
|
586
|
+
|
|
587
|
+
# Auto-link Google login to existing unverified email/password accounts (default: true)
|
|
588
|
+
auto_link_unverified_accounts = true
|
|
589
|
+
|
|
590
|
+
# Customize button text (optional)
|
|
591
|
+
google_button_text = Continue with Google
|
|
592
|
+
oauth_divider_text = or
|
|
593
|
+
```
|
|
594
|
+
|
|
595
|
+
**Configuration Options:**
|
|
596
|
+
|
|
597
|
+
- **Google-only authentication** (no email/password):
|
|
598
|
+
```ini
|
|
599
|
+
enable_google = true
|
|
600
|
+
enable_email_password = false
|
|
601
|
+
```
|
|
602
|
+
|
|
603
|
+
- **Email/password only** (no OAuth):
|
|
604
|
+
```ini
|
|
605
|
+
enable_google = false
|
|
606
|
+
enable_email_password = true
|
|
607
|
+
```
|
|
608
|
+
|
|
609
|
+
- **Both methods** (recommended):
|
|
610
|
+
```ini
|
|
611
|
+
enable_google = true
|
|
612
|
+
enable_email_password = true
|
|
613
|
+
```
|
|
614
|
+
|
|
615
|
+
### Step 3.2.5: Create OAuth API Routes
|
|
616
|
+
|
|
617
|
+
**Option A: Use CLI generator (Recommended):**
|
|
618
|
+
```bash
|
|
619
|
+
npx hazo_auth generate-routes --oauth
|
|
620
|
+
```
|
|
621
|
+
|
|
622
|
+
**Option B: Create manually:**
|
|
623
|
+
|
|
624
|
+
Create `app/api/auth/[...nextauth]/route.ts`:
|
|
625
|
+
```typescript
|
|
626
|
+
export { GET, POST } from "hazo_auth/server/routes/nextauth";
|
|
627
|
+
```
|
|
628
|
+
|
|
629
|
+
Create `app/api/hazo_auth/oauth/google/callback/route.ts`:
|
|
630
|
+
```typescript
|
|
631
|
+
export { GET } from "hazo_auth/server/routes/oauth_google_callback";
|
|
632
|
+
```
|
|
633
|
+
|
|
634
|
+
Create `app/api/hazo_auth/set_password/route.ts`:
|
|
635
|
+
```typescript
|
|
636
|
+
export { POST } from "hazo_auth/server/routes/set_password";
|
|
637
|
+
```
|
|
638
|
+
|
|
639
|
+
### Step 3.2.6: Verify OAuth API Routes
|
|
640
|
+
|
|
641
|
+
```bash
|
|
642
|
+
ls app/api/auth/\[...nextauth\]/route.ts
|
|
643
|
+
ls app/api/hazo_auth/oauth/google/callback/route.ts
|
|
644
|
+
ls app/api/hazo_auth/set_password/route.ts
|
|
645
|
+
# All files should exist
|
|
646
|
+
```
|
|
647
|
+
|
|
648
|
+
**OAuth Setup Checklist:**
|
|
649
|
+
- [ ] Google OAuth credentials obtained
|
|
650
|
+
- [ ] `NEXTAUTH_SECRET` and `NEXTAUTH_URL` set in `.env.local`
|
|
651
|
+
- [ ] `HAZO_AUTH_GOOGLE_CLIENT_ID` and `HAZO_AUTH_GOOGLE_CLIENT_SECRET` set
|
|
652
|
+
- [ ] OAuth migration applied (google_id and auth_providers columns added)
|
|
653
|
+
- [ ] `[hazo_auth__oauth]` section configured in `hazo_auth_config.ini`
|
|
654
|
+
- [ ] OAuth API routes created (`[...nextauth]`, `oauth/google/callback`, `set_password`)
|
|
655
|
+
|
|
656
|
+
---
|
|
657
|
+
|
|
495
658
|
## Phase 4: API Routes
|
|
496
659
|
|
|
497
660
|
Create API route files in your project. Each file re-exports handlers from hazo_auth.
|
|
@@ -956,6 +1119,45 @@ Visit each page and verify it loads:
|
|
|
956
1119
|
- [ ] `http://localhost:3000/hazo_auth/my_settings` - Settings page displays (after login)
|
|
957
1120
|
- [ ] `http://localhost:3000/hazo_auth/profile_stamp_test` - ProfileStamp component examples display
|
|
958
1121
|
|
|
1122
|
+
### Test 7: Google OAuth (if configured)
|
|
1123
|
+
|
|
1124
|
+
If you completed Phase 3.2 (Google OAuth Setup):
|
|
1125
|
+
|
|
1126
|
+
**Check login page:**
|
|
1127
|
+
1. Visit `http://localhost:3000/hazo_auth/login`
|
|
1128
|
+
2. Verify "Sign in with Google" button appears
|
|
1129
|
+
3. Verify divider with "or" text (if email/password is also enabled)
|
|
1130
|
+
|
|
1131
|
+
**Test Google sign-in:**
|
|
1132
|
+
1. Click "Sign in with Google" button
|
|
1133
|
+
2. You should be redirected to Google's login page
|
|
1134
|
+
3. Sign in with your Google account
|
|
1135
|
+
4. You should be redirected back to your app and logged in
|
|
1136
|
+
5. Visit `/hazo_auth/my_settings`
|
|
1137
|
+
6. Verify "Connected Accounts" section shows Google as connected
|
|
1138
|
+
|
|
1139
|
+
**Test Google-only user features:**
|
|
1140
|
+
1. If you signed in with Google (and didn't have a password account first):
|
|
1141
|
+
2. Visit `/hazo_auth/my_settings`
|
|
1142
|
+
3. Verify "Set Password" section appears
|
|
1143
|
+
4. Set a password
|
|
1144
|
+
5. Log out and try logging in with email/password (should work)
|
|
1145
|
+
|
|
1146
|
+
**Test forgot password with Google-only user:**
|
|
1147
|
+
1. Create a new user with Google OAuth only
|
|
1148
|
+
2. Try visiting `/hazo_auth/forgot_password`
|
|
1149
|
+
3. Enter the Google user's email
|
|
1150
|
+
4. Should show message: "You registered with Google. Please sign in with Google instead."
|
|
1151
|
+
|
|
1152
|
+
**OAuth Test Checklist:**
|
|
1153
|
+
- [ ] "Sign in with Google" button appears on login page
|
|
1154
|
+
- [ ] OAuth divider appears (if both auth methods enabled)
|
|
1155
|
+
- [ ] Google OAuth flow completes successfully
|
|
1156
|
+
- [ ] User is logged in after OAuth callback
|
|
1157
|
+
- [ ] Connected Accounts section shows Google in My Settings
|
|
1158
|
+
- [ ] Set Password feature works for Google-only users
|
|
1159
|
+
- [ ] Forgot password shows appropriate message for Google-only users
|
|
1160
|
+
|
|
959
1161
|
---
|
|
960
1162
|
|
|
961
1163
|
## Phase 7: HRBAC Setup (Optional)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../../src/app/api/hazo_auth/forgot_password/route.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAOxD,wBAAsB,IAAI,CAAC,OAAO,EAAE,WAAW;;;;;
|
|
1
|
+
{"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../../src/app/api/hazo_auth/forgot_password/route.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAOxD,wBAAsB,IAAI,CAAC,OAAO,EAAE,WAAW;;;;;IAoH9C"}
|
|
@@ -49,6 +49,21 @@ export async function POST(request) {
|
|
|
49
49
|
message: "If an account with that email exists, a password reset link has been sent.",
|
|
50
50
|
}, { status: 200 });
|
|
51
51
|
}
|
|
52
|
+
// Check if this is a Google-only user (no password set)
|
|
53
|
+
if (result.no_password_set) {
|
|
54
|
+
logger.info("password_reset_no_password_set", {
|
|
55
|
+
filename: get_filename(),
|
|
56
|
+
line_number: get_line_number(),
|
|
57
|
+
email,
|
|
58
|
+
note: "User does not have a password set (OAuth-only account)",
|
|
59
|
+
});
|
|
60
|
+
// Return success to prevent email enumeration, but include flag for UI handling
|
|
61
|
+
return NextResponse.json({
|
|
62
|
+
success: true,
|
|
63
|
+
no_password_set: true,
|
|
64
|
+
message: "If an account with that email exists, a password reset link has been sent.",
|
|
65
|
+
}, { status: 200 });
|
|
66
|
+
}
|
|
52
67
|
logger.info("password_reset_requested", {
|
|
53
68
|
filename: get_filename(),
|
|
54
69
|
line_number: get_line_number(),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../../src/app/api/hazo_auth/logout/route.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAOxD,wBAAsB,IAAI,CAAC,OAAO,EAAE,WAAW;;;;;
|
|
1
|
+
{"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../../src/app/api/hazo_auth/logout/route.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAOxD,wBAAsB,IAAI,CAAC,OAAO,EAAE,WAAW;;;;;IAkH9C"}
|
|
@@ -32,6 +32,37 @@ export async function POST(request) {
|
|
|
32
32
|
expires: new Date(0),
|
|
33
33
|
path: "/",
|
|
34
34
|
});
|
|
35
|
+
// Clear NextAuth session cookies (for OAuth users)
|
|
36
|
+
response.cookies.set("next-auth.session-token", "", {
|
|
37
|
+
expires: new Date(0),
|
|
38
|
+
path: "/",
|
|
39
|
+
});
|
|
40
|
+
response.cookies.set("next-auth.csrf-token", "", {
|
|
41
|
+
expires: new Date(0),
|
|
42
|
+
path: "/",
|
|
43
|
+
});
|
|
44
|
+
response.cookies.set("next-auth.callback-url", "", {
|
|
45
|
+
expires: new Date(0),
|
|
46
|
+
path: "/",
|
|
47
|
+
});
|
|
48
|
+
// Also clear secure cookie variants (used in production with HTTPS)
|
|
49
|
+
response.cookies.set("__Secure-next-auth.session-token", "", {
|
|
50
|
+
expires: new Date(0),
|
|
51
|
+
path: "/",
|
|
52
|
+
});
|
|
53
|
+
response.cookies.set("__Secure-next-auth.csrf-token", "", {
|
|
54
|
+
expires: new Date(0),
|
|
55
|
+
path: "/",
|
|
56
|
+
});
|
|
57
|
+
response.cookies.set("__Secure-next-auth.callback-url", "", {
|
|
58
|
+
expires: new Date(0),
|
|
59
|
+
path: "/",
|
|
60
|
+
});
|
|
61
|
+
// Host-prefixed variants (for some NextAuth configurations)
|
|
62
|
+
response.cookies.set("__Host-next-auth.csrf-token", "", {
|
|
63
|
+
expires: new Date(0),
|
|
64
|
+
path: "/",
|
|
65
|
+
});
|
|
35
66
|
// Invalidate user cache
|
|
36
67
|
if (user_id) {
|
|
37
68
|
try {
|
|
@@ -1 +1 @@
|
|
|
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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAsB,GAAG,CAAC,OAAO,EAAE,WAAW;;
|
|
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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAsB,GAAG,CAAC,OAAO,EAAE,WAAW;;IA2F7C"}
|
|
@@ -65,6 +65,12 @@ export async function GET(request) {
|
|
|
65
65
|
// Map database profile_source to UI representation
|
|
66
66
|
const profile_source_db = user_db.profile_source;
|
|
67
67
|
const profile_source_ui = profile_source_db ? map_db_source_to_ui(profile_source_db) : undefined;
|
|
68
|
+
// Parse auth_providers (comma-separated string to array)
|
|
69
|
+
const auth_providers_str = user_db.auth_providers || "email";
|
|
70
|
+
const auth_providers = auth_providers_str.split(",").map((p) => p.trim());
|
|
71
|
+
// Check if user has a password set
|
|
72
|
+
const password_hash = user_db.password_hash;
|
|
73
|
+
const has_password = password_hash !== null && password_hash !== undefined && password_hash !== "";
|
|
68
74
|
// Return unified format with all fields
|
|
69
75
|
const profile_pic = auth_result.user.profile_picture_url;
|
|
70
76
|
return NextResponse.json({
|
|
@@ -81,6 +87,10 @@ export async function GET(request) {
|
|
|
81
87
|
avatar_url: profile_pic,
|
|
82
88
|
image: profile_pic,
|
|
83
89
|
profile_source: profile_source_ui,
|
|
90
|
+
// OAuth-related fields
|
|
91
|
+
auth_providers,
|
|
92
|
+
has_password,
|
|
93
|
+
google_connected: auth_providers.includes("google"),
|
|
84
94
|
// Permissions and user object (always included)
|
|
85
95
|
user: auth_result.user,
|
|
86
96
|
permissions: auth_result.permissions,
|
|
@@ -13,6 +13,8 @@ export type UseForgotPasswordFormResult = {
|
|
|
13
13
|
isSubmitDisabled: boolean;
|
|
14
14
|
isSubmitting: boolean;
|
|
15
15
|
emailTouched: boolean;
|
|
16
|
+
/** True if the submitted email is for a Google-only account (no password set) */
|
|
17
|
+
isGoogleOnlyAccount: boolean;
|
|
16
18
|
handleFieldChange: (fieldId: ForgotPasswordFieldId, value: string) => void;
|
|
17
19
|
handleEmailBlur: () => void;
|
|
18
20
|
handleSubmit: (event: React.FormEvent<HTMLFormElement>) => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use_forgot_password_form.d.ts","sourceRoot":"","sources":["../../../../../src/components/layouts/forgot_password/hooks/use_forgot_password_form.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sCAAsC,CAAC;AAC7E,OAAO,EAA6B,KAAK,qBAAqB,EAAE,MAAM,wCAAwC,CAAC;AAK/G,MAAM,MAAM,wBAAwB,GAAG,MAAM,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;AAC7E,MAAM,MAAM,wBAAwB,GAAG,OAAO,CAAC,MAAM,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC,GAAG;IACtF,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,2BAA2B,CAAC,OAAO,GAAG,OAAO,IAAI;IAC3D,UAAU,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAC;CACvC,CAAC;AAEF,MAAM,MAAM,2BAA2B,GAAG;IACxC,MAAM,EAAE,wBAAwB,CAAC;IACjC,MAAM,EAAE,wBAAwB,CAAC;IACjC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,YAAY,EAAE,OAAO,CAAC;IACtB,YAAY,EAAE,OAAO,CAAC;IACtB,iBAAiB,EAAE,CAAC,OAAO,EAAE,qBAAqB,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3E,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B,YAAY,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC,eAAe,CAAC,KAAK,IAAI,CAAC;IAChE,YAAY,EAAE,MAAM,IAAI,CAAC;CAC1B,CAAC;AAQF,eAAO,MAAM,wBAAwB,GAAI,OAAO,EAAG,iBAEhD,2BAA2B,CAAC,OAAO,CAAC,KAAG,
|
|
1
|
+
{"version":3,"file":"use_forgot_password_form.d.ts","sourceRoot":"","sources":["../../../../../src/components/layouts/forgot_password/hooks/use_forgot_password_form.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sCAAsC,CAAC;AAC7E,OAAO,EAA6B,KAAK,qBAAqB,EAAE,MAAM,wCAAwC,CAAC;AAK/G,MAAM,MAAM,wBAAwB,GAAG,MAAM,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;AAC7E,MAAM,MAAM,wBAAwB,GAAG,OAAO,CAAC,MAAM,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC,GAAG;IACtF,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,2BAA2B,CAAC,OAAO,GAAG,OAAO,IAAI;IAC3D,UAAU,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAC;CACvC,CAAC;AAEF,MAAM,MAAM,2BAA2B,GAAG;IACxC,MAAM,EAAE,wBAAwB,CAAC;IACjC,MAAM,EAAE,wBAAwB,CAAC;IACjC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,YAAY,EAAE,OAAO,CAAC;IACtB,YAAY,EAAE,OAAO,CAAC;IACtB,iFAAiF;IACjF,mBAAmB,EAAE,OAAO,CAAC;IAC7B,iBAAiB,EAAE,CAAC,OAAO,EAAE,qBAAqB,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3E,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B,YAAY,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC,eAAe,CAAC,KAAK,IAAI,CAAC;IAChE,YAAY,EAAE,MAAM,IAAI,CAAC;CAC1B,CAAC;AAQF,eAAO,MAAM,wBAAwB,GAAI,OAAO,EAAG,iBAEhD,2BAA2B,CAAC,OAAO,CAAC,KAAG,2BAqJzC,CAAC"}
|
|
@@ -16,6 +16,7 @@ export const use_forgot_password_form = ({ dataClient, }) => {
|
|
|
16
16
|
const [errors, setErrors] = useState({});
|
|
17
17
|
const [emailTouched, setEmailTouched] = useState(false);
|
|
18
18
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
19
|
+
const [isGoogleOnlyAccount, setIsGoogleOnlyAccount] = useState(false);
|
|
19
20
|
const isSubmitDisabled = useMemo(() => {
|
|
20
21
|
if (isSubmitting) {
|
|
21
22
|
return true;
|
|
@@ -72,6 +73,7 @@ export const use_forgot_password_form = ({ dataClient, }) => {
|
|
|
72
73
|
}
|
|
73
74
|
setIsSubmitting(true);
|
|
74
75
|
setErrors({});
|
|
76
|
+
setIsGoogleOnlyAccount(false);
|
|
75
77
|
try {
|
|
76
78
|
const response = await fetch(`${apiBasePath}/forgot_password`, {
|
|
77
79
|
method: "POST",
|
|
@@ -86,6 +88,11 @@ export const use_forgot_password_form = ({ dataClient, }) => {
|
|
|
86
88
|
if (!response.ok) {
|
|
87
89
|
throw new Error(data.error || "Password reset request failed");
|
|
88
90
|
}
|
|
91
|
+
// Check if user is a Google-only account (no password set)
|
|
92
|
+
if (data.no_password_set) {
|
|
93
|
+
setIsGoogleOnlyAccount(true);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
89
96
|
// Show success notification
|
|
90
97
|
toast.success("Password reset link sent", {
|
|
91
98
|
description: "If an account with that email exists, a password reset link has been sent.",
|
|
@@ -121,6 +128,7 @@ export const use_forgot_password_form = ({ dataClient, }) => {
|
|
|
121
128
|
isSubmitDisabled,
|
|
122
129
|
isSubmitting,
|
|
123
130
|
emailTouched,
|
|
131
|
+
isGoogleOnlyAccount,
|
|
124
132
|
handleFieldChange,
|
|
125
133
|
handleEmailBlur,
|
|
126
134
|
handleSubmit,
|
|
@@ -16,6 +16,12 @@ export type ForgotPasswordLayoutProps<TClient = unknown> = {
|
|
|
16
16
|
showReturnHomeButton?: boolean;
|
|
17
17
|
returnHomeButtonLabel?: string;
|
|
18
18
|
returnHomePath?: string;
|
|
19
|
+
/** Message shown when user's account is Google-only (no password set) */
|
|
20
|
+
googleOnlyAccountHeading?: string;
|
|
21
|
+
googleOnlyAccountMessage?: string;
|
|
22
|
+
googleOnlyAccountHelpText?: string;
|
|
23
|
+
mySettingsPath?: string;
|
|
24
|
+
mySettingsLabel?: string;
|
|
19
25
|
};
|
|
20
|
-
export default function forgot_password_layout<TClient>({ image_src, image_alt, image_background_color, field_overrides, labels, button_colors, data_client, sign_in_path, sign_in_label, alreadyLoggedInMessage, showLogoutButton, showReturnHomeButton, returnHomeButtonLabel, returnHomePath, }: ForgotPasswordLayoutProps<TClient>): import("react/jsx-runtime").JSX.Element;
|
|
26
|
+
export default function forgot_password_layout<TClient>({ image_src, image_alt, image_background_color, field_overrides, labels, button_colors, data_client, sign_in_path, sign_in_label, alreadyLoggedInMessage, showLogoutButton, showReturnHomeButton, returnHomeButtonLabel, returnHomePath, googleOnlyAccountHeading, googleOnlyAccountMessage, googleOnlyAccountHelpText, mySettingsPath, mySettingsLabel, }: ForgotPasswordLayoutProps<TClient>): import("react/jsx-runtime").JSX.Element;
|
|
21
27
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/layouts/forgot_password/index.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/layouts/forgot_password/index.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAOlD,OAAO,EACL,KAAK,sBAAsB,EAC3B,KAAK,uBAAuB,EAC5B,KAAK,oBAAoB,EAC1B,MAAM,uCAAuC,CAAC;AAW/C,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAI1E,MAAM,MAAM,yBAAyB,CAAC,OAAO,GAAG,OAAO,IAAI;IACzD,SAAS,EAAE,MAAM,GAAG,eAAe,CAAC;IACpC,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,WAAW,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAC;IACvC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,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,yEAAyE;IACzE,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,yBAAyB,CAAC,EAAE,MAAM,CAAC;IACnC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC;AASF,MAAM,CAAC,OAAO,UAAU,sBAAsB,CAAC,OAAO,EAAE,EACtD,SAAS,EACT,SAAS,EACT,sBAAkC,EAClC,eAAe,EACf,MAAM,EACN,aAAa,EACb,WAAW,EACX,YAAiC,EACjC,aAAyB,EACzB,sBAAoD,EACpD,gBAAuB,EACvB,oBAA4B,EAC5B,qBAAqC,EACrC,cAAoB,EACpB,wBAAoD,EACpD,wBAA2G,EAC3G,yBAA0I,EAC1I,cAAyC,EACzC,eAAkC,GACnC,EAAE,yBAAyB,CAAC,OAAO,CAAC,2CAgJpC"}
|