@djangocfg/api 2.1.59 → 2.1.60

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/auth.d.cts CHANGED
@@ -421,6 +421,13 @@ interface UseAuthFormOptions {
421
421
  requireTermsAcceptance?: boolean;
422
422
  /** Path to auth page for auto-OTP detection. Default: '/auth' */
423
423
  authPath?: string;
424
+ /**
425
+ * Enable 2FA setup prompt after successful authentication.
426
+ * When true (default), users without 2FA will see a setup prompt after login.
427
+ * When false, users go directly to success without 2FA setup prompt.
428
+ * @default true
429
+ */
430
+ enable2FASetup?: boolean;
424
431
  }
425
432
  interface AuthLayoutConfig {
426
433
  /** Support page URL */
@@ -439,6 +446,14 @@ interface AuthLayoutConfig {
439
446
  logoUrl?: string;
440
447
  /** URL to redirect after successful auth (default: /dashboard) */
441
448
  redirectUrl?: string;
449
+ /**
450
+ * Enable 2FA setup prompt after successful authentication.
451
+ * When true (default), users without 2FA will see a setup prompt after login.
452
+ * When false, users go directly to success without 2FA setup prompt.
453
+ * Note: This only affects the setup prompt - existing 2FA verification still works.
454
+ * @default true
455
+ */
456
+ enable2FASetup?: boolean;
442
457
  }
443
458
  interface AuthFormContextType extends AuthFormReturn, AuthLayoutConfig {
444
459
  }
@@ -665,6 +680,49 @@ interface UseTwoFactorSetupReturn {
665
680
  */
666
681
  declare const useTwoFactorSetup: (options?: UseTwoFactorSetupOptions) => UseTwoFactorSetupReturn;
667
682
 
683
+ interface TwoFactorDevice {
684
+ id: string;
685
+ name: string;
686
+ createdAt: string;
687
+ lastUsedAt: string | null;
688
+ isPrimary: boolean;
689
+ }
690
+ interface UseTwoFactorStatusReturn {
691
+ /** Loading state */
692
+ isLoading: boolean;
693
+ /** Error message */
694
+ error: string | null;
695
+ /** Whether 2FA is enabled for user */
696
+ has2FAEnabled: boolean | null;
697
+ /** List of TOTP devices */
698
+ devices: TwoFactorDevice[];
699
+ /** Fetch 2FA status */
700
+ fetchStatus: () => Promise<void>;
701
+ /** Disable 2FA (requires TOTP code) */
702
+ disable2FA: (code: string) => Promise<boolean>;
703
+ /** Clear error */
704
+ clearError: () => void;
705
+ }
706
+ /**
707
+ * Hook for checking and managing 2FA status.
708
+ *
709
+ * @example
710
+ * ```tsx
711
+ * const { has2FAEnabled, devices, fetchStatus, disable2FA, isLoading } = useTwoFactorStatus();
712
+ *
713
+ * useEffect(() => {
714
+ * fetchStatus();
715
+ * }, [fetchStatus]);
716
+ *
717
+ * if (has2FAEnabled) {
718
+ * // Show disable button
719
+ * } else {
720
+ * // Show enable button
721
+ * }
722
+ * ```
723
+ */
724
+ declare const useTwoFactorStatus: () => UseTwoFactorStatusReturn;
725
+
668
726
  interface AuthRedirectOptions {
669
727
  fallbackUrl?: string;
670
728
  clearOnUse?: boolean;
@@ -830,4 +888,4 @@ declare const Analytics: {
830
888
  setUser(userId: string): void;
831
889
  };
832
890
 
833
- export { type AccountsContextValue, AccountsProvider, Analytics, AnalyticsCategory, type AnalyticsCategoryType, AnalyticsEvent, type AnalyticsEventType, type AuthChannel, type AuthConfig, type AuthContextType, type AuthFormAutoSubmit, type AuthFormContextType, type AuthFormReturn, type AuthFormState, type AuthFormStateHandlers, type AuthFormSubmitHandlers, type AuthFormValidation, type AuthHelpProps, type AuthLayoutConfig, type AuthLayoutProps, AuthProvider, type AuthProviderProps, type AuthStep, type PatchedUserProfileUpdateRequest, PatchedUserProfileUpdateRequestSchema, type ProfileCacheOptions, type TwoFactorSetupData, type UseAuthFormOptions, type UseAuthFormStateReturn, type UseAutoAuthOptions, type UseGithubAuthOptions, type UseGithubAuthReturn, type UseTwoFactorOptions, type UseTwoFactorReturn, type UseTwoFactorSetupOptions, type UseTwoFactorSetupReturn, type UserProfile, authLogger, clearProfileCache, decodeBase64, detectChannelFromIdentifier, encodeBase64, formatAuthError, getCacheMetadata, getCachedProfile, hasValidCache, logger, setCachedProfile, useAccountsContext, useAuth, useAuthForm, useAuthFormState, useAuthGuard, useAuthRedirectManager, useAuthValidation, useAutoAuth, useBase64, useGithubAuth, useLocalStorage, useSessionStorage, useTwoFactor, useTwoFactorSetup, validateEmail, validateIdentifier };
891
+ export { type AccountsContextValue, AccountsProvider, Analytics, AnalyticsCategory, type AnalyticsCategoryType, AnalyticsEvent, type AnalyticsEventType, type AuthChannel, type AuthConfig, type AuthContextType, type AuthFormAutoSubmit, type AuthFormContextType, type AuthFormReturn, type AuthFormState, type AuthFormStateHandlers, type AuthFormSubmitHandlers, type AuthFormValidation, type AuthHelpProps, type AuthLayoutConfig, type AuthLayoutProps, AuthProvider, type AuthProviderProps, type AuthStep, type PatchedUserProfileUpdateRequest, PatchedUserProfileUpdateRequestSchema, type ProfileCacheOptions, type TwoFactorDevice, type TwoFactorSetupData, type UseAuthFormOptions, type UseAuthFormStateReturn, type UseAutoAuthOptions, type UseGithubAuthOptions, type UseGithubAuthReturn, type UseTwoFactorOptions, type UseTwoFactorReturn, type UseTwoFactorSetupOptions, type UseTwoFactorSetupReturn, type UseTwoFactorStatusReturn, type UserProfile, authLogger, clearProfileCache, decodeBase64, detectChannelFromIdentifier, encodeBase64, formatAuthError, getCacheMetadata, getCachedProfile, hasValidCache, logger, setCachedProfile, useAccountsContext, useAuth, useAuthForm, useAuthFormState, useAuthGuard, useAuthRedirectManager, useAuthValidation, useAutoAuth, useBase64, useGithubAuth, useLocalStorage, useSessionStorage, useTwoFactor, useTwoFactorSetup, useTwoFactorStatus, validateEmail, validateIdentifier };
package/dist/auth.d.ts CHANGED
@@ -421,6 +421,13 @@ interface UseAuthFormOptions {
421
421
  requireTermsAcceptance?: boolean;
422
422
  /** Path to auth page for auto-OTP detection. Default: '/auth' */
423
423
  authPath?: string;
424
+ /**
425
+ * Enable 2FA setup prompt after successful authentication.
426
+ * When true (default), users without 2FA will see a setup prompt after login.
427
+ * When false, users go directly to success without 2FA setup prompt.
428
+ * @default true
429
+ */
430
+ enable2FASetup?: boolean;
424
431
  }
425
432
  interface AuthLayoutConfig {
426
433
  /** Support page URL */
@@ -439,6 +446,14 @@ interface AuthLayoutConfig {
439
446
  logoUrl?: string;
440
447
  /** URL to redirect after successful auth (default: /dashboard) */
441
448
  redirectUrl?: string;
449
+ /**
450
+ * Enable 2FA setup prompt after successful authentication.
451
+ * When true (default), users without 2FA will see a setup prompt after login.
452
+ * When false, users go directly to success without 2FA setup prompt.
453
+ * Note: This only affects the setup prompt - existing 2FA verification still works.
454
+ * @default true
455
+ */
456
+ enable2FASetup?: boolean;
442
457
  }
443
458
  interface AuthFormContextType extends AuthFormReturn, AuthLayoutConfig {
444
459
  }
@@ -665,6 +680,49 @@ interface UseTwoFactorSetupReturn {
665
680
  */
666
681
  declare const useTwoFactorSetup: (options?: UseTwoFactorSetupOptions) => UseTwoFactorSetupReturn;
667
682
 
683
+ interface TwoFactorDevice {
684
+ id: string;
685
+ name: string;
686
+ createdAt: string;
687
+ lastUsedAt: string | null;
688
+ isPrimary: boolean;
689
+ }
690
+ interface UseTwoFactorStatusReturn {
691
+ /** Loading state */
692
+ isLoading: boolean;
693
+ /** Error message */
694
+ error: string | null;
695
+ /** Whether 2FA is enabled for user */
696
+ has2FAEnabled: boolean | null;
697
+ /** List of TOTP devices */
698
+ devices: TwoFactorDevice[];
699
+ /** Fetch 2FA status */
700
+ fetchStatus: () => Promise<void>;
701
+ /** Disable 2FA (requires TOTP code) */
702
+ disable2FA: (code: string) => Promise<boolean>;
703
+ /** Clear error */
704
+ clearError: () => void;
705
+ }
706
+ /**
707
+ * Hook for checking and managing 2FA status.
708
+ *
709
+ * @example
710
+ * ```tsx
711
+ * const { has2FAEnabled, devices, fetchStatus, disable2FA, isLoading } = useTwoFactorStatus();
712
+ *
713
+ * useEffect(() => {
714
+ * fetchStatus();
715
+ * }, [fetchStatus]);
716
+ *
717
+ * if (has2FAEnabled) {
718
+ * // Show disable button
719
+ * } else {
720
+ * // Show enable button
721
+ * }
722
+ * ```
723
+ */
724
+ declare const useTwoFactorStatus: () => UseTwoFactorStatusReturn;
725
+
668
726
  interface AuthRedirectOptions {
669
727
  fallbackUrl?: string;
670
728
  clearOnUse?: boolean;
@@ -830,4 +888,4 @@ declare const Analytics: {
830
888
  setUser(userId: string): void;
831
889
  };
832
890
 
833
- export { type AccountsContextValue, AccountsProvider, Analytics, AnalyticsCategory, type AnalyticsCategoryType, AnalyticsEvent, type AnalyticsEventType, type AuthChannel, type AuthConfig, type AuthContextType, type AuthFormAutoSubmit, type AuthFormContextType, type AuthFormReturn, type AuthFormState, type AuthFormStateHandlers, type AuthFormSubmitHandlers, type AuthFormValidation, type AuthHelpProps, type AuthLayoutConfig, type AuthLayoutProps, AuthProvider, type AuthProviderProps, type AuthStep, type PatchedUserProfileUpdateRequest, PatchedUserProfileUpdateRequestSchema, type ProfileCacheOptions, type TwoFactorSetupData, type UseAuthFormOptions, type UseAuthFormStateReturn, type UseAutoAuthOptions, type UseGithubAuthOptions, type UseGithubAuthReturn, type UseTwoFactorOptions, type UseTwoFactorReturn, type UseTwoFactorSetupOptions, type UseTwoFactorSetupReturn, type UserProfile, authLogger, clearProfileCache, decodeBase64, detectChannelFromIdentifier, encodeBase64, formatAuthError, getCacheMetadata, getCachedProfile, hasValidCache, logger, setCachedProfile, useAccountsContext, useAuth, useAuthForm, useAuthFormState, useAuthGuard, useAuthRedirectManager, useAuthValidation, useAutoAuth, useBase64, useGithubAuth, useLocalStorage, useSessionStorage, useTwoFactor, useTwoFactorSetup, validateEmail, validateIdentifier };
891
+ export { type AccountsContextValue, AccountsProvider, Analytics, AnalyticsCategory, type AnalyticsCategoryType, AnalyticsEvent, type AnalyticsEventType, type AuthChannel, type AuthConfig, type AuthContextType, type AuthFormAutoSubmit, type AuthFormContextType, type AuthFormReturn, type AuthFormState, type AuthFormStateHandlers, type AuthFormSubmitHandlers, type AuthFormValidation, type AuthHelpProps, type AuthLayoutConfig, type AuthLayoutProps, AuthProvider, type AuthProviderProps, type AuthStep, type PatchedUserProfileUpdateRequest, PatchedUserProfileUpdateRequestSchema, type ProfileCacheOptions, type TwoFactorDevice, type TwoFactorSetupData, type UseAuthFormOptions, type UseAuthFormStateReturn, type UseAutoAuthOptions, type UseGithubAuthOptions, type UseGithubAuthReturn, type UseTwoFactorOptions, type UseTwoFactorReturn, type UseTwoFactorSetupOptions, type UseTwoFactorSetupReturn, type UseTwoFactorStatusReturn, type UserProfile, authLogger, clearProfileCache, decodeBase64, detectChannelFromIdentifier, encodeBase64, formatAuthError, getCacheMetadata, getCachedProfile, hasValidCache, logger, setCachedProfile, useAccountsContext, useAuth, useAuthForm, useAuthFormState, useAuthGuard, useAuthRedirectManager, useAuthValidation, useAutoAuth, useBase64, useGithubAuth, useLocalStorage, useSessionStorage, useTwoFactor, useTwoFactorSetup, useTwoFactorStatus, validateEmail, validateIdentifier };
package/dist/auth.mjs CHANGED
@@ -5840,7 +5840,8 @@ var useAuthForm = /* @__PURE__ */ __name((options) => {
5840
5840
  sourceUrl,
5841
5841
  redirectUrl,
5842
5842
  requireTermsAcceptance = false,
5843
- authPath = "/auth"
5843
+ authPath = "/auth",
5844
+ enable2FASetup = true
5844
5845
  } = options;
5845
5846
  const formState = useAuthFormState();
5846
5847
  const validation = useAuthValidation();
@@ -5995,14 +5996,18 @@ var useAuthForm = /* @__PURE__ */ __name((options) => {
5995
5996
  }
5996
5997
  if (result.success) {
5997
5998
  saveIdentifierToStorage(submitIdentifier, submitChannel);
5998
- if (result.should_prompt_2fa) {
5999
+ if (result.should_prompt_2fa && enable2FASetup) {
5999
6000
  authLogger.info("OTP verification successful, prompting 2FA setup");
6000
6001
  setShouldPrompt2FA(true);
6001
6002
  setStep("2fa-setup");
6002
6003
  onOTPSuccess?.();
6003
6004
  return true;
6004
6005
  }
6005
- authLogger.info("OTP verification successful, showing success screen");
6006
+ if (result.should_prompt_2fa && !enable2FASetup) {
6007
+ authLogger.info("OTP verification successful, skipping 2FA setup prompt (disabled)");
6008
+ } else {
6009
+ authLogger.info("OTP verification successful, showing success screen");
6010
+ }
6006
6011
  setStep("success");
6007
6012
  onOTPSuccess?.();
6008
6013
  return true;
@@ -6019,7 +6024,7 @@ var useAuthForm = /* @__PURE__ */ __name((options) => {
6019
6024
  } finally {
6020
6025
  setIsLoading(false);
6021
6026
  }
6022
- }, [verifyOTP, saveIdentifierToStorage, setError, setIsLoading, clearError, onOTPSuccess, onError, sourceUrl, redirectUrl, setTwoFactorSessionId, setShouldPrompt2FA, setStep]);
6027
+ }, [verifyOTP, saveIdentifierToStorage, setError, setIsLoading, clearError, onOTPSuccess, onError, sourceUrl, redirectUrl, setTwoFactorSessionId, setShouldPrompt2FA, setStep, enable2FASetup]);
6023
6028
  const handleOTPSubmit = useCallback6(async (e) => {
6024
6029
  e.preventDefault();
6025
6030
  await submitOTP(identifier, otp, channel);
@@ -6345,14 +6350,83 @@ var useTwoFactorSetup = /* @__PURE__ */ __name((options = {}) => {
6345
6350
  };
6346
6351
  }, "useTwoFactorSetup");
6347
6352
 
6353
+ // src/auth/hooks/useTwoFactorStatus.ts
6354
+ import { useCallback as useCallback9, useState as useState8 } from "react";
6355
+ var useTwoFactorStatus = /* @__PURE__ */ __name(() => {
6356
+ const [isLoading, setIsLoading] = useState8(false);
6357
+ const [error, setError] = useState8(null);
6358
+ const [has2FAEnabled, setHas2FAEnabled] = useState8(null);
6359
+ const [devices, setDevices] = useState8([]);
6360
+ const clearError = useCallback9(() => {
6361
+ setError(null);
6362
+ }, []);
6363
+ const fetchStatus = useCallback9(async () => {
6364
+ setIsLoading(true);
6365
+ setError(null);
6366
+ try {
6367
+ authLogger.info("Fetching 2FA status...");
6368
+ const response = await apiTotp.totp_management.totpDevicesList();
6369
+ const mappedDevices = (response.results || []).map((device) => ({
6370
+ id: device.id,
6371
+ name: device.name,
6372
+ createdAt: device.created_at,
6373
+ lastUsedAt: device.last_used_at ?? null,
6374
+ isPrimary: device.is_primary
6375
+ }));
6376
+ setDevices(mappedDevices);
6377
+ const enabled = mappedDevices.length > 0;
6378
+ setHas2FAEnabled(enabled);
6379
+ authLogger.info("2FA status:", enabled ? "enabled" : "disabled");
6380
+ } catch (err) {
6381
+ const errorMessage = err instanceof Error ? err.message : "Failed to fetch 2FA status";
6382
+ authLogger.error("Failed to fetch 2FA status:", err);
6383
+ setError(errorMessage);
6384
+ } finally {
6385
+ setIsLoading(false);
6386
+ }
6387
+ }, []);
6388
+ const disable2FA = useCallback9(async (code) => {
6389
+ if (!code || code.length !== 6) {
6390
+ setError("Please enter a 6-digit code");
6391
+ return false;
6392
+ }
6393
+ setIsLoading(true);
6394
+ setError(null);
6395
+ try {
6396
+ authLogger.info("Disabling 2FA...");
6397
+ await apiTotp.totp_management.totpDisableCreate({ code });
6398
+ setHas2FAEnabled(false);
6399
+ setDevices([]);
6400
+ authLogger.info("2FA disabled successfully");
6401
+ return true;
6402
+ } catch (err) {
6403
+ const errorMessage = err instanceof Error ? err.message : "Invalid verification code";
6404
+ authLogger.error("Failed to disable 2FA:", err);
6405
+ setError(errorMessage);
6406
+ return false;
6407
+ } finally {
6408
+ setIsLoading(false);
6409
+ }
6410
+ }, []);
6411
+ return {
6412
+ isLoading,
6413
+ error,
6414
+ has2FAEnabled,
6415
+ devices,
6416
+ fetchStatus,
6417
+ disable2FA,
6418
+ clearError
6419
+ };
6420
+ }, "useTwoFactorStatus");
6421
+
6348
6422
  // src/auth/hooks/useAuthGuard.ts
6349
- import { useEffect as useEffect5, useState as useState8 } from "react";
6423
+ import { useEffect as useEffect5, useState as useState9 } from "react";
6350
6424
  import { useCfgRouter as useCfgRouter5 } from "@djangocfg/ui-nextjs/hooks";
6351
6425
  var useAuthGuard = /* @__PURE__ */ __name((options = {}) => {
6352
6426
  const { redirectTo = "/auth", requireAuth = true, saveRedirectUrl: shouldSaveUrl = true } = options;
6353
6427
  const { isAuthenticated, isLoading, saveRedirectUrl } = useAuth();
6354
6428
  const router = useCfgRouter5();
6355
- const [isRedirecting, setIsRedirecting] = useState8(false);
6429
+ const [isRedirecting, setIsRedirecting] = useState9(false);
6356
6430
  useEffect5(() => {
6357
6431
  if (!isLoading && requireAuth && !isAuthenticated && !isRedirecting) {
6358
6432
  if (shouldSaveUrl && typeof window !== "undefined") {
@@ -6367,9 +6441,9 @@ var useAuthGuard = /* @__PURE__ */ __name((options = {}) => {
6367
6441
  }, "useAuthGuard");
6368
6442
 
6369
6443
  // src/auth/hooks/useLocalStorage.ts
6370
- import { useState as useState9 } from "react";
6444
+ import { useState as useState10 } from "react";
6371
6445
  function useLocalStorage2(key, initialValue) {
6372
- const [storedValue, setStoredValue] = useState9(() => {
6446
+ const [storedValue, setStoredValue] = useState10(() => {
6373
6447
  if (typeof window === "undefined") {
6374
6448
  return initialValue;
6375
6449
  }
@@ -6580,6 +6654,7 @@ export {
6580
6654
  useSessionStorage,
6581
6655
  useTwoFactor,
6582
6656
  useTwoFactorSetup,
6657
+ useTwoFactorStatus,
6583
6658
  validateEmail,
6584
6659
  validateIdentifier
6585
6660
  };