@djangocfg/api 2.1.355 → 2.1.357
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 +53 -632
- package/dist/auth-server.cjs +717 -200
- package/dist/auth-server.cjs.map +1 -1
- package/dist/auth-server.mjs +717 -200
- package/dist/auth-server.mjs.map +1 -1
- package/dist/auth.cjs +843 -783
- package/dist/auth.cjs.map +1 -1
- package/dist/auth.d.cts +58 -37
- package/dist/auth.d.ts +58 -37
- package/dist/auth.mjs +846 -784
- package/dist/auth.mjs.map +1 -1
- package/dist/clients.cjs +1427 -0
- package/dist/clients.cjs.map +1 -1
- package/dist/clients.d.cts +1686 -0
- package/dist/clients.d.ts +1686 -0
- package/dist/clients.mjs +1427 -0
- package/dist/clients.mjs.map +1 -1
- package/dist/hooks.cjs +1277 -1924
- package/dist/hooks.cjs.map +1 -1
- package/dist/hooks.d.cts +18 -1206
- package/dist/hooks.d.ts +18 -1206
- package/dist/hooks.mjs +1253 -1900
- package/dist/hooks.mjs.map +1 -1
- package/dist/index.cjs +545 -1232
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1389 -1455
- package/dist/index.d.ts +1389 -1455
- package/dist/index.mjs +545 -1232
- package/dist/index.mjs.map +1 -1
- package/package.json +7 -2
- package/src/_api/generated/_cfg_accounts/api.ts +11 -3
- package/src/_api/generated/_cfg_accounts/hooks/index.ts +3 -0
- package/src/_api/generated/_cfg_accounts/hooks/useCfgAccountsApiKeyRegenerateCreate.ts +64 -0
- package/src/_api/generated/_cfg_accounts/hooks/useCfgAccountsApiKeyRetrieve.ts +65 -0
- package/src/_api/generated/_cfg_accounts/hooks/useCfgAccountsApiKeyTestCreate.ts +64 -0
- package/src/_api/generated/_cfg_accounts/hooks/useCfgAccountsOauthConnectionsList.ts +43 -3
- package/src/_api/generated/_cfg_accounts/hooks/useCfgAccountsOauthDisconnectCreate.ts +43 -3
- package/src/_api/generated/_cfg_accounts/hooks/useCfgAccountsOauthGithubAuthorizeCreate.ts +43 -3
- package/src/_api/generated/_cfg_accounts/hooks/useCfgAccountsOauthGithubCallbackCreate.ts +43 -3
- package/src/_api/generated/_cfg_accounts/hooks/useCfgAccountsOauthProvidersRetrieve.ts +43 -3
- package/src/_api/generated/_cfg_accounts/hooks/useCfgAccountsOtpRequestCreate.ts +43 -3
- package/src/_api/generated/_cfg_accounts/hooks/useCfgAccountsOtpVerifyCreate.ts +43 -3
- package/src/_api/generated/_cfg_accounts/hooks/useCfgAccountsProfileAvatarCreate.ts +43 -3
- package/src/_api/generated/_cfg_accounts/hooks/useCfgAccountsProfileDeleteCreate.ts +43 -3
- package/src/_api/generated/_cfg_accounts/hooks/useCfgAccountsProfilePartialPartialUpdate.ts +43 -3
- package/src/_api/generated/_cfg_accounts/hooks/useCfgAccountsProfilePartialUpdate.ts +43 -3
- package/src/_api/generated/_cfg_accounts/hooks/useCfgAccountsProfileRetrieve.ts +43 -3
- package/src/_api/generated/_cfg_accounts/hooks/useCfgAccountsProfileUpdatePartialUpdate.ts +43 -3
- package/src/_api/generated/_cfg_accounts/hooks/useCfgAccountsProfileUpdateUpdate.ts +43 -3
- package/src/_api/generated/_cfg_accounts/hooks/useCfgAccountsTokenRefreshCreate.ts +43 -3
- package/src/_api/generated/_cfg_accounts/index.ts +1 -1
- package/src/_api/generated/_cfg_accounts/schemas/APIKey.ts +13 -0
- package/src/_api/generated/_cfg_accounts/schemas/APIKeyRegenerate.ts +12 -0
- package/src/_api/generated/_cfg_accounts/schemas/APIKeyRequest.ts +13 -0
- package/src/_api/generated/{_cfg_totp/schemas/DeviceListStatusEnum.ts → _cfg_accounts/schemas/APIKeyTestRequest.ts} +4 -2
- package/src/_api/generated/_cfg_accounts/schemas/APIKeyTestResult.ts +12 -0
- package/src/_api/generated/_cfg_accounts/schemas/AccountDeleteResponse.ts +1 -1
- package/src/_api/generated/_cfg_accounts/schemas/CentrifugoToken.ts +2 -2
- package/src/_api/generated/_cfg_accounts/schemas/CfgUserUpdateRequest.ts +3 -2
- package/src/_api/generated/_cfg_accounts/schemas/OAuthCallbackRequestRequest.ts +1 -1
- package/src/_api/generated/_cfg_accounts/schemas/OAuthConnection.ts +6 -6
- package/src/_api/generated/_cfg_accounts/schemas/OAuthDisconnectRequestRequest.ts +2 -2
- package/src/_api/generated/_cfg_accounts/schemas/{ProviderEnum.ts → OAuthProviderEnum.ts} +2 -2
- package/src/_api/generated/_cfg_accounts/schemas/OAuthTokenResponse.ts +5 -5
- package/src/_api/generated/_cfg_accounts/schemas/OTPVerifyRequest.ts +1 -1
- package/src/_api/generated/_cfg_accounts/schemas/OTPVerifyResponse.ts +3 -3
- package/src/_api/generated/_cfg_accounts/schemas/PatchedCfgUserUpdateRequest.ts +3 -2
- package/src/_api/generated/_cfg_accounts/schemas/User.ts +12 -10
- package/src/_api/generated/_cfg_accounts/schemas/cfg_accounts_oauth_connections_response_200_AutoRef.ts +10 -0
- package/src/_api/generated/_cfg_accounts/schemas/cfg_accounts_oauth_disconnect_response_200_AutoRef.ts +11 -0
- package/src/_api/generated/_cfg_accounts/schemas/index.ts +8 -1
- package/src/_api/generated/_cfg_centrifugo/api.ts +3 -3
- package/src/_api/generated/_cfg_centrifugo/hooks/useCfgCentrifugoAuthTokenRetrieve.ts +43 -3
- package/src/_api/generated/_cfg_centrifugo/index.ts +1 -1
- package/src/_api/generated/_cfg_centrifugo/schemas/ConnectionTokenResponse.ts +2 -2
- package/src/_api/generated/_cfg_totp/api.ts +9 -3
- package/src/_api/generated/_cfg_totp/hooks/useCfgTotpBackupCodesRegenerateCreate.ts +43 -3
- package/src/_api/generated/_cfg_totp/hooks/useCfgTotpBackupCodesRetrieve.ts +43 -3
- package/src/_api/generated/_cfg_totp/hooks/useCfgTotpDevicesDestroy.ts +7 -3
- package/src/_api/generated/_cfg_totp/hooks/useCfgTotpDevicesRetrieve.ts +43 -3
- package/src/_api/generated/_cfg_totp/hooks/useCfgTotpDisableCreate.ts +43 -3
- package/src/_api/generated/_cfg_totp/hooks/useCfgTotpSetupConfirmCreate.ts +43 -3
- package/src/_api/generated/_cfg_totp/hooks/useCfgTotpSetupCreate.ts +43 -3
- package/src/_api/generated/_cfg_totp/hooks/useCfgTotpVerifyBackupCreate.ts +43 -3
- package/src/_api/generated/_cfg_totp/hooks/useCfgTotpVerifyCreate.ts +43 -3
- package/src/_api/generated/_cfg_totp/index.ts +1 -1
- package/src/_api/generated/_cfg_totp/schemas/ConfirmSetupRequest.ts +1 -1
- package/src/_api/generated/_cfg_totp/schemas/ConfirmSetupResponse.ts +1 -1
- package/src/_api/generated/_cfg_totp/schemas/DeviceList.ts +5 -5
- package/src/_api/generated/_cfg_totp/schemas/DeviceStatusEnum.ts +9 -0
- package/src/_api/generated/_cfg_totp/schemas/SetupResponse.ts +2 -2
- package/src/_api/generated/_cfg_totp/schemas/TotpVerifyUser.ts +11 -9
- package/src/_api/generated/_cfg_totp/schemas/VerifyBackupRequest.ts +1 -1
- package/src/_api/generated/_cfg_totp/schemas/VerifyRequest.ts +1 -1
- package/src/_api/generated/_cfg_totp/schemas/VerifyResponse.ts +2 -2
- package/src/_api/generated/_cfg_totp/schemas/cfg_totp_disable_response_200_AutoRef.ts +9 -0
- package/src/_api/generated/_cfg_totp/schemas/index.ts +2 -1
- package/src/_api/generated/index.ts +3 -1
- package/src/_api/generated/sdk.gen.ts +80 -813
- package/src/_api/generated/types.gen.ts +320 -159
- package/src/auth/context/AccountsContext.tsx +18 -6
- package/src/auth/context/AuthContext.tsx +11 -3
- package/src/auth/hooks/useDeleteAccount.ts +2 -2
- package/src/auth/hooks/useGithubAuth.ts +3 -3
- package/src/auth/hooks/useTokenRefresh.ts +2 -2
- package/src/auth/hooks/useTwoFactor.ts +3 -3
- package/src/auth/hooks/useTwoFactorSetup.ts +3 -3
- package/src/auth/hooks/useTwoFactorStatus.ts +3 -3
- package/src/auth/middlewares/tokenRefresh.ts +2 -2
- package/src/hooks/index.ts +1 -0
- package/src/hooks/useApiKey.ts +73 -0
- package/src/index.ts +12 -16
package/README.md
CHANGED
|
@@ -1,14 +1,6 @@
|
|
|
1
|
-
<div align="center">
|
|
2
|
-
|
|
3
|
-

|
|
4
|
-
|
|
5
|
-
</div>
|
|
6
|
-
|
|
7
1
|
# @djangocfg/api
|
|
8
2
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
**Part of [DjangoCFG](https://djangocfg.com)** — modern Django framework for production-ready SaaS applications.
|
|
3
|
+
Type-safe API client and auth system for DjangoCFG applications.
|
|
12
4
|
|
|
13
5
|
## Install
|
|
14
6
|
|
|
@@ -16,504 +8,92 @@ Core authentication API client and auth system for DjangoCFG applications.
|
|
|
16
8
|
pnpm add @djangocfg/api
|
|
17
9
|
```
|
|
18
10
|
|
|
19
|
-
## What's Inside
|
|
20
|
-
|
|
21
|
-
This package provides everything needed for authentication and user management:
|
|
22
|
-
|
|
23
|
-
- **API Client** - Type-safe client for Django `cfg_accounts` API
|
|
24
|
-
- **Auth System** - Complete authentication module with contexts, hooks, and utilities
|
|
25
|
-
- **JWT Management** - Automatic token refresh and storage
|
|
26
|
-
- **OAuth Integration** - GitHub OAuth with callback handling
|
|
27
|
-
- **Two-Factor Authentication** - TOTP-based 2FA setup and verification
|
|
28
|
-
- **Server Middleware** - Proxy middleware for Next.js
|
|
29
|
-
- **Shared Storage** - Authentication storage used by all extensions
|
|
30
|
-
|
|
31
|
-
## Package Structure
|
|
32
|
-
|
|
33
|
-
```
|
|
34
|
-
src/
|
|
35
|
-
├── generated/
|
|
36
|
-
│ ├── cfg_accounts/ # Generated API client (accounts, profiles, OAuth)
|
|
37
|
-
│ │ ├── api/ # API class with all endpoints
|
|
38
|
-
│ │ ├── schemas/ # Zod validation schemas
|
|
39
|
-
│ │ └── types/ # TypeScript types
|
|
40
|
-
│ ├── cfg_totp/ # Generated TOTP/2FA client
|
|
41
|
-
│ │ ├── api/ # TOTP device, setup, verification endpoints
|
|
42
|
-
│ │ ├── schemas/ # TOTP-specific schemas
|
|
43
|
-
│ │ └── types/ # TOTP types
|
|
44
|
-
│ └── cfg_centrifugo/ # Generated Centrifugo auth client
|
|
45
|
-
│ ├── api/ # Token endpoint (GET /auth/token/)
|
|
46
|
-
│ ├── schemas/ # Centrifugo response schemas
|
|
47
|
-
│ └── types/ # Centrifugo types
|
|
48
|
-
└── auth/
|
|
49
|
-
├── context/ # AuthProvider, AccountsProvider
|
|
50
|
-
├── hooks/ # useAuth, useAuthGuard, useGithubAuth, useTwoFactor, etc.
|
|
51
|
-
├── middlewares/ # Next.js proxy middleware
|
|
52
|
-
└── utils/ # Validation, errors, logger, analytics
|
|
53
|
-
```
|
|
54
|
-
|
|
55
11
|
## Entry Points
|
|
56
12
|
|
|
57
13
|
| Entry | Import | Description |
|
|
58
14
|
|-------|--------|-------------|
|
|
59
|
-
| **Main** | `@djangocfg/api` |
|
|
60
|
-
| **
|
|
61
|
-
| **Auth** | `@djangocfg/api/auth` |
|
|
62
|
-
| **
|
|
15
|
+
| **Main** | `@djangocfg/api` | API classes, types, fetchers, schemas |
|
|
16
|
+
| **Auth** | `@djangocfg/api/auth` | Auth providers, hooks, utilities |
|
|
17
|
+
| **Auth Server** | `@djangocfg/api/auth/server` | Next.js proxy middleware |
|
|
18
|
+
| **Clients** | `@djangocfg/api/clients` | Pre-configured API instances |
|
|
63
19
|
|
|
64
|
-
## API
|
|
20
|
+
## Generated API Classes
|
|
65
21
|
|
|
66
|
-
|
|
22
|
+
One class per OpenAPI tag. Import directly and call static methods:
|
|
67
23
|
|
|
68
24
|
```typescript
|
|
69
|
-
import {
|
|
25
|
+
import {
|
|
26
|
+
CfgAccounts, // OTP login
|
|
27
|
+
CfgAccountsProfile, // Profile CRUD
|
|
28
|
+
CfgAccountsOauth, // GitHub OAuth
|
|
29
|
+
CfgAccountsAuth, // Token refresh
|
|
30
|
+
CfgAccountsApiKey, // API key management
|
|
31
|
+
CfgTotp, // TOTP devices / disable
|
|
32
|
+
CfgTotpSetup, // TOTP setup / confirm
|
|
33
|
+
CfgTotpVerify, // TOTP verify / backup
|
|
34
|
+
CfgTotpBackupCodes, // Backup codes
|
|
35
|
+
CfgCentrifugo, // Centrifugo token
|
|
36
|
+
} from '@djangocfg/api';
|
|
70
37
|
|
|
71
|
-
//
|
|
72
|
-
await
|
|
73
|
-
|
|
74
|
-
|
|
38
|
+
// OTP login
|
|
39
|
+
const result = await CfgAccounts.cfgAccountsOtpVerifyCreate({
|
|
40
|
+
body: { identifier, otp },
|
|
41
|
+
});
|
|
75
42
|
|
|
76
43
|
// Profile
|
|
77
|
-
const profile = await
|
|
78
|
-
await api.accounts.profileUpdate({ first_name: 'John' });
|
|
79
|
-
|
|
80
|
-
// Password
|
|
81
|
-
await api.accounts.passwordChange({ old_password, new_password });
|
|
82
|
-
await api.accounts.passwordReset({ email });
|
|
83
|
-
await api.accounts.passwordResetConfirm({ token, password });
|
|
84
|
-
|
|
85
|
-
// OAuth
|
|
86
|
-
await api.accounts.oauthCallback({ provider: 'github', code });
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
### Centrifugo Token
|
|
90
|
-
|
|
91
|
-
Fetch a JWT connection token for Centrifugo WebSocket (used by `@djangocfg/centrifugo` provider):
|
|
92
|
-
|
|
93
|
-
```typescript
|
|
94
|
-
import { getCentrifugoAuthTokenRetrieve } from '@djangocfg/api';
|
|
95
|
-
|
|
96
|
-
const { token, centrifugo_url, channels, expires_at } =
|
|
97
|
-
await getCentrifugoAuthTokenRetrieve();
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
### Shared Authentication Storage
|
|
101
|
-
|
|
102
|
-
All DjangoCFG extensions use shared authentication storage from this package:
|
|
44
|
+
const profile = await CfgAccountsProfile.cfgAccountsProfileRetrieve();
|
|
103
45
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
// All API clients share the same authentication state
|
|
110
|
-
// Login once, authenticated everywhere
|
|
46
|
+
// Token refresh
|
|
47
|
+
const tokens = await CfgAccountsAuth.cfgAccountsTokenRefreshCreate({
|
|
48
|
+
body: { refresh },
|
|
49
|
+
});
|
|
111
50
|
```
|
|
112
51
|
|
|
113
|
-
This is handled automatically by `createExtensionAPI()` from `@djangocfg/ext-base`.
|
|
114
|
-
|
|
115
52
|
## Auth Module
|
|
116
53
|
|
|
117
|
-
Complete authentication system with OTP, OAuth, and Two-Factor Authentication (2FA) support.
|
|
118
|
-
|
|
119
|
-
### Authentication Flow
|
|
120
|
-
|
|
121
|
-
```
|
|
122
|
-
1. User enters email → OTP sent
|
|
123
|
-
2. User enters OTP code → Verify
|
|
124
|
-
├── If 2FA enabled → Show TOTP verification
|
|
125
|
-
│ └── User enters 6-digit TOTP → Verify
|
|
126
|
-
└── If no 2FA → Continue
|
|
127
|
-
3. Success screen with logo → Auto-redirect to dashboard
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
All authentication methods (OTP, OAuth, 2FA) show a success screen with your logo before redirecting.
|
|
131
|
-
|
|
132
|
-
### Setup
|
|
133
|
-
|
|
134
54
|
```tsx
|
|
135
|
-
|
|
136
|
-
import { AuthProvider } from '@djangocfg/api/auth';
|
|
55
|
+
import { AuthProvider, useAuth } from '@djangocfg/api/auth';
|
|
137
56
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
auth: '/auth',
|
|
146
|
-
defaultCallback: '/dashboard'
|
|
147
|
-
}
|
|
148
|
-
}}
|
|
149
|
-
>
|
|
150
|
-
{children}
|
|
151
|
-
</AuthProvider>
|
|
152
|
-
</body>
|
|
153
|
-
</html>
|
|
154
|
-
);
|
|
155
|
-
}
|
|
57
|
+
// Provider
|
|
58
|
+
<AuthProvider config={{ routes: { auth: '/auth', defaultCallback: '/dashboard' } }}>
|
|
59
|
+
{children}
|
|
60
|
+
</AuthProvider>
|
|
61
|
+
|
|
62
|
+
// Hook
|
|
63
|
+
const { user, isAuthenticated, requestOTP, verifyOTP, logout } = useAuth();
|
|
156
64
|
```
|
|
157
65
|
|
|
158
|
-
###
|
|
66
|
+
### Auth Hooks
|
|
159
67
|
|
|
160
68
|
```typescript
|
|
161
69
|
import {
|
|
162
|
-
useAuth, // Main auth context
|
|
163
|
-
useAuthGuard, //
|
|
164
|
-
useAuthForm, //
|
|
165
|
-
useGithubAuth, // GitHub OAuth
|
|
166
|
-
useTwoFactor, // 2FA verification
|
|
167
|
-
useTwoFactorSetup, // 2FA setup flow
|
|
168
|
-
useTwoFactorStatus, // 2FA status
|
|
169
|
-
|
|
170
|
-
useLocalStorage, // localStorage helper
|
|
171
|
-
useSessionStorage, // sessionStorage helper
|
|
70
|
+
useAuth, // Main auth context
|
|
71
|
+
useAuthGuard, // Route protection
|
|
72
|
+
useAuthForm, // OTP form state machine
|
|
73
|
+
useGithubAuth, // GitHub OAuth
|
|
74
|
+
useTwoFactor, // 2FA verification
|
|
75
|
+
useTwoFactorSetup, // 2FA setup flow
|
|
76
|
+
useTwoFactorStatus, // 2FA status / disable
|
|
77
|
+
useDeleteAccount, // Account deletion
|
|
172
78
|
} from '@djangocfg/api/auth';
|
|
173
79
|
```
|
|
174
80
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
Main authentication hook with OTP support:
|
|
178
|
-
|
|
179
|
-
```tsx
|
|
180
|
-
'use client';
|
|
181
|
-
import { useAuth } from '@djangocfg/api/auth';
|
|
182
|
-
|
|
183
|
-
export function UserProfile() {
|
|
184
|
-
const {
|
|
185
|
-
user, // UserProfile | null
|
|
186
|
-
isAuthenticated, // boolean
|
|
187
|
-
isLoading, // boolean
|
|
188
|
-
requestOTP, // (identifier, sourceUrl?) => Promise<{ success, message }>
|
|
189
|
-
verifyOTP, // (identifier, otp, sourceUrl?, redirectUrl?) => Promise<{ success, message, user? }>
|
|
190
|
-
logout, // () => void
|
|
191
|
-
} = useAuth();
|
|
192
|
-
|
|
193
|
-
if (isLoading) return <div>Loading...</div>;
|
|
194
|
-
|
|
195
|
-
if (!isAuthenticated) {
|
|
196
|
-
return <div>Please sign in</div>;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
return (
|
|
200
|
-
<div>
|
|
201
|
-
<p>Welcome, {user?.email}!</p>
|
|
202
|
-
<button onClick={logout}>Logout</button>
|
|
203
|
-
</div>
|
|
204
|
-
);
|
|
205
|
-
}
|
|
206
|
-
```
|
|
207
|
-
|
|
208
|
-
### useAuthGuard
|
|
209
|
-
|
|
210
|
-
Protect routes from unauthenticated access:
|
|
211
|
-
|
|
212
|
-
```tsx
|
|
213
|
-
'use client';
|
|
214
|
-
import { useAuthGuard } from '@djangocfg/api/auth';
|
|
215
|
-
|
|
216
|
-
export default function DashboardPage() {
|
|
217
|
-
const { isAllowed } = useAuthGuard({
|
|
218
|
-
redirectTo: '/auth',
|
|
219
|
-
requireAuth: true,
|
|
220
|
-
});
|
|
221
|
-
|
|
222
|
-
if (!isAllowed) return null;
|
|
223
|
-
|
|
224
|
-
return <div>Protected Dashboard Content</div>;
|
|
225
|
-
}
|
|
226
|
-
```
|
|
227
|
-
|
|
228
|
-
### useAuthForm
|
|
229
|
-
|
|
230
|
-
Manage authentication form state with OTP and 2FA support:
|
|
231
|
-
|
|
232
|
-
```tsx
|
|
233
|
-
'use client';
|
|
234
|
-
import { useAuthForm } from '@djangocfg/api/auth';
|
|
235
|
-
|
|
236
|
-
export function OTPLoginForm() {
|
|
237
|
-
const {
|
|
238
|
-
// State
|
|
239
|
-
identifier, // Email address
|
|
240
|
-
otp, // 6-digit OTP code
|
|
241
|
-
step, // 'identifier' | 'otp' | '2fa' | '2fa-setup' | 'success'
|
|
242
|
-
isLoading,
|
|
243
|
-
error,
|
|
244
|
-
acceptedTerms,
|
|
245
|
-
isRateLimited, // boolean - true when rate limited
|
|
246
|
-
rateLimitLabel, // string - formatted countdown e.g. "1:30" or "45s"
|
|
247
|
-
|
|
248
|
-
// Setters
|
|
249
|
-
setIdentifier,
|
|
250
|
-
setOtp,
|
|
251
|
-
setAcceptedTerms,
|
|
252
|
-
|
|
253
|
-
// Handlers
|
|
254
|
-
handleIdentifierSubmit, // Request OTP
|
|
255
|
-
handleOTPSubmit, // Verify OTP
|
|
256
|
-
handleResendOTP, // Resend OTP
|
|
257
|
-
handleBackToIdentifier, // Go back to step 1
|
|
258
|
-
|
|
259
|
-
// Utilities
|
|
260
|
-
validateIdentifier,
|
|
261
|
-
} = useAuthForm({
|
|
262
|
-
sourceUrl: window.location.origin,
|
|
263
|
-
requireTermsAcceptance: false, // Set true if terms/privacy links provided
|
|
264
|
-
onIdentifierSuccess: (identifier) => {
|
|
265
|
-
console.log('OTP sent to', identifier);
|
|
266
|
-
},
|
|
267
|
-
onOTPSuccess: () => {
|
|
268
|
-
console.log('Login successful');
|
|
269
|
-
},
|
|
270
|
-
});
|
|
271
|
-
|
|
272
|
-
if (step === 'identifier') {
|
|
273
|
-
return (
|
|
274
|
-
<form onSubmit={handleIdentifierSubmit}>
|
|
275
|
-
<input
|
|
276
|
-
type="email"
|
|
277
|
-
value={identifier}
|
|
278
|
-
onChange={(e) => setIdentifier(e.target.value)}
|
|
279
|
-
placeholder="Enter email"
|
|
280
|
-
/>
|
|
281
|
-
{error && <p className="text-red-500">{error}</p>}
|
|
282
|
-
<button type="submit" disabled={isLoading}>
|
|
283
|
-
{isLoading ? 'Sending...' : 'Send verification code'}
|
|
284
|
-
</button>
|
|
285
|
-
</form>
|
|
286
|
-
);
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
return (
|
|
290
|
-
<form onSubmit={handleOTPSubmit}>
|
|
291
|
-
<p>Enter the code sent to {identifier}</p>
|
|
292
|
-
<input
|
|
293
|
-
type="text"
|
|
294
|
-
value={otp}
|
|
295
|
-
onChange={(e) => setOtp(e.target.value)}
|
|
296
|
-
placeholder="000000"
|
|
297
|
-
maxLength={6}
|
|
298
|
-
/>
|
|
299
|
-
{error && <p className="text-red-500">{error}</p>}
|
|
300
|
-
<button type="submit" disabled={isLoading || otp.length < 6}>
|
|
301
|
-
{isLoading ? 'Verifying...' : 'Verify'}
|
|
302
|
-
</button>
|
|
303
|
-
<button type="button" onClick={handleResendOTP}>Resend</button>
|
|
304
|
-
<button type="button" onClick={handleBackToIdentifier}>Back</button>
|
|
305
|
-
</form>
|
|
306
|
-
);
|
|
307
|
-
}
|
|
308
|
-
```
|
|
309
|
-
|
|
310
|
-
#### useAuthForm Options
|
|
311
|
-
|
|
312
|
-
| Option | Type | Default | Description |
|
|
313
|
-
|--------|------|---------|-------------|
|
|
314
|
-
| `sourceUrl` | `string` | required | Application URL for OTP emails |
|
|
315
|
-
| `redirectUrl` | `string` | - | URL to redirect after successful OTP verification |
|
|
316
|
-
| `requireTermsAcceptance` | `boolean` | `false` | Require terms acceptance before submit |
|
|
317
|
-
| `onIdentifierSuccess` | `function` | - | Callback after OTP sent |
|
|
318
|
-
| `onOTPSuccess` | `function` | - | Callback after successful verification |
|
|
319
|
-
| `onError` | `function` | - | Callback on error |
|
|
320
|
-
|
|
321
|
-
### useGithubAuth
|
|
322
|
-
|
|
323
|
-
GitHub OAuth integration:
|
|
324
|
-
|
|
325
|
-
```tsx
|
|
326
|
-
'use client';
|
|
327
|
-
import { useGithubAuth } from '@djangocfg/api/auth';
|
|
328
|
-
|
|
329
|
-
export function GithubLoginButton() {
|
|
330
|
-
const {
|
|
331
|
-
startGithubAuth, // () => void - redirects to GitHub
|
|
332
|
-
isLoading, // boolean
|
|
333
|
-
error, // string | null
|
|
334
|
-
} = useGithubAuth({
|
|
335
|
-
sourceUrl: window.location.origin,
|
|
336
|
-
});
|
|
337
|
-
|
|
338
|
-
return (
|
|
339
|
-
<button onClick={startGithubAuth} disabled={isLoading}>
|
|
340
|
-
{isLoading ? 'Connecting...' : 'Continue with GitHub'}
|
|
341
|
-
</button>
|
|
342
|
-
);
|
|
343
|
-
}
|
|
344
|
-
```
|
|
345
|
-
|
|
346
|
-
OAuth callback is handled automatically by `@djangocfg/layouts` AuthLayout component.
|
|
347
|
-
|
|
348
|
-
### useTwoFactor
|
|
349
|
-
|
|
350
|
-
Verify 2FA code during authentication:
|
|
351
|
-
|
|
352
|
-
```tsx
|
|
353
|
-
'use client';
|
|
354
|
-
import { useTwoFactor } from '@djangocfg/api/auth';
|
|
355
|
-
|
|
356
|
-
export function TwoFactorVerify({ sessionId }: { sessionId: string }) {
|
|
357
|
-
const {
|
|
358
|
-
verify, // (code: string) => Promise<void>
|
|
359
|
-
isLoading, // boolean
|
|
360
|
-
error, // string | null
|
|
361
|
-
} = useTwoFactor({
|
|
362
|
-
sessionId,
|
|
363
|
-
onSuccess: (user) => console.log('2FA verified:', user),
|
|
364
|
-
onError: (error) => console.error('2FA failed:', error),
|
|
365
|
-
redirectUrl: '/dashboard',
|
|
366
|
-
skipRedirect: false, // Set true if handling navigation manually
|
|
367
|
-
});
|
|
368
|
-
|
|
369
|
-
const [code, setCode] = useState('');
|
|
370
|
-
|
|
371
|
-
return (
|
|
372
|
-
<form onSubmit={(e) => { e.preventDefault(); verify(code); }}>
|
|
373
|
-
<input
|
|
374
|
-
type="text"
|
|
375
|
-
value={code}
|
|
376
|
-
onChange={(e) => setCode(e.target.value)}
|
|
377
|
-
placeholder="000000"
|
|
378
|
-
maxLength={6}
|
|
379
|
-
/>
|
|
380
|
-
<button type="submit" disabled={isLoading || code.length < 6}>
|
|
381
|
-
{isLoading ? 'Verifying...' : 'Verify'}
|
|
382
|
-
</button>
|
|
383
|
-
</form>
|
|
384
|
-
);
|
|
385
|
-
}
|
|
386
|
-
```
|
|
387
|
-
|
|
388
|
-
### useTwoFactorSetup
|
|
389
|
-
|
|
390
|
-
Setup 2FA for authenticated users:
|
|
391
|
-
|
|
392
|
-
```tsx
|
|
393
|
-
'use client';
|
|
394
|
-
import { useTwoFactorSetup } from '@djangocfg/api/auth';
|
|
395
|
-
|
|
396
|
-
export function TwoFactorSetup() {
|
|
397
|
-
const {
|
|
398
|
-
// State
|
|
399
|
-
qrCode, // Base64 QR code image
|
|
400
|
-
secret, // Manual entry secret
|
|
401
|
-
isEnabled, // Current 2FA status
|
|
402
|
-
isLoading,
|
|
403
|
-
error,
|
|
404
|
-
|
|
405
|
-
// Actions
|
|
406
|
-
startSetup, // () => Promise<void> - generates QR code
|
|
407
|
-
verifySetup, // (code: string) => Promise<void> - enables 2FA
|
|
408
|
-
disable, // () => Promise<void> - disables 2FA
|
|
409
|
-
checkStatus, // () => Promise<boolean> - refresh status
|
|
410
|
-
} = useTwoFactorSetup({
|
|
411
|
-
onSetupComplete: () => console.log('2FA enabled successfully'),
|
|
412
|
-
onDisabled: () => console.log('2FA disabled'),
|
|
413
|
-
onError: (error) => console.error('2FA setup error:', error),
|
|
414
|
-
});
|
|
415
|
-
|
|
416
|
-
if (isEnabled) {
|
|
417
|
-
return (
|
|
418
|
-
<div>
|
|
419
|
-
<p>Two-factor authentication is enabled</p>
|
|
420
|
-
<button onClick={disable}>Disable 2FA</button>
|
|
421
|
-
</div>
|
|
422
|
-
);
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
if (qrCode) {
|
|
426
|
-
return (
|
|
427
|
-
<div>
|
|
428
|
-
<img src={qrCode} alt="2FA QR Code" />
|
|
429
|
-
<p>Secret: {secret}</p>
|
|
430
|
-
<input placeholder="Enter code from app" />
|
|
431
|
-
<button onClick={() => verifySetup('123456')}>Verify & Enable</button>
|
|
432
|
-
</div>
|
|
433
|
-
);
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
return <button onClick={startSetup}>Set up 2FA</button>;
|
|
437
|
-
}
|
|
438
|
-
```
|
|
439
|
-
|
|
440
|
-
### useTwoFactorStatus
|
|
441
|
-
|
|
442
|
-
Check 2FA status and disable 2FA for authenticated users:
|
|
443
|
-
|
|
444
|
-
```tsx
|
|
445
|
-
'use client';
|
|
446
|
-
import { useTwoFactorStatus } from '@djangocfg/api/auth';
|
|
447
|
-
|
|
448
|
-
export function TwoFactorStatus() {
|
|
449
|
-
const {
|
|
450
|
-
// State
|
|
451
|
-
has2FAEnabled, // boolean | null - current 2FA status
|
|
452
|
-
devices, // TwoFactorDevice[] - list of TOTP devices
|
|
453
|
-
isLoading,
|
|
454
|
-
error,
|
|
455
|
-
|
|
456
|
-
// Actions
|
|
457
|
-
fetchStatus, // () => Promise<void> - refresh status
|
|
458
|
-
disable2FA, // (code: string) => Promise<boolean> - disable with TOTP code
|
|
459
|
-
clearError, // () => void
|
|
460
|
-
} = useTwoFactorStatus();
|
|
461
|
-
|
|
462
|
-
useEffect(() => {
|
|
463
|
-
fetchStatus();
|
|
464
|
-
}, [fetchStatus]);
|
|
465
|
-
|
|
466
|
-
if (has2FAEnabled) {
|
|
467
|
-
return (
|
|
468
|
-
<div>
|
|
469
|
-
<p>2FA is enabled</p>
|
|
470
|
-
<p>Devices: {devices.length}</p>
|
|
471
|
-
<button onClick={() => disable2FA('123456')}>Disable 2FA</button>
|
|
472
|
-
</div>
|
|
473
|
-
);
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
return <p>2FA is not enabled</p>;
|
|
477
|
-
}
|
|
478
|
-
```
|
|
479
|
-
|
|
480
|
-
## Server Components & API Routes
|
|
481
|
-
|
|
482
|
-
Use fetchers for server-side data fetching:
|
|
81
|
+
## Type Namespaces
|
|
483
82
|
|
|
484
83
|
```typescript
|
|
485
|
-
import {
|
|
486
|
-
|
|
487
|
-
// Server Component
|
|
488
|
-
export default async function ProfilePage() {
|
|
489
|
-
const profile = await Fetchers.getAccountsProfileRetrieve(api);
|
|
490
|
-
|
|
491
|
-
return <div>{profile.email}</div>;
|
|
492
|
-
}
|
|
84
|
+
import type { AccountsTypes, TotpTypes, CentrifugoTypes } from '@djangocfg/api';
|
|
493
85
|
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
try {
|
|
497
|
-
const profile = await Fetchers.getAccountsProfileRetrieve(api);
|
|
498
|
-
return Response.json(profile);
|
|
499
|
-
} catch (error) {
|
|
500
|
-
return Response.json({ error: 'Failed to fetch profile' }, { status: 500 });
|
|
501
|
-
}
|
|
502
|
-
}
|
|
86
|
+
type User = AccountsTypes.User;
|
|
87
|
+
type Device = TotpTypes.TotpDevice;
|
|
503
88
|
```
|
|
504
89
|
|
|
505
90
|
## Server Middleware
|
|
506
91
|
|
|
507
|
-
Proxy middleware for Django backend:
|
|
508
|
-
|
|
509
92
|
```typescript
|
|
510
93
|
// middleware.ts
|
|
511
94
|
import { proxyMiddleware } from '@djangocfg/api/auth/server';
|
|
512
|
-
import { NextRequest } from 'next/server';
|
|
513
95
|
|
|
514
96
|
export function middleware(request: NextRequest) {
|
|
515
|
-
// Proxies /media/* and /api/* to Django backend
|
|
516
|
-
// Automatically forwards cookies and headers
|
|
517
97
|
return proxyMiddleware(request);
|
|
518
98
|
}
|
|
519
99
|
|
|
@@ -522,174 +102,15 @@ export const config = {
|
|
|
522
102
|
};
|
|
523
103
|
```
|
|
524
104
|
|
|
525
|
-
##
|
|
526
|
-
|
|
527
|
-
Use SWR hooks for reactive data fetching in client components:
|
|
528
|
-
|
|
529
|
-
```tsx
|
|
530
|
-
'use client';
|
|
531
|
-
import { useAccountsProfileRetrieve, useAccountsProfileUpdate } from '@djangocfg/api/hooks';
|
|
532
|
-
|
|
533
|
-
export function Profile() {
|
|
534
|
-
const { data: profile, isLoading, error, mutate } = useAccountsProfileRetrieve();
|
|
535
|
-
const { trigger: updateProfile } = useAccountsProfileUpdate();
|
|
536
|
-
|
|
537
|
-
const handleUpdate = async () => {
|
|
538
|
-
await updateProfile({ first_name: 'John' });
|
|
539
|
-
mutate(); // Revalidate data
|
|
540
|
-
};
|
|
541
|
-
|
|
542
|
-
if (isLoading) return <div>Loading...</div>;
|
|
543
|
-
if (error) return <div>Error: {error.message}</div>;
|
|
544
|
-
|
|
545
|
-
return (
|
|
546
|
-
<div>
|
|
547
|
-
<p>Email: {profile?.email}</p>
|
|
548
|
-
<button onClick={handleUpdate}>Update Profile</button>
|
|
549
|
-
</div>
|
|
550
|
-
);
|
|
551
|
-
}
|
|
552
|
-
```
|
|
553
|
-
|
|
554
|
-
## Validation Schemas
|
|
555
|
-
|
|
556
|
-
Zod schemas for runtime validation:
|
|
557
|
-
|
|
558
|
-
```typescript
|
|
559
|
-
import { Schemas } from '@djangocfg/api';
|
|
560
|
-
|
|
561
|
-
// Validate API responses
|
|
562
|
-
const profile = Schemas.UserProfileSchema.parse(data);
|
|
563
|
-
|
|
564
|
-
// Validate form data
|
|
565
|
-
const loginData = Schemas.LoginRequestSchema.parse({
|
|
566
|
-
email: 'user@example.com',
|
|
567
|
-
password: 'password123',
|
|
568
|
-
});
|
|
569
|
-
```
|
|
570
|
-
|
|
571
|
-
## TypeScript Types
|
|
572
|
-
|
|
573
|
-
Full type safety for all API operations:
|
|
574
|
-
|
|
575
|
-
```typescript
|
|
576
|
-
import type {
|
|
577
|
-
UserProfile,
|
|
578
|
-
LoginRequest,
|
|
579
|
-
RegisterRequest,
|
|
580
|
-
OAuthProvider,
|
|
581
|
-
OAuthCallbackRequest,
|
|
582
|
-
} from '@djangocfg/api';
|
|
583
|
-
|
|
584
|
-
// Or use namespace
|
|
585
|
-
import type { CfgAccountsTypes } from '@djangocfg/api';
|
|
586
|
-
type Profile = CfgAccountsTypes.UserProfile;
|
|
587
|
-
type LoginReq = CfgAccountsTypes.LoginRequest;
|
|
588
|
-
```
|
|
589
|
-
|
|
590
|
-
## Extension Packages
|
|
591
|
-
|
|
592
|
-
Extensions are now in **separate packages** with their own API clients that share authentication:
|
|
593
|
-
|
|
594
|
-
| Extension | Package | Description |
|
|
595
|
-
|-----------|---------|-------------|
|
|
596
|
-
| **Newsletter** | `@djangocfg/ext-newsletter` | Newsletter subscription and campaigns |
|
|
597
|
-
| **Knowledge Base** | `@djangocfg/ext-knowbase` | Documentation, chat, RAG-powered AI |
|
|
598
|
-
| **Leads** | `@djangocfg/ext-leads` | Lead capture and contact forms |
|
|
599
|
-
| **Payments** | `@djangocfg/ext-payments` | Payment processing and subscriptions |
|
|
600
|
-
| **Support** | `@djangocfg/ext-support` | Support tickets and helpdesk |
|
|
601
|
-
|
|
602
|
-
### Extension Usage
|
|
603
|
-
|
|
604
|
-
```typescript
|
|
605
|
-
// Extensions automatically use shared auth from @djangocfg/api
|
|
606
|
-
import { apiSupport } from '@djangocfg/ext-support';
|
|
607
|
-
import { apiPayments } from '@djangocfg/ext-payments';
|
|
608
|
-
import { apiLeads } from '@djangocfg/ext-leads';
|
|
609
|
-
|
|
610
|
-
// All authenticated automatically if user is logged in
|
|
611
|
-
const tickets = await apiSupport.tickets.list();
|
|
612
|
-
const payments = await apiPayments.payments.list();
|
|
613
|
-
const leads = await apiLeads.leads.list();
|
|
614
|
-
```
|
|
615
|
-
|
|
616
|
-
See individual extension documentation for details.
|
|
617
|
-
|
|
618
|
-
## Error Handling
|
|
619
|
-
|
|
620
|
-
```typescript
|
|
621
|
-
import { handleError, formatError } from '@djangocfg/api/auth';
|
|
622
|
-
|
|
623
|
-
try {
|
|
624
|
-
await api.accounts.login({ email, password });
|
|
625
|
-
} catch (error) {
|
|
626
|
-
handleError(error, (formattedError) => {
|
|
627
|
-
console.error('Login failed:', formattedError);
|
|
628
|
-
// formattedError has consistent structure:
|
|
629
|
-
// { message: string, code?: string, details?: any }
|
|
630
|
-
});
|
|
631
|
-
}
|
|
632
|
-
```
|
|
633
|
-
|
|
634
|
-
## Analytics Integration
|
|
635
|
-
|
|
636
|
-
Auth events are automatically tracked when analytics is enabled:
|
|
637
|
-
|
|
638
|
-
```typescript
|
|
639
|
-
// Automatic tracking for:
|
|
640
|
-
// - AUTH_LOGIN_SUCCESS
|
|
641
|
-
// - AUTH_LOGOUT
|
|
642
|
-
// - AUTH_SESSION_EXPIRED
|
|
643
|
-
// - AUTH_TOKEN_REFRESH
|
|
644
|
-
// - AUTH_OAUTH_START
|
|
645
|
-
// - AUTH_OAUTH_SUCCESS
|
|
646
|
-
// - AUTH_OAUTH_FAIL
|
|
647
|
-
// - AUTH_2FA_SETUP_START
|
|
648
|
-
// - AUTH_2FA_SETUP_COMPLETE
|
|
649
|
-
// - AUTH_2FA_VERIFY_SUCCESS
|
|
650
|
-
// - AUTH_2FA_VERIFY_FAIL
|
|
651
|
-
```
|
|
652
|
-
|
|
653
|
-
Analytics setup is handled by `@djangocfg/layouts` package.
|
|
654
|
-
|
|
655
|
-
## Environment Variables
|
|
105
|
+
## Environment
|
|
656
106
|
|
|
657
107
|
```bash
|
|
658
|
-
# Required
|
|
659
108
|
NEXT_PUBLIC_API_URL=http://localhost:8000
|
|
660
|
-
|
|
661
|
-
# OAuth (optional)
|
|
662
|
-
NEXT_PUBLIC_GITHUB_CLIENT_ID=your_github_client_id
|
|
663
|
-
|
|
664
|
-
# Static build (optional)
|
|
665
|
-
NEXT_PUBLIC_STATIC_BUILD=false
|
|
666
109
|
```
|
|
667
110
|
|
|
668
|
-
##
|
|
111
|
+
## Regenerate Client
|
|
669
112
|
|
|
670
113
|
```bash
|
|
671
|
-
#
|
|
672
|
-
make
|
|
673
|
-
|
|
674
|
-
# Build package
|
|
675
|
-
make build
|
|
676
|
-
|
|
677
|
-
# Watch mode
|
|
678
|
-
pnpm dev
|
|
114
|
+
# From django solution directory
|
|
115
|
+
make api
|
|
679
116
|
```
|
|
680
|
-
|
|
681
|
-
## Requirements
|
|
682
|
-
|
|
683
|
-
- Next.js >= 15
|
|
684
|
-
- React >= 19
|
|
685
|
-
- SWR (peer dependency)
|
|
686
|
-
- Zod (bundled for validation)
|
|
687
|
-
|
|
688
|
-
## License
|
|
689
|
-
|
|
690
|
-
MIT
|
|
691
|
-
|
|
692
|
-
## Links
|
|
693
|
-
|
|
694
|
-
- [DjangoCFG Documentation](https://djangocfg.com)
|
|
695
|
-
- [GitHub](https://github.com/markolofsen/django-cfg)
|