@djangocfg/api 2.1.583 → 2.1.584
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/dist/OAuthTokenResponse-WEDM6IP5.mjs +19 -0
- package/dist/OAuthTokenResponse-WEDM6IP5.mjs.map +1 -0
- package/dist/OTPVerifyResponse-P5LDNM7H.mjs +20 -0
- package/dist/OTPVerifyResponse-P5LDNM7H.mjs.map +1 -0
- package/dist/PasswordLoginResponse-33B576NG.mjs +20 -0
- package/dist/PasswordLoginResponse-33B576NG.mjs.map +1 -0
- package/dist/auth.cjs +12 -28
- package/dist/auth.cjs.map +1 -1
- package/dist/auth.d.cts +14 -41
- package/dist/auth.d.ts +14 -41
- package/dist/auth.mjs +12 -26
- package/dist/auth.mjs.map +1 -1
- package/dist/clients.cjs +0 -1
- package/dist/clients.cjs.map +1 -1
- package/dist/clients.d.cts +13 -41
- package/dist/clients.d.ts +13 -41
- package/dist/clients.mjs +0 -1
- package/dist/clients.mjs.map +1 -1
- package/dist/hooks.cjs +0 -1
- package/dist/hooks.cjs.map +1 -1
- package/dist/hooks.mjs +0 -1
- package/dist/hooks.mjs.map +1 -1
- package/dist/index.cjs +0 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -64
- package/dist/index.d.ts +7 -64
- package/dist/index.mjs +0 -1
- package/dist/index.mjs.map +1 -1
- package/dist/storage.cjs +0 -1
- package/dist/storage.cjs.map +1 -1
- package/dist/storage.d.cts +0 -1
- package/dist/storage.d.ts +0 -1
- package/dist/storage.mjs +0 -1
- package/dist/storage.mjs.map +1 -1
- package/package.json +2 -2
- package/src/_api/generated/_cfg_accounts/openapi.json +1 -28
- package/src/_api/generated/_cfg_accounts/schemas/OAuthCallbackRequestRequest.ts +0 -1
- package/src/_api/generated/_cfg_accounts/schemas/OAuthTokenResponse.ts +0 -1
- package/src/_api/generated/_cfg_accounts/schemas/OTPVerifyRequest.ts +0 -1
- package/src/_api/generated/_cfg_accounts/schemas/OTPVerifyResponse.ts +0 -1
- package/src/_api/generated/_cfg_accounts/schemas/PasswordLoginRequest.ts +0 -1
- package/src/_api/generated/_cfg_accounts/schemas/PasswordLoginResponse.ts +0 -1
- package/src/_api/generated/_cfg_totp/openapi.json +0 -5
- package/src/_api/generated/_cfg_totp/schemas/VerifyResponse.ts +0 -1
- package/src/_api/generated/helpers/auth.ts +1 -1
- package/src/_api/generated/helpers/keys.ts +0 -1
- package/src/_api/generated/openapi.json +1 -33
- package/src/_api/generated/types.gen.ts +4 -59
- package/src/auth/__tests__/passwordLogin.test.tsx +1 -3
- package/src/auth/context/AccountsContext.tsx +6 -8
- package/src/auth/context/AuthContext.tsx +1 -4
- package/src/auth/context/types.ts +1 -1
- package/src/auth/hooks/useAuthForm.ts +3 -5
- package/src/auth/hooks/useAuthFormState.ts +0 -4
- package/src/auth/hooks/useGithubAuth.ts +5 -12
- package/src/auth/hooks/useTwoFactorVerify.ts +2 -2
- package/src/auth/types/form.ts +0 -5
|
@@ -321,10 +321,6 @@ export type OAuthCallbackRequestRequest = {
|
|
|
321
321
|
* Same redirect_uri used in authorize request. If not provided, uses config's site_url + callback_path
|
|
322
322
|
*/
|
|
323
323
|
redirect_uri?: string;
|
|
324
|
-
/**
|
|
325
|
-
* Keep this browser signed in for 30 days
|
|
326
|
-
*/
|
|
327
|
-
remember_me?: boolean;
|
|
328
324
|
};
|
|
329
325
|
|
|
330
326
|
/**
|
|
@@ -454,10 +450,6 @@ export type OAuthTokenResponse = {
|
|
|
454
450
|
* True if user should be prompted to enable 2FA
|
|
455
451
|
*/
|
|
456
452
|
should_prompt_2fa?: boolean;
|
|
457
|
-
/**
|
|
458
|
-
* Whether this login should persist across browser restarts
|
|
459
|
-
*/
|
|
460
|
-
persistent_session?: boolean;
|
|
461
453
|
};
|
|
462
454
|
|
|
463
455
|
/**
|
|
@@ -545,10 +537,6 @@ export type OtpVerifyRequest = {
|
|
|
545
537
|
* Source URL for tracking login (e.g., https://my.djangocfg.com)
|
|
546
538
|
*/
|
|
547
539
|
source_url?: string;
|
|
548
|
-
/**
|
|
549
|
-
* Keep this browser signed in for 30 days
|
|
550
|
-
*/
|
|
551
|
-
remember_me?: boolean;
|
|
552
540
|
};
|
|
553
541
|
|
|
554
542
|
/**
|
|
@@ -589,10 +577,6 @@ export type OtpVerifyResponse = {
|
|
|
589
577
|
* Whether user should be prompted to enable 2FA
|
|
590
578
|
*/
|
|
591
579
|
should_prompt_2fa?: boolean;
|
|
592
|
-
/**
|
|
593
|
-
* Whether this login should persist across browser restarts
|
|
594
|
-
*/
|
|
595
|
-
persistent_session?: boolean;
|
|
596
580
|
};
|
|
597
581
|
|
|
598
582
|
/**
|
|
@@ -623,14 +607,12 @@ export type PasswordLoginError = {
|
|
|
623
607
|
*
|
|
624
608
|
* Subclasses SimpleJWT so the field/validation contract stays theirs, but
|
|
625
609
|
* replaces ``validate()`` — the token pair itself is minted by the view via
|
|
626
|
-
* ``mint_tokens_for_request`` so the DPoP binding and
|
|
610
|
+
* ``mint_tokens_for_request`` so the DPoP binding and token
|
|
627
611
|
* lifetime match OTP, OAuth and TOTP exactly.
|
|
628
612
|
*/
|
|
629
613
|
export type PasswordLoginRequest = {
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
*/
|
|
633
|
-
remember_me?: boolean;
|
|
614
|
+
email: string;
|
|
615
|
+
password: string;
|
|
634
616
|
};
|
|
635
617
|
|
|
636
618
|
/**
|
|
@@ -664,10 +646,6 @@ export type PasswordLoginResponse = {
|
|
|
664
646
|
* Whether user should be prompted to enable 2FA
|
|
665
647
|
*/
|
|
666
648
|
should_prompt_2fa?: boolean;
|
|
667
|
-
/**
|
|
668
|
-
* Whether this login should persist across browser restarts
|
|
669
|
-
*/
|
|
670
|
-
persistent_session?: boolean;
|
|
671
649
|
};
|
|
672
650
|
|
|
673
651
|
/**
|
|
@@ -868,10 +846,6 @@ export type VerifyResponse = {
|
|
|
868
846
|
* User profile data
|
|
869
847
|
*/
|
|
870
848
|
user: TotpVerifyUser;
|
|
871
|
-
/**
|
|
872
|
-
* Whether this login should persist across browser restarts
|
|
873
|
-
*/
|
|
874
|
-
persistent_session: boolean;
|
|
875
849
|
/**
|
|
876
850
|
* Number of remaining backup codes (if backup code was used)
|
|
877
851
|
*/
|
|
@@ -1064,27 +1038,6 @@ export type OtpVerifyResponseWritable = {
|
|
|
1064
1038
|
* Whether user should be prompted to enable 2FA
|
|
1065
1039
|
*/
|
|
1066
1040
|
should_prompt_2fa?: boolean;
|
|
1067
|
-
/**
|
|
1068
|
-
* Whether this login should persist across browser restarts
|
|
1069
|
-
*/
|
|
1070
|
-
persistent_session?: boolean;
|
|
1071
|
-
};
|
|
1072
|
-
|
|
1073
|
-
/**
|
|
1074
|
-
* Validate email+password against live accounts only.
|
|
1075
|
-
*
|
|
1076
|
-
* Subclasses SimpleJWT so the field/validation contract stays theirs, but
|
|
1077
|
-
* replaces ``validate()`` — the token pair itself is minted by the view via
|
|
1078
|
-
* ``mint_tokens_for_request`` so the DPoP binding and remembered-session
|
|
1079
|
-
* lifetime match OTP, OAuth and TOTP exactly.
|
|
1080
|
-
*/
|
|
1081
|
-
export type PasswordLoginRequestWritable = {
|
|
1082
|
-
/**
|
|
1083
|
-
* Keep this browser signed in for 30 days
|
|
1084
|
-
*/
|
|
1085
|
-
remember_me?: boolean;
|
|
1086
|
-
email: string;
|
|
1087
|
-
password: string;
|
|
1088
1041
|
};
|
|
1089
1042
|
|
|
1090
1043
|
/**
|
|
@@ -1118,10 +1071,6 @@ export type PasswordLoginResponseWritable = {
|
|
|
1118
1071
|
* Whether user should be prompted to enable 2FA
|
|
1119
1072
|
*/
|
|
1120
1073
|
should_prompt_2fa?: boolean;
|
|
1121
|
-
/**
|
|
1122
|
-
* Whether this login should persist across browser restarts
|
|
1123
|
-
*/
|
|
1124
|
-
persistent_session?: boolean;
|
|
1125
1074
|
};
|
|
1126
1075
|
|
|
1127
1076
|
export type TokenRefreshWritable = {
|
|
@@ -1171,10 +1120,6 @@ export type VerifyResponseWritable = {
|
|
|
1171
1120
|
* User profile data
|
|
1172
1121
|
*/
|
|
1173
1122
|
user: TotpVerifyUserWritable;
|
|
1174
|
-
/**
|
|
1175
|
-
* Whether this login should persist across browser restarts
|
|
1176
|
-
*/
|
|
1177
|
-
persistent_session: boolean;
|
|
1178
1123
|
/**
|
|
1179
1124
|
* Number of remaining backup codes (if backup code was used)
|
|
1180
1125
|
*/
|
|
@@ -1566,7 +1511,7 @@ export type CfgAccountsProfileUpdateUpdateResponses = {
|
|
|
1566
1511
|
export type CfgAccountsProfileUpdateUpdateResponse = CfgAccountsProfileUpdateUpdateResponses[keyof CfgAccountsProfileUpdateUpdateResponses];
|
|
1567
1512
|
|
|
1568
1513
|
export type CfgAccountsTokenCreateData = {
|
|
1569
|
-
body:
|
|
1514
|
+
body: PasswordLoginRequest;
|
|
1570
1515
|
path?: never;
|
|
1571
1516
|
query?: never;
|
|
1572
1517
|
url: '/cfg/accounts/token/';
|
|
@@ -136,21 +136,19 @@ describe('AuthContext.login (password grant)', () => {
|
|
|
136
136
|
expect(tokens).toEqual({ access: 'access-1', refresh: 'refresh-1' });
|
|
137
137
|
});
|
|
138
138
|
|
|
139
|
-
it('sends email
|
|
139
|
+
it('sends email and password to the password endpoint', async () => {
|
|
140
140
|
respondWith({ requires_2fa: false, access: 'access-1', refresh: 'refresh-1', user: USER });
|
|
141
141
|
const { result } = await renderAuth();
|
|
142
142
|
|
|
143
143
|
await act(async () => {
|
|
144
144
|
await result.current.login('jane@example.com', 'correct horse', {
|
|
145
145
|
skipRedirect: true,
|
|
146
|
-
rememberMe: true,
|
|
147
146
|
});
|
|
148
147
|
});
|
|
149
148
|
|
|
150
149
|
expect(loginWithPassword).toHaveBeenCalledWith({
|
|
151
150
|
email: 'jane@example.com',
|
|
152
151
|
password: 'correct horse',
|
|
153
|
-
remember_me: true,
|
|
154
152
|
});
|
|
155
153
|
});
|
|
156
154
|
|
|
@@ -57,7 +57,7 @@ import type {
|
|
|
57
57
|
OtpVerifyRequest,
|
|
58
58
|
OtpRequestResponse,
|
|
59
59
|
OtpVerifyResponse,
|
|
60
|
-
|
|
60
|
+
PasswordLoginRequest,
|
|
61
61
|
PasswordLoginResponse,
|
|
62
62
|
} from '../../_api/generated/_cfg_accounts/types.gen';
|
|
63
63
|
|
|
@@ -79,7 +79,7 @@ export interface AccountsContextValue {
|
|
|
79
79
|
|
|
80
80
|
requestOTP: (data: OtpRequestRequest) => Promise<OtpRequestResponse>;
|
|
81
81
|
verifyOTP: (data: OtpVerifyRequest) => Promise<OtpVerifyResponse>;
|
|
82
|
-
loginWithPassword: (data:
|
|
82
|
+
loginWithPassword: (data: PasswordLoginRequest) => Promise<PasswordLoginResponse>;
|
|
83
83
|
logout: () => void;
|
|
84
84
|
}
|
|
85
85
|
|
|
@@ -207,11 +207,9 @@ export function AccountsProvider({ children }: AccountsProviderProps) {
|
|
|
207
207
|
|
|
208
208
|
if (result.access && result.refresh) {
|
|
209
209
|
// The ONE write path — atomic pair, notifies every session subscriber.
|
|
210
|
-
// Storage is always localStorage:
|
|
211
|
-
//
|
|
212
|
-
//
|
|
213
|
-
// to strand the tokens — the module reinitializes to localStorage on the
|
|
214
|
-
// next page load and would never look at sessionStorage again.
|
|
210
|
+
// Storage is always localStorage: session length is the token lifetime
|
|
211
|
+
// the server chose. A sessionStorage switch would strand the tokens — the
|
|
212
|
+
// module reinitializes to localStorage on the next page load.
|
|
215
213
|
auth.setSession({ access: result.access, refresh: result.refresh });
|
|
216
214
|
try {
|
|
217
215
|
await refreshProfile({ callerId, force: true });
|
|
@@ -228,7 +226,7 @@ export function AccountsProvider({ children }: AccountsProviderProps) {
|
|
|
228
226
|
}, [triggerOtpVerify, settleLoginEnvelope]);
|
|
229
227
|
|
|
230
228
|
const loginWithPassword = useCallback(async (
|
|
231
|
-
data:
|
|
229
|
+
data: PasswordLoginRequest,
|
|
232
230
|
): Promise<PasswordLoginResponse> => {
|
|
233
231
|
// Errors propagate: the SWR trigger throws APIError for 401/429 and the
|
|
234
232
|
// caller maps them. Nothing is written to the session on a failure.
|
|
@@ -288,7 +288,6 @@ const AuthProviderInternal: React.FC<AuthProviderProps> = ({ children, config })
|
|
|
288
288
|
sourceUrl?: string,
|
|
289
289
|
redirectUrl?: string,
|
|
290
290
|
skipRedirect?: boolean,
|
|
291
|
-
rememberMe = false,
|
|
292
291
|
): Promise<{
|
|
293
292
|
success: boolean;
|
|
294
293
|
message: string;
|
|
@@ -306,7 +305,6 @@ const AuthProviderInternal: React.FC<AuthProviderProps> = ({ children, config })
|
|
|
306
305
|
identifier,
|
|
307
306
|
otp: otpCode,
|
|
308
307
|
source_url: sourceUrl,
|
|
309
|
-
remember_me: rememberMe,
|
|
310
308
|
});
|
|
311
309
|
|
|
312
310
|
if (result.requires_2fa && result.session_id) {
|
|
@@ -379,7 +377,7 @@ const AuthProviderInternal: React.FC<AuthProviderProps> = ({ children, config })
|
|
|
379
377
|
password: string,
|
|
380
378
|
options?: PasswordLoginOptions,
|
|
381
379
|
): Promise<PasswordLoginResult> => {
|
|
382
|
-
const { redirectUrl, skipRedirect
|
|
380
|
+
const { redirectUrl, skipRedirect } = options || {};
|
|
383
381
|
|
|
384
382
|
try {
|
|
385
383
|
// The caller opting out of redirect commits to handling ALL navigation
|
|
@@ -389,7 +387,6 @@ const AuthProviderInternal: React.FC<AuthProviderProps> = ({ children, config })
|
|
|
389
387
|
const result = await accountsRef.current.loginWithPassword({
|
|
390
388
|
email,
|
|
391
389
|
password,
|
|
392
|
-
remember_me: rememberMe,
|
|
393
390
|
});
|
|
394
391
|
|
|
395
392
|
if (result.requires_2fa && result.session_id) {
|
|
@@ -55,7 +55,7 @@ export interface AuthContextType {
|
|
|
55
55
|
|
|
56
56
|
// OTP Methods - email only
|
|
57
57
|
requestOTP: (identifier: string, sourceUrl?: string, consent?: OTPRequestConsent) => Promise<OTPRequestResult>;
|
|
58
|
-
verifyOTP: (identifier: string, otpCode: string, sourceUrl?: string, redirectUrl?: string, skipRedirect?: boolean
|
|
58
|
+
verifyOTP: (identifier: string, otpCode: string, sourceUrl?: string, redirectUrl?: string, skipRedirect?: boolean) => Promise<{
|
|
59
59
|
success: boolean;
|
|
60
60
|
message: string;
|
|
61
61
|
user?: UserProfile;
|
|
@@ -55,7 +55,6 @@ export const useAuthForm = (options: UseAuthFormOptions): AuthFormReturn => {
|
|
|
55
55
|
password,
|
|
56
56
|
acceptedTerms,
|
|
57
57
|
marketingConsent,
|
|
58
|
-
rememberMe,
|
|
59
58
|
setIdentifier,
|
|
60
59
|
setOtp,
|
|
61
60
|
setStep,
|
|
@@ -176,7 +175,7 @@ export const useAuthForm = (options: UseAuthFormOptions): AuthFormReturn => {
|
|
|
176
175
|
|
|
177
176
|
try {
|
|
178
177
|
// Skip redirect - we'll show success screen first
|
|
179
|
-
const result = await verifyOTP(submitIdentifier, submitOtp, sourceUrl, redirectUrl, true
|
|
178
|
+
const result = await verifyOTP(submitIdentifier, submitOtp, sourceUrl, redirectUrl, true);
|
|
180
179
|
|
|
181
180
|
if (result.requires_2fa && result.session_id) {
|
|
182
181
|
authLogger.info('2FA required after OTP verification');
|
|
@@ -205,7 +204,7 @@ export const useAuthForm = (options: UseAuthFormOptions): AuthFormReturn => {
|
|
|
205
204
|
} finally {
|
|
206
205
|
setIsLoading(false);
|
|
207
206
|
}
|
|
208
|
-
}, [verifyOTP, saveIdentifierToStorage, setError, setIsLoading, clearError, onOTPSuccess, onError, sourceUrl, redirectUrl,
|
|
207
|
+
}, [verifyOTP, saveIdentifierToStorage, setError, setIsLoading, clearError, onOTPSuccess, onError, sourceUrl, redirectUrl, setStep]);
|
|
209
208
|
|
|
210
209
|
const handleOTPSubmit = useCallback(async (e: React.FormEvent) => {
|
|
211
210
|
e.preventDefault();
|
|
@@ -244,7 +243,6 @@ export const useAuthForm = (options: UseAuthFormOptions): AuthFormReturn => {
|
|
|
244
243
|
const result = await login(submitIdentifier, submitPassword_, {
|
|
245
244
|
redirectUrl,
|
|
246
245
|
skipRedirect: true,
|
|
247
|
-
rememberMe,
|
|
248
246
|
});
|
|
249
247
|
|
|
250
248
|
if (result.requires_2fa && result.session_id) {
|
|
@@ -283,7 +281,7 @@ export const useAuthForm = (options: UseAuthFormOptions): AuthFormReturn => {
|
|
|
283
281
|
}, [
|
|
284
282
|
login, validateIdentifier, saveIdentifierToStorage, setError, setIsLoading,
|
|
285
283
|
clearError, startRateLimitCountdown, onOTPSuccess, onError, redirectUrl,
|
|
286
|
-
|
|
284
|
+
setStep,
|
|
287
285
|
]);
|
|
288
286
|
|
|
289
287
|
const handlePasswordSubmit = useCallback(async (e: React.FormEvent) => {
|
|
@@ -53,8 +53,6 @@ export const useAuthFormState = (
|
|
|
53
53
|
// null until the marketing-consent feature (if enabled) resolves its
|
|
54
54
|
// jurisdiction-aware default — the layout owns that decision.
|
|
55
55
|
const [marketingConsent, setMarketingConsent] = useState<boolean | null>(null);
|
|
56
|
-
// Signed in for 30 days unless an app opts into showing the choice.
|
|
57
|
-
const [rememberMe, setRememberMe] = useState(true);
|
|
58
56
|
const [step, setStep] = useState<AuthStep>('identifier');
|
|
59
57
|
const [error, setError] = useState('');
|
|
60
58
|
const [webmail, setWebmail] = useState<WebmailLink | null>(null);
|
|
@@ -72,7 +70,6 @@ export const useAuthFormState = (
|
|
|
72
70
|
isLoading,
|
|
73
71
|
acceptedTerms,
|
|
74
72
|
marketingConsent,
|
|
75
|
-
rememberMe,
|
|
76
73
|
step,
|
|
77
74
|
error,
|
|
78
75
|
rateLimitSeconds: rateLimit.seconds,
|
|
@@ -87,7 +84,6 @@ export const useAuthFormState = (
|
|
|
87
84
|
setPassword,
|
|
88
85
|
setAcceptedTerms,
|
|
89
86
|
setMarketingConsent,
|
|
90
|
-
setRememberMe,
|
|
91
87
|
setError,
|
|
92
88
|
clearError,
|
|
93
89
|
setStep,
|
|
@@ -13,7 +13,6 @@ import { useCfgRouter } from './useCfgRouter';
|
|
|
13
13
|
|
|
14
14
|
const OAUTH_STATE_KEY = CFG_KEYS.oauthState.key;
|
|
15
15
|
const OAUTH_PROVIDER_KEY = CFG_KEYS.oauthProvider.key;
|
|
16
|
-
const OAUTH_REMEMBER_KEY = CFG_KEYS.oauthRememberMe.key;
|
|
17
16
|
|
|
18
17
|
/**
|
|
19
18
|
* The user payload as the OAuth endpoint declares it.
|
|
@@ -27,8 +26,6 @@ export type OAuthUser = NonNullable<OAuthTokenResponse['user']>;
|
|
|
27
26
|
|
|
28
27
|
export interface UseGithubAuthOptions {
|
|
29
28
|
sourceUrl?: string;
|
|
30
|
-
/** Keep the completed browser session for 30 days. */
|
|
31
|
-
rememberMe?: boolean;
|
|
32
29
|
/**
|
|
33
30
|
* The OAuth endpoint's OpenAPI schema types `user` as a free-form object, so
|
|
34
31
|
* this is what the server actually promises — not a `User`. Narrow it at the
|
|
@@ -70,7 +67,7 @@ export interface UseGithubAuthReturn {
|
|
|
70
67
|
* ```
|
|
71
68
|
*/
|
|
72
69
|
export const useGithubAuth = (options: UseGithubAuthOptions = {}): UseGithubAuthReturn => {
|
|
73
|
-
const { sourceUrl,
|
|
70
|
+
const { sourceUrl, onSuccess, onError, onRequires2FA, redirectUrl, skipRedirect = false } = options;
|
|
74
71
|
const router = useCfgRouter();
|
|
75
72
|
|
|
76
73
|
const [isLoading, setIsLoading] = useState(false);
|
|
@@ -114,7 +111,6 @@ export const useGithubAuth = (options: UseGithubAuthOptions = {}): UseGithubAuth
|
|
|
114
111
|
if (typeof window !== 'undefined') {
|
|
115
112
|
sessionStorage.setItem(OAUTH_STATE_KEY, response.state);
|
|
116
113
|
sessionStorage.setItem(OAUTH_PROVIDER_KEY, 'github');
|
|
117
|
-
sessionStorage.setItem(OAUTH_REMEMBER_KEY, String(rememberMe));
|
|
118
114
|
}
|
|
119
115
|
|
|
120
116
|
window.location.href = response.authorization_url;
|
|
@@ -133,7 +129,7 @@ export const useGithubAuth = (options: UseGithubAuthOptions = {}): UseGithubAuth
|
|
|
133
129
|
} finally {
|
|
134
130
|
setIsLoading(false);
|
|
135
131
|
}
|
|
136
|
-
}, [sourceUrl,
|
|
132
|
+
}, [sourceUrl, onError]);
|
|
137
133
|
|
|
138
134
|
/**
|
|
139
135
|
* Handle GitHub OAuth callback - exchanges code for JWT tokens.
|
|
@@ -149,22 +145,19 @@ export const useGithubAuth = (options: UseGithubAuthOptions = {}): UseGithubAuth
|
|
|
149
145
|
authLogger.info('Processing GitHub OAuth callback...');
|
|
150
146
|
|
|
151
147
|
// Verify state matches what we stored
|
|
152
|
-
let rememberMeForSession = false;
|
|
153
148
|
if (typeof window !== 'undefined') {
|
|
154
149
|
const storedState = sessionStorage.getItem(OAUTH_STATE_KEY);
|
|
155
150
|
if (storedState && storedState !== state) {
|
|
156
151
|
throw new Error('Invalid OAuth state - possible CSRF attack');
|
|
157
152
|
}
|
|
158
|
-
rememberMeForSession = sessionStorage.getItem(OAUTH_REMEMBER_KEY) === 'true';
|
|
159
153
|
// Clear stored state
|
|
160
154
|
sessionStorage.removeItem(OAUTH_STATE_KEY);
|
|
161
155
|
sessionStorage.removeItem(OAUTH_PROVIDER_KEY);
|
|
162
|
-
sessionStorage.removeItem(OAUTH_REMEMBER_KEY);
|
|
163
156
|
|
|
164
157
|
}
|
|
165
158
|
|
|
166
159
|
const result = await CfgAccountsOauth.cfgAccountsOauthGithubCallbackCreate({
|
|
167
|
-
body: { code, state
|
|
160
|
+
body: { code, state },
|
|
168
161
|
throwOnError: true,
|
|
169
162
|
});
|
|
170
163
|
const response = result.data;
|
|
@@ -191,8 +184,8 @@ export const useGithubAuth = (options: UseGithubAuthOptions = {}): UseGithubAuth
|
|
|
191
184
|
authLogger.info('GitHub OAuth successful, user:', response.user);
|
|
192
185
|
|
|
193
186
|
// The ONE write path — atomic pair + session notification. Storage is
|
|
194
|
-
// always localStorage; session length is the server's call
|
|
195
|
-
//
|
|
187
|
+
// always localStorage; session length is the server's call.
|
|
188
|
+
// See AccountsContext.verifyOTP.
|
|
196
189
|
auth.setSession({ access: response.access, refresh: response.refresh });
|
|
197
190
|
|
|
198
191
|
// Track successful OAuth
|
|
@@ -69,8 +69,8 @@ export const useTwoFactorVerify = (
|
|
|
69
69
|
// copy it replaces cannot drift from the server contract any more.
|
|
70
70
|
const handleSuccess = useCallback((response: VerifyResponse) => {
|
|
71
71
|
// Save tokens — the ONE write path (atomic pair + session notification).
|
|
72
|
-
// Storage is always localStorage; session length is the server's call
|
|
73
|
-
//
|
|
72
|
+
// Storage is always localStorage; session length is the server's call.
|
|
73
|
+
// See AccountsContext.verifyOTP.
|
|
74
74
|
auth.setSession({ access: response.access_token, refresh: response.refresh_token });
|
|
75
75
|
|
|
76
76
|
if (response.warning) {
|
package/src/auth/types/form.ts
CHANGED
|
@@ -52,8 +52,6 @@ export interface PasswordLoginOptions {
|
|
|
52
52
|
redirectUrl?: string;
|
|
53
53
|
/** Caller owns ALL navigation for this login, including the 2FA continuation. */
|
|
54
54
|
skipRedirect?: boolean;
|
|
55
|
-
/** Ask the server for a 30-day session instead of the default lifetime. */
|
|
56
|
-
rememberMe?: boolean;
|
|
57
55
|
}
|
|
58
56
|
|
|
59
57
|
/**
|
|
@@ -99,8 +97,6 @@ export interface AuthFormState {
|
|
|
99
97
|
* jurisdiction-aware default on mount.
|
|
100
98
|
*/
|
|
101
99
|
marketingConsent: boolean | null;
|
|
102
|
-
/** Keep this browser signed in for 30 days after successful verification. */
|
|
103
|
-
rememberMe: boolean;
|
|
104
100
|
/** Current form step */
|
|
105
101
|
step: AuthStep;
|
|
106
102
|
/** Error message */
|
|
@@ -129,7 +125,6 @@ export interface AuthFormStateHandlers {
|
|
|
129
125
|
setPassword: (password: string) => void;
|
|
130
126
|
setAcceptedTerms: (accepted: boolean) => void;
|
|
131
127
|
setMarketingConsent: (consent: boolean | null) => void;
|
|
132
|
-
setRememberMe: (rememberMe: boolean) => void;
|
|
133
128
|
setError: (error: string) => void;
|
|
134
129
|
clearError: () => void;
|
|
135
130
|
setStep: (step: AuthStep) => void;
|