@ollaid/native-sso 1.0.8 → 2.1.2

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/index.d.ts CHANGED
@@ -31,12 +31,14 @@ export { useNativeAuth } from './hooks/useNativeAuth';
31
31
  export type { UseNativeAuthOptions } from './hooks/useNativeAuth';
32
32
  export { useTokenHealthCheck } from './hooks/useTokenHealthCheck';
33
33
  export type { UseTokenHealthCheckOptions } from './hooks/useTokenHealthCheck';
34
+ export { useLogout } from './hooks/useLogout';
35
+ export type { UseLogoutOptions, UseLogoutReturn } from './hooks/useLogout';
34
36
  export { useMobilePassword } from './hooks/useMobilePassword';
35
37
  export { useMobileRegistration } from './hooks/useMobileRegistration';
36
38
  export { nativeAuthService } from './services/nativeAuth';
37
39
  export { mobilePasswordService } from './services/mobilePassword';
38
40
  export { iamAccountService } from './services/iamAccount';
39
- export { setNativeAuthConfig, getNativeAuthConfig, ApiError, getAuthToken, getAuthUser, getAccountType, clearAuthToken } from './services/api';
41
+ export { setNativeAuthConfig, getNativeAuthConfig, ApiError, getAuthToken, getAuthUser, getAccountType, clearAuthToken, logout } from './services/api';
40
42
  export type { NativeAuthConfig, ApiErrorType } from './services/api';
41
43
  export type { NativeAuthType, NativeAuthStatus, AccountType, RegistrationType, NativeCredentials, NativeEncryptRequest, NativeEncryptResponse, NativeConfigResponse, NativeInitResponse, NativeValidateResponse, NativeGrantAccessResponse, NativeResendOtpResponse, NativeExchangeResponse, NativeUser, NativeAuthState, UserInfos, LinkPhoneRequest, LinkPhoneResponse, LinkEmailRequest, LinkEmailResponse, RefreshUserInfoSingleRequest, RefreshUserInfoSingleResponse, RefreshUserInfoBulkRequest, RefreshUserInfoBulkResponse, UpdateAvatarRequest, UpdateAvatarResponse, ResetAvatarRequest, ResetAvatarResponse, CheckTokenResponse, } from './types/native';
42
44
  export type { MobilePasswordState, MobilePasswordStatus, } from './types/mobile';
package/dist/index.js CHANGED
@@ -494,7 +494,8 @@ const STORAGE = {
494
494
  TOKEN: "token",
495
495
  USER: "user",
496
496
  ACCOUNT_TYPE: "account_type",
497
- ALIAS_REFERENCE: "alias_reference"
497
+ ALIAS_REFERENCE: "alias_reference",
498
+ APP_ACCESS_TOKEN_REF: "app_access_token_ref"
498
499
  };
499
500
  const setAuthToken = (token) => {
500
501
  if (typeof localStorage !== "undefined") {
@@ -513,8 +514,14 @@ const clearAuthToken = () => {
513
514
  localStorage.removeItem(STORAGE.USER);
514
515
  localStorage.removeItem(STORAGE.ACCOUNT_TYPE);
515
516
  localStorage.removeItem(STORAGE.ALIAS_REFERENCE);
517
+ localStorage.removeItem(STORAGE.APP_ACCESS_TOKEN_REF);
516
518
  }
517
519
  };
520
+ const logout = async () => {
521
+ const { nativeAuthService: nativeAuthService2 } = await Promise.resolve().then(() => nativeAuth);
522
+ const token = getAuthToken();
523
+ return nativeAuthService2.logout(token || void 0);
524
+ };
518
525
  const setAuthUser = (user) => {
519
526
  if (typeof localStorage !== "undefined") {
520
527
  localStorage.setItem(STORAGE.USER, JSON.stringify(user));
@@ -808,7 +815,7 @@ const nativeAuthService = {
808
815
  );
809
816
  },
810
817
  async exchange(callbackToken) {
811
- var _a;
818
+ var _a, _b;
812
819
  const config2 = getNativeAuthConfig();
813
820
  if (!config2.saasApiUrl) {
814
821
  throw new ApiError("saasApiUrl non configurée", "unknown");
@@ -830,9 +837,16 @@ const nativeAuthService = {
830
837
  if (response.user) {
831
838
  setAuthUser(response.user);
832
839
  }
840
+ if (response.app_access_token_ref && typeof localStorage !== "undefined") {
841
+ localStorage.setItem(STORAGE.APP_ACCESS_TOKEN_REF, response.app_access_token_ref);
842
+ }
843
+ const aliasRef = ((_a = response.user) == null ? void 0 : _a.alias_reference) || response.alias_reference;
844
+ if (aliasRef && typeof localStorage !== "undefined") {
845
+ localStorage.setItem(STORAGE.ALIAS_REFERENCE, aliasRef);
846
+ }
833
847
  }
834
848
  if (isDebugMode()) {
835
- console.log("✅ [SaaS] Session établie:", { user: (_a = response.user) == null ? void 0 : _a.name });
849
+ console.log("✅ [SaaS] Session établie:", { user: (_b = response.user) == null ? void 0 : _b.name });
836
850
  }
837
851
  return response;
838
852
  },
@@ -853,7 +867,13 @@ const nativeAuthService = {
853
867
  },
854
868
  1e4
855
869
  );
856
- return { valid: response.valid !== false, user_infos: response.user_infos };
870
+ if (response.status === "connected" && response.user) {
871
+ return { valid: true, user: response.user };
872
+ }
873
+ if (response.success !== false) {
874
+ return { valid: true, user: response.user };
875
+ }
876
+ return { valid: false };
857
877
  } catch (err) {
858
878
  if (err instanceof ApiError && err.statusCode === 401) {
859
879
  return { valid: false };
@@ -863,28 +883,53 @@ const nativeAuthService = {
863
883
  },
864
884
  async logout(token) {
865
885
  const config2 = getNativeAuthConfig();
866
- if (!config2.saasApiUrl) {
867
- throw new ApiError("saasApiUrl non configurée", "unknown");
886
+ const iamToken = typeof localStorage !== "undefined" ? localStorage.getItem(STORAGE.AUTH_TOKEN) || localStorage.getItem(STORAGE.TOKEN) : null;
887
+ const appAccessTokenRef = typeof localStorage !== "undefined" ? localStorage.getItem(STORAGE.APP_ACCESS_TOKEN_REF) : null;
888
+ const promises = [];
889
+ if (config2.saasApiUrl && token) {
890
+ promises.push(
891
+ fetchWithTimeout(
892
+ `${config2.saasApiUrl}/native/logout`,
893
+ {
894
+ method: "POST",
895
+ headers: getHeaders(token, true)
896
+ },
897
+ config2.timeout || 3e4
898
+ ).catch((err) => {
899
+ if (isDebugMode()) {
900
+ console.warn("⚠️ [SaaS] Échec logout (non-bloquant):", err instanceof Error ? err.message : err);
901
+ }
902
+ })
903
+ );
868
904
  }
869
- try {
870
- const response = await fetchWithTimeout(
871
- `${config2.saasApiUrl}/native/logout`,
872
- {
873
- method: "POST",
874
- headers: getHeaders(token, true)
875
- },
876
- config2.timeout || 3e4
905
+ if (config2.iamApiUrl && (iamToken || appAccessTokenRef)) {
906
+ const payload = {};
907
+ if (iamToken) payload.sanctum_token = iamToken;
908
+ if (appAccessTokenRef) payload.app_access_token_ref = appAccessTokenRef;
909
+ promises.push(
910
+ fetchWithTimeout(
911
+ `${config2.iamApiUrl}/iam/disconnect`,
912
+ {
913
+ method: "POST",
914
+ headers: { "Content-Type": "application/json", "Accept": "application/json" },
915
+ body: JSON.stringify(payload)
916
+ },
917
+ 5e3
918
+ ).catch((err) => {
919
+ if (isDebugMode()) {
920
+ console.warn("⚠️ [IAM] Échec disconnect (non-bloquant):", err instanceof Error ? err.message : err);
921
+ }
922
+ })
877
923
  );
878
- clearAuthToken();
879
- credentials = null;
880
- credentialsLoadedAt = 0;
881
- return response;
882
- } catch {
883
- clearAuthToken();
884
- credentials = null;
885
- credentialsLoadedAt = 0;
886
- return { success: true };
887
924
  }
925
+ await Promise.allSettled(promises);
926
+ if (isDebugMode()) {
927
+ console.log("✅ [Logout] Double revocation terminée — nettoyage local");
928
+ }
929
+ clearAuthToken();
930
+ credentials = null;
931
+ credentialsLoadedAt = 0;
932
+ return { success: true };
888
933
  },
889
934
  clearCredentials() {
890
935
  credentials = null;
@@ -945,6 +990,10 @@ const nativeAuthService = {
945
990
  return this.init(native_token);
946
991
  }
947
992
  };
993
+ const nativeAuth = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
994
+ __proto__: null,
995
+ nativeAuthService
996
+ }, Symbol.toStringTag, { value: "Module" }));
948
997
  function getIAMHeaders() {
949
998
  const creds = nativeAuthService.getCredentials();
950
999
  if (!creds) {
@@ -1522,8 +1571,8 @@ function PasswordRecoveryModal({ open, onOpenChange, onSuccess, saasApiUrl, iamA
1522
1571
  ] })
1523
1572
  ] }) });
1524
1573
  }
1525
- const FIRST_CHECK_DELAY = 2 * 60 * 1e3;
1526
- const INTERVAL_DELAY = 5 * 60 * 1e3;
1574
+ const FIRST_CHECK_DELAY = 60 * 1e3;
1575
+ const INTERVAL_DELAY = 2 * 60 * 1e3;
1527
1576
  async function checkTokenValidity(saasApiUrl, token, debug) {
1528
1577
  if (typeof navigator !== "undefined" && !navigator.onLine) {
1529
1578
  if (debug) console.log("🔄 [HealthCheck] Offline — skip");
@@ -1543,7 +1592,7 @@ async function checkTokenValidity(saasApiUrl, token, debug) {
1543
1592
  });
1544
1593
  clearTimeout(timeoutId);
1545
1594
  if (response.status === 401) {
1546
- if (debug) console.log("🔄 [HealthCheck] Token invalide (401)");
1595
+ if (debug) console.log("🔄 [HealthCheck] Token invalide (401) — déconnexion");
1547
1596
  return { valid: false };
1548
1597
  }
1549
1598
  if (!response.ok) {
@@ -1551,11 +1600,15 @@ async function checkTokenValidity(saasApiUrl, token, debug) {
1551
1600
  throw new Error(`server_error_${response.status}`);
1552
1601
  }
1553
1602
  const data = await response.json();
1554
- if (debug) console.log("🔄 [HealthCheck] Token valide ✅");
1555
- return {
1556
- valid: data.valid !== false,
1557
- user_infos: data.user_infos
1558
- };
1603
+ if (data.status === "connected" && data.user) {
1604
+ if (debug) console.log("🔄 [HealthCheck] Token valide ✅ — user_infos mis à jour");
1605
+ return { valid: true, user: data.user };
1606
+ }
1607
+ if (data.success !== false) {
1608
+ if (debug) console.log("🔄 [HealthCheck] Token valide ✅");
1609
+ return { valid: true, user: data.user };
1610
+ }
1611
+ return { valid: false };
1559
1612
  } catch (error) {
1560
1613
  clearTimeout(timeoutId);
1561
1614
  if (error instanceof Error && error.message === "offline") {
@@ -1568,8 +1621,34 @@ async function checkTokenValidity(saasApiUrl, token, debug) {
1568
1621
  throw error;
1569
1622
  }
1570
1623
  }
1624
+ function revokeOnIam(iamApiUrl, sanctumToken, debug) {
1625
+ try {
1626
+ const controller = new AbortController();
1627
+ setTimeout(() => controller.abort(), 5e3);
1628
+ const appAccessTokenRef = typeof localStorage !== "undefined" ? localStorage.getItem(STORAGE.APP_ACCESS_TOKEN_REF) : null;
1629
+ const payload = { sanctum_token: sanctumToken };
1630
+ if (appAccessTokenRef) {
1631
+ payload.app_access_token_ref = appAccessTokenRef;
1632
+ }
1633
+ if (debug) {
1634
+ console.log("🔄 [HealthCheck] Revocation IAM:", { hasRef: !!appAccessTokenRef });
1635
+ }
1636
+ fetch(`${iamApiUrl}/iam/disconnect`, {
1637
+ method: "POST",
1638
+ headers: {
1639
+ "Content-Type": "application/json",
1640
+ "Accept": "application/json"
1641
+ },
1642
+ body: JSON.stringify(payload),
1643
+ signal: controller.signal
1644
+ }).catch(() => {
1645
+ if (debug) console.log("🔄 [HealthCheck] Échec revocation IAM (non-bloquant)");
1646
+ });
1647
+ } catch {
1648
+ }
1649
+ }
1571
1650
  function useTokenHealthCheck(options) {
1572
- const { enabled, saasApiUrl, onTokenInvalid, onUserUpdated, debug = false } = options;
1651
+ const { enabled, saasApiUrl, iamApiUrl, onTokenInvalid, onUserUpdated, debug = false } = options;
1573
1652
  const timerRef = useRef(null);
1574
1653
  const intervalRef = useRef(null);
1575
1654
  const enabledRef = useRef(enabled);
@@ -1586,15 +1665,19 @@ function useTokenHealthCheck(options) {
1586
1665
  try {
1587
1666
  const result = await checkTokenValidity(saasApiUrl, token, debug);
1588
1667
  if (!result.valid) {
1668
+ if (iamApiUrl) {
1669
+ if (debug) console.log("🔄 [HealthCheck] Revocation IAM avec sanctum_token...");
1670
+ revokeOnIam(iamApiUrl, token, debug);
1671
+ }
1589
1672
  callbacksRef.current.onTokenInvalid();
1590
1673
  return;
1591
1674
  }
1592
- if (result.user_infos && callbacksRef.current.onUserUpdated) {
1593
- callbacksRef.current.onUserUpdated(result.user_infos);
1675
+ if (result.user && callbacksRef.current.onUserUpdated) {
1676
+ callbacksRef.current.onUserUpdated(result.user);
1594
1677
  }
1595
1678
  } catch {
1596
1679
  }
1597
- }, [saasApiUrl, debug]);
1680
+ }, [saasApiUrl, iamApiUrl, debug]);
1598
1681
  useEffect(() => {
1599
1682
  if (timerRef.current) {
1600
1683
  clearTimeout(timerRef.current);
@@ -1605,7 +1688,7 @@ function useTokenHealthCheck(options) {
1605
1688
  intervalRef.current = null;
1606
1689
  }
1607
1690
  if (!enabled || !saasApiUrl) return;
1608
- if (debug) console.log("🔄 [HealthCheck] Activé — premier check dans 2 min");
1691
+ if (debug) console.log("🔄 [HealthCheck] Activé — premier check dans 60s, puis toutes les 2 min");
1609
1692
  timerRef.current = setTimeout(() => {
1610
1693
  performCheck();
1611
1694
  intervalRef.current = setInterval(performCheck, INTERVAL_DELAY);
@@ -1632,6 +1715,9 @@ function saveSession(exchangeResult, accountType) {
1632
1715
  if (aliasRef) {
1633
1716
  localStorage.setItem(STORAGE.ALIAS_REFERENCE, aliasRef);
1634
1717
  }
1718
+ if (exchangeResult.app_access_token_ref) {
1719
+ localStorage.setItem(STORAGE.APP_ACCESS_TOKEN_REF, exchangeResult.app_access_token_ref);
1720
+ }
1635
1721
  const acctType = typeof accountType === "string" ? accountType : "user";
1636
1722
  localStorage.setItem(STORAGE.USER, JSON.stringify(userToStore));
1637
1723
  localStorage.setItem(STORAGE.ACCOUNT_TYPE, acctType);
@@ -1643,6 +1729,7 @@ function clearSession() {
1643
1729
  localStorage.removeItem(STORAGE.USER);
1644
1730
  localStorage.removeItem(STORAGE.ACCOUNT_TYPE);
1645
1731
  localStorage.removeItem(STORAGE.ALIAS_REFERENCE);
1732
+ localStorage.removeItem(STORAGE.APP_ACCESS_TOKEN_REF);
1646
1733
  }
1647
1734
  function getErrorMessage$1(err, context) {
1648
1735
  if (err instanceof Error) {
@@ -1716,6 +1803,7 @@ function useNativeAuth(options) {
1716
1803
  useTokenHealthCheck({
1717
1804
  enabled: state.status === "completed" && state.user !== null,
1718
1805
  saasApiUrl,
1806
+ iamApiUrl,
1719
1807
  onTokenInvalid: handleTokenInvalid,
1720
1808
  onUserUpdated: handleUserUpdated,
1721
1809
  debug: isDebug
@@ -2192,7 +2280,7 @@ function useNativeAuth(options) {
2192
2280
  processToken: null
2193
2281
  }));
2194
2282
  }, [defaultAccountType]);
2195
- const logout = useCallback(async () => {
2283
+ const logout2 = useCallback(async () => {
2196
2284
  const token = localStorage.getItem(STORAGE.AUTH_TOKEN) || localStorage.getItem(STORAGE.TOKEN);
2197
2285
  try {
2198
2286
  if (token) {
@@ -2264,7 +2352,7 @@ function useNativeAuth(options) {
2264
2352
  grantAccess,
2265
2353
  resendOtp,
2266
2354
  setSession,
2267
- logout,
2355
+ logout: logout2,
2268
2356
  reset,
2269
2357
  clearError,
2270
2358
  register,
@@ -4718,12 +4806,8 @@ function NativeSSOPage({
4718
4806
  onLoginSuccess == null ? void 0 : onLoginSuccess(pendingSession.token, pendingSession.user);
4719
4807
  if (redirectAfterLogin) window.location.href = redirectAfterLogin;
4720
4808
  }, [pendingSession, onLoginSuccess, redirectAfterLogin]);
4721
- const handleLogout = useCallback(() => {
4722
- localStorage.removeItem(STORAGE.AUTH_TOKEN);
4723
- localStorage.removeItem(STORAGE.TOKEN);
4724
- localStorage.removeItem(STORAGE.USER);
4725
- localStorage.removeItem(STORAGE.ACCOUNT_TYPE);
4726
- localStorage.removeItem(STORAGE.ALIAS_REFERENCE);
4809
+ const handleLogout = useCallback(async () => {
4810
+ await logout();
4727
4811
  setSession(null);
4728
4812
  onLogout == null ? void 0 : onLogout();
4729
4813
  if (redirectAfterLogout) window.location.href = redirectAfterLogout;
@@ -4879,6 +4963,26 @@ function useNativeSSOConfig() {
4879
4963
  }
4880
4964
  return ctx;
4881
4965
  }
4966
+ const useLogout = (options) => {
4967
+ const [loading, setLoading] = useState(false);
4968
+ const [error, setError] = useState(null);
4969
+ const handleLogout = useCallback(async () => {
4970
+ var _a, _b;
4971
+ setLoading(true);
4972
+ setError(null);
4973
+ try {
4974
+ await logout();
4975
+ (_a = options == null ? void 0 : options.onSuccess) == null ? void 0 : _a.call(options);
4976
+ } catch (err) {
4977
+ const message = err instanceof Error ? err.message : "Erreur de déconnexion";
4978
+ setError(message);
4979
+ (_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(options, err instanceof Error ? err : new Error(message));
4980
+ } finally {
4981
+ setLoading(false);
4982
+ }
4983
+ }, [options]);
4984
+ return { logout: handleLogout, loading, error };
4985
+ };
4882
4986
  function getCredentialsOrThrow(params) {
4883
4987
  const app_key = params.app_key;
4884
4988
  const secret_key = params.secret_key;
@@ -5049,10 +5153,12 @@ export {
5049
5153
  getDefaultCountry,
5050
5154
  getNativeAuthConfig,
5051
5155
  iamAccountService,
5156
+ logout,
5052
5157
  mobilePasswordService,
5053
5158
  nativeAuthService,
5054
5159
  searchCountries,
5055
5160
  setNativeAuthConfig,
5161
+ useLogout,
5056
5162
  useMobilePassword,
5057
5163
  useMobileRegistration,
5058
5164
  useNativeAuth,