@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.cjs CHANGED
@@ -496,7 +496,8 @@ const STORAGE = {
496
496
  TOKEN: "token",
497
497
  USER: "user",
498
498
  ACCOUNT_TYPE: "account_type",
499
- ALIAS_REFERENCE: "alias_reference"
499
+ ALIAS_REFERENCE: "alias_reference",
500
+ APP_ACCESS_TOKEN_REF: "app_access_token_ref"
500
501
  };
501
502
  const setAuthToken = (token) => {
502
503
  if (typeof localStorage !== "undefined") {
@@ -515,8 +516,14 @@ const clearAuthToken = () => {
515
516
  localStorage.removeItem(STORAGE.USER);
516
517
  localStorage.removeItem(STORAGE.ACCOUNT_TYPE);
517
518
  localStorage.removeItem(STORAGE.ALIAS_REFERENCE);
519
+ localStorage.removeItem(STORAGE.APP_ACCESS_TOKEN_REF);
518
520
  }
519
521
  };
522
+ const logout = async () => {
523
+ const { nativeAuthService: nativeAuthService2 } = await Promise.resolve().then(() => nativeAuth);
524
+ const token = getAuthToken();
525
+ return nativeAuthService2.logout(token || void 0);
526
+ };
520
527
  const setAuthUser = (user) => {
521
528
  if (typeof localStorage !== "undefined") {
522
529
  localStorage.setItem(STORAGE.USER, JSON.stringify(user));
@@ -810,7 +817,7 @@ const nativeAuthService = {
810
817
  );
811
818
  },
812
819
  async exchange(callbackToken) {
813
- var _a;
820
+ var _a, _b;
814
821
  const config2 = getNativeAuthConfig();
815
822
  if (!config2.saasApiUrl) {
816
823
  throw new ApiError("saasApiUrl non configurée", "unknown");
@@ -832,9 +839,16 @@ const nativeAuthService = {
832
839
  if (response.user) {
833
840
  setAuthUser(response.user);
834
841
  }
842
+ if (response.app_access_token_ref && typeof localStorage !== "undefined") {
843
+ localStorage.setItem(STORAGE.APP_ACCESS_TOKEN_REF, response.app_access_token_ref);
844
+ }
845
+ const aliasRef = ((_a = response.user) == null ? void 0 : _a.alias_reference) || response.alias_reference;
846
+ if (aliasRef && typeof localStorage !== "undefined") {
847
+ localStorage.setItem(STORAGE.ALIAS_REFERENCE, aliasRef);
848
+ }
835
849
  }
836
850
  if (isDebugMode()) {
837
- console.log("✅ [SaaS] Session établie:", { user: (_a = response.user) == null ? void 0 : _a.name });
851
+ console.log("✅ [SaaS] Session établie:", { user: (_b = response.user) == null ? void 0 : _b.name });
838
852
  }
839
853
  return response;
840
854
  },
@@ -855,7 +869,13 @@ const nativeAuthService = {
855
869
  },
856
870
  1e4
857
871
  );
858
- return { valid: response.valid !== false, user_infos: response.user_infos };
872
+ if (response.status === "connected" && response.user) {
873
+ return { valid: true, user: response.user };
874
+ }
875
+ if (response.success !== false) {
876
+ return { valid: true, user: response.user };
877
+ }
878
+ return { valid: false };
859
879
  } catch (err) {
860
880
  if (err instanceof ApiError && err.statusCode === 401) {
861
881
  return { valid: false };
@@ -865,28 +885,53 @@ const nativeAuthService = {
865
885
  },
866
886
  async logout(token) {
867
887
  const config2 = getNativeAuthConfig();
868
- if (!config2.saasApiUrl) {
869
- throw new ApiError("saasApiUrl non configurée", "unknown");
888
+ const iamToken = typeof localStorage !== "undefined" ? localStorage.getItem(STORAGE.AUTH_TOKEN) || localStorage.getItem(STORAGE.TOKEN) : null;
889
+ const appAccessTokenRef = typeof localStorage !== "undefined" ? localStorage.getItem(STORAGE.APP_ACCESS_TOKEN_REF) : null;
890
+ const promises = [];
891
+ if (config2.saasApiUrl && token) {
892
+ promises.push(
893
+ fetchWithTimeout(
894
+ `${config2.saasApiUrl}/native/logout`,
895
+ {
896
+ method: "POST",
897
+ headers: getHeaders(token, true)
898
+ },
899
+ config2.timeout || 3e4
900
+ ).catch((err) => {
901
+ if (isDebugMode()) {
902
+ console.warn("⚠️ [SaaS] Échec logout (non-bloquant):", err instanceof Error ? err.message : err);
903
+ }
904
+ })
905
+ );
870
906
  }
871
- try {
872
- const response = await fetchWithTimeout(
873
- `${config2.saasApiUrl}/native/logout`,
874
- {
875
- method: "POST",
876
- headers: getHeaders(token, true)
877
- },
878
- config2.timeout || 3e4
907
+ if (config2.iamApiUrl && (iamToken || appAccessTokenRef)) {
908
+ const payload = {};
909
+ if (iamToken) payload.sanctum_token = iamToken;
910
+ if (appAccessTokenRef) payload.app_access_token_ref = appAccessTokenRef;
911
+ promises.push(
912
+ fetchWithTimeout(
913
+ `${config2.iamApiUrl}/iam/disconnect`,
914
+ {
915
+ method: "POST",
916
+ headers: { "Content-Type": "application/json", "Accept": "application/json" },
917
+ body: JSON.stringify(payload)
918
+ },
919
+ 5e3
920
+ ).catch((err) => {
921
+ if (isDebugMode()) {
922
+ console.warn("⚠️ [IAM] Échec disconnect (non-bloquant):", err instanceof Error ? err.message : err);
923
+ }
924
+ })
879
925
  );
880
- clearAuthToken();
881
- credentials = null;
882
- credentialsLoadedAt = 0;
883
- return response;
884
- } catch {
885
- clearAuthToken();
886
- credentials = null;
887
- credentialsLoadedAt = 0;
888
- return { success: true };
889
926
  }
927
+ await Promise.allSettled(promises);
928
+ if (isDebugMode()) {
929
+ console.log("✅ [Logout] Double revocation terminée — nettoyage local");
930
+ }
931
+ clearAuthToken();
932
+ credentials = null;
933
+ credentialsLoadedAt = 0;
934
+ return { success: true };
890
935
  },
891
936
  clearCredentials() {
892
937
  credentials = null;
@@ -947,6 +992,10 @@ const nativeAuthService = {
947
992
  return this.init(native_token);
948
993
  }
949
994
  };
995
+ const nativeAuth = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
996
+ __proto__: null,
997
+ nativeAuthService
998
+ }, Symbol.toStringTag, { value: "Module" }));
950
999
  function getIAMHeaders() {
951
1000
  const creds = nativeAuthService.getCredentials();
952
1001
  if (!creds) {
@@ -1524,8 +1573,8 @@ function PasswordRecoveryModal({ open, onOpenChange, onSuccess, saasApiUrl, iamA
1524
1573
  ] })
1525
1574
  ] }) });
1526
1575
  }
1527
- const FIRST_CHECK_DELAY = 2 * 60 * 1e3;
1528
- const INTERVAL_DELAY = 5 * 60 * 1e3;
1576
+ const FIRST_CHECK_DELAY = 60 * 1e3;
1577
+ const INTERVAL_DELAY = 2 * 60 * 1e3;
1529
1578
  async function checkTokenValidity(saasApiUrl, token, debug) {
1530
1579
  if (typeof navigator !== "undefined" && !navigator.onLine) {
1531
1580
  if (debug) console.log("🔄 [HealthCheck] Offline — skip");
@@ -1545,7 +1594,7 @@ async function checkTokenValidity(saasApiUrl, token, debug) {
1545
1594
  });
1546
1595
  clearTimeout(timeoutId);
1547
1596
  if (response.status === 401) {
1548
- if (debug) console.log("🔄 [HealthCheck] Token invalide (401)");
1597
+ if (debug) console.log("🔄 [HealthCheck] Token invalide (401) — déconnexion");
1549
1598
  return { valid: false };
1550
1599
  }
1551
1600
  if (!response.ok) {
@@ -1553,11 +1602,15 @@ async function checkTokenValidity(saasApiUrl, token, debug) {
1553
1602
  throw new Error(`server_error_${response.status}`);
1554
1603
  }
1555
1604
  const data = await response.json();
1556
- if (debug) console.log("🔄 [HealthCheck] Token valide ✅");
1557
- return {
1558
- valid: data.valid !== false,
1559
- user_infos: data.user_infos
1560
- };
1605
+ if (data.status === "connected" && data.user) {
1606
+ if (debug) console.log("🔄 [HealthCheck] Token valide ✅ — user_infos mis à jour");
1607
+ return { valid: true, user: data.user };
1608
+ }
1609
+ if (data.success !== false) {
1610
+ if (debug) console.log("🔄 [HealthCheck] Token valide ✅");
1611
+ return { valid: true, user: data.user };
1612
+ }
1613
+ return { valid: false };
1561
1614
  } catch (error) {
1562
1615
  clearTimeout(timeoutId);
1563
1616
  if (error instanceof Error && error.message === "offline") {
@@ -1570,8 +1623,34 @@ async function checkTokenValidity(saasApiUrl, token, debug) {
1570
1623
  throw error;
1571
1624
  }
1572
1625
  }
1626
+ function revokeOnIam(iamApiUrl, sanctumToken, debug) {
1627
+ try {
1628
+ const controller = new AbortController();
1629
+ setTimeout(() => controller.abort(), 5e3);
1630
+ const appAccessTokenRef = typeof localStorage !== "undefined" ? localStorage.getItem(STORAGE.APP_ACCESS_TOKEN_REF) : null;
1631
+ const payload = { sanctum_token: sanctumToken };
1632
+ if (appAccessTokenRef) {
1633
+ payload.app_access_token_ref = appAccessTokenRef;
1634
+ }
1635
+ if (debug) {
1636
+ console.log("🔄 [HealthCheck] Revocation IAM:", { hasRef: !!appAccessTokenRef });
1637
+ }
1638
+ fetch(`${iamApiUrl}/iam/disconnect`, {
1639
+ method: "POST",
1640
+ headers: {
1641
+ "Content-Type": "application/json",
1642
+ "Accept": "application/json"
1643
+ },
1644
+ body: JSON.stringify(payload),
1645
+ signal: controller.signal
1646
+ }).catch(() => {
1647
+ if (debug) console.log("🔄 [HealthCheck] Échec revocation IAM (non-bloquant)");
1648
+ });
1649
+ } catch {
1650
+ }
1651
+ }
1573
1652
  function useTokenHealthCheck(options) {
1574
- const { enabled, saasApiUrl, onTokenInvalid, onUserUpdated, debug = false } = options;
1653
+ const { enabled, saasApiUrl, iamApiUrl, onTokenInvalid, onUserUpdated, debug = false } = options;
1575
1654
  const timerRef = react.useRef(null);
1576
1655
  const intervalRef = react.useRef(null);
1577
1656
  const enabledRef = react.useRef(enabled);
@@ -1588,15 +1667,19 @@ function useTokenHealthCheck(options) {
1588
1667
  try {
1589
1668
  const result = await checkTokenValidity(saasApiUrl, token, debug);
1590
1669
  if (!result.valid) {
1670
+ if (iamApiUrl) {
1671
+ if (debug) console.log("🔄 [HealthCheck] Revocation IAM avec sanctum_token...");
1672
+ revokeOnIam(iamApiUrl, token, debug);
1673
+ }
1591
1674
  callbacksRef.current.onTokenInvalid();
1592
1675
  return;
1593
1676
  }
1594
- if (result.user_infos && callbacksRef.current.onUserUpdated) {
1595
- callbacksRef.current.onUserUpdated(result.user_infos);
1677
+ if (result.user && callbacksRef.current.onUserUpdated) {
1678
+ callbacksRef.current.onUserUpdated(result.user);
1596
1679
  }
1597
1680
  } catch {
1598
1681
  }
1599
- }, [saasApiUrl, debug]);
1682
+ }, [saasApiUrl, iamApiUrl, debug]);
1600
1683
  react.useEffect(() => {
1601
1684
  if (timerRef.current) {
1602
1685
  clearTimeout(timerRef.current);
@@ -1607,7 +1690,7 @@ function useTokenHealthCheck(options) {
1607
1690
  intervalRef.current = null;
1608
1691
  }
1609
1692
  if (!enabled || !saasApiUrl) return;
1610
- if (debug) console.log("🔄 [HealthCheck] Activé — premier check dans 2 min");
1693
+ if (debug) console.log("🔄 [HealthCheck] Activé — premier check dans 60s, puis toutes les 2 min");
1611
1694
  timerRef.current = setTimeout(() => {
1612
1695
  performCheck();
1613
1696
  intervalRef.current = setInterval(performCheck, INTERVAL_DELAY);
@@ -1634,6 +1717,9 @@ function saveSession(exchangeResult, accountType) {
1634
1717
  if (aliasRef) {
1635
1718
  localStorage.setItem(STORAGE.ALIAS_REFERENCE, aliasRef);
1636
1719
  }
1720
+ if (exchangeResult.app_access_token_ref) {
1721
+ localStorage.setItem(STORAGE.APP_ACCESS_TOKEN_REF, exchangeResult.app_access_token_ref);
1722
+ }
1637
1723
  const acctType = typeof accountType === "string" ? accountType : "user";
1638
1724
  localStorage.setItem(STORAGE.USER, JSON.stringify(userToStore));
1639
1725
  localStorage.setItem(STORAGE.ACCOUNT_TYPE, acctType);
@@ -1645,6 +1731,7 @@ function clearSession() {
1645
1731
  localStorage.removeItem(STORAGE.USER);
1646
1732
  localStorage.removeItem(STORAGE.ACCOUNT_TYPE);
1647
1733
  localStorage.removeItem(STORAGE.ALIAS_REFERENCE);
1734
+ localStorage.removeItem(STORAGE.APP_ACCESS_TOKEN_REF);
1648
1735
  }
1649
1736
  function getErrorMessage$1(err, context) {
1650
1737
  if (err instanceof Error) {
@@ -1718,6 +1805,7 @@ function useNativeAuth(options) {
1718
1805
  useTokenHealthCheck({
1719
1806
  enabled: state.status === "completed" && state.user !== null,
1720
1807
  saasApiUrl,
1808
+ iamApiUrl,
1721
1809
  onTokenInvalid: handleTokenInvalid,
1722
1810
  onUserUpdated: handleUserUpdated,
1723
1811
  debug: isDebug
@@ -2194,7 +2282,7 @@ function useNativeAuth(options) {
2194
2282
  processToken: null
2195
2283
  }));
2196
2284
  }, [defaultAccountType]);
2197
- const logout = react.useCallback(async () => {
2285
+ const logout2 = react.useCallback(async () => {
2198
2286
  const token = localStorage.getItem(STORAGE.AUTH_TOKEN) || localStorage.getItem(STORAGE.TOKEN);
2199
2287
  try {
2200
2288
  if (token) {
@@ -2266,7 +2354,7 @@ function useNativeAuth(options) {
2266
2354
  grantAccess,
2267
2355
  resendOtp,
2268
2356
  setSession,
2269
- logout,
2357
+ logout: logout2,
2270
2358
  reset,
2271
2359
  clearError,
2272
2360
  register,
@@ -4720,12 +4808,8 @@ function NativeSSOPage({
4720
4808
  onLoginSuccess == null ? void 0 : onLoginSuccess(pendingSession.token, pendingSession.user);
4721
4809
  if (redirectAfterLogin) window.location.href = redirectAfterLogin;
4722
4810
  }, [pendingSession, onLoginSuccess, redirectAfterLogin]);
4723
- const handleLogout = react.useCallback(() => {
4724
- localStorage.removeItem(STORAGE.AUTH_TOKEN);
4725
- localStorage.removeItem(STORAGE.TOKEN);
4726
- localStorage.removeItem(STORAGE.USER);
4727
- localStorage.removeItem(STORAGE.ACCOUNT_TYPE);
4728
- localStorage.removeItem(STORAGE.ALIAS_REFERENCE);
4811
+ const handleLogout = react.useCallback(async () => {
4812
+ await logout();
4729
4813
  setSession(null);
4730
4814
  onLogout == null ? void 0 : onLogout();
4731
4815
  if (redirectAfterLogout) window.location.href = redirectAfterLogout;
@@ -4881,6 +4965,26 @@ function useNativeSSOConfig() {
4881
4965
  }
4882
4966
  return ctx;
4883
4967
  }
4968
+ const useLogout = (options) => {
4969
+ const [loading, setLoading] = react.useState(false);
4970
+ const [error, setError] = react.useState(null);
4971
+ const handleLogout = react.useCallback(async () => {
4972
+ var _a, _b;
4973
+ setLoading(true);
4974
+ setError(null);
4975
+ try {
4976
+ await logout();
4977
+ (_a = options == null ? void 0 : options.onSuccess) == null ? void 0 : _a.call(options);
4978
+ } catch (err) {
4979
+ const message = err instanceof Error ? err.message : "Erreur de déconnexion";
4980
+ setError(message);
4981
+ (_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(options, err instanceof Error ? err : new Error(message));
4982
+ } finally {
4983
+ setLoading(false);
4984
+ }
4985
+ }, [options]);
4986
+ return { logout: handleLogout, loading, error };
4987
+ };
4884
4988
  function getCredentialsOrThrow(params) {
4885
4989
  const app_key = params.app_key;
4886
4990
  const secret_key = params.secret_key;
@@ -5050,10 +5154,12 @@ exports.getCountryByDialCode = getCountryByDialCode;
5050
5154
  exports.getDefaultCountry = getDefaultCountry;
5051
5155
  exports.getNativeAuthConfig = getNativeAuthConfig;
5052
5156
  exports.iamAccountService = iamAccountService;
5157
+ exports.logout = logout;
5053
5158
  exports.mobilePasswordService = mobilePasswordService;
5054
5159
  exports.nativeAuthService = nativeAuthService;
5055
5160
  exports.searchCountries = searchCountries;
5056
5161
  exports.setNativeAuthConfig = setNativeAuthConfig;
5162
+ exports.useLogout = useLogout;
5057
5163
  exports.useMobilePassword = useMobilePassword;
5058
5164
  exports.useMobileRegistration = useMobileRegistration;
5059
5165
  exports.useNativeAuth = useNativeAuth;