@ollaid/native-sso 1.0.0 → 1.0.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/README.md CHANGED
@@ -60,6 +60,7 @@ function App() {
60
60
  <NativeSSOPage
61
61
  saasApiUrl="https://mon-saas.com/api"
62
62
  iamApiUrl="https://identityam.ollaid.com/api"
63
+ accountType="user"
63
64
  onLoginSuccess={(token, user) => {
64
65
  console.log('Connecté !', user.name);
65
66
  navigate('/dashboard');
@@ -95,15 +96,17 @@ La page `/auth/sso` gère automatiquement :
95
96
  |------|------|--------|-------------|
96
97
  | `saasApiUrl` | `string` | ✅ | URL du backend SaaS (ex: `https://mon-saas.com/api`) |
97
98
  | `iamApiUrl` | `string` | ✅ | URL du backend IAM (ex: `https://identityam.ollaid.com/api`) |
99
+ | `accountType` | `'user' \| 'client'` | ❌ | Type de compte à persister dans localStorage (défaut: `'user'`). Utile si vous avez plusieurs pages SSO avec des rôles différents. |
98
100
  | `onLoginSuccess` | `(token: string, user: UserInfos) => void` | ❌ | Callback après connexion réussie |
99
101
  | `onLogout` | `() => void` | ❌ | Callback après déconnexion |
100
- | `debug` | `boolean` | ❌ | Active les logs console |
101
102
  | `title` | `string` | ❌ | Titre personnalisé (défaut: "Un compte, plusieurs accès") |
102
103
  | `description` | `string` | ❌ | Description personnalisée |
103
104
  | `logoUrl` | `string` | ❌ | URL du logo (remplace le slider) |
104
105
  | `hideFooter` | `boolean` | ❌ | Masquer "Propulsé par iam.ollaid.com" |
105
106
  | `onOnboardingComplete` | `(data: { image_url?: string; ccphone?: string; phone?: string }) => void` | ❌ | Callback après complétion de l'onboarding |
106
107
 
108
+ > **Note :** Le mode `debug` est contrôlé **uniquement** par le backend via la variable d'environnement `IAM_DEBUG` dans le `.env` du SaaS. Il n'y a plus de prop `debug` à passer au composant.
109
+
107
110
  ---
108
111
 
109
112
  ## Usage avancé (composants individuels)
@@ -227,6 +230,11 @@ $secretKey = $payload['secret_key'];
227
230
 
228
231
  ### `POST /api/native/exchange`
229
232
 
233
+ > ⚠️ **IMPORTANT — Route PUBLIQUE obligatoire**
234
+ > Cette route **NE DOIT PAS** être derrière le middleware `auth:sanctum`.
235
+ > Si vous la placez dans un groupe `Route::middleware('auth:sanctum')`, le frontend recevra une **erreur 401 Unauthenticated** systématique car l'utilisateur n'a pas encore de token Sanctum à ce stade du flux.
236
+ > Assurez-vous que `/api/native/config` et `/api/native/exchange` sont **en dehors** de tout groupe authentifié.
237
+
230
238
  Échange le `callback_token` reçu de l'IAM contre un token Sanctum local.
231
239
 
232
240
  **Headers requis :** `Content-Type: application/json`
@@ -665,14 +673,19 @@ class NativeAuthController extends Controller
665
673
 
666
674
  ### Routes `routes/api.php`
667
675
 
676
+ > ⚠️ **Attention au placement des routes !**
677
+ > `config` et `exchange` doivent être **publiques** (pas de middleware auth).
678
+ > `check-token` et `logout` doivent être **protégées** par `auth:sanctum`.
679
+ > Si `exchange` est derrière `auth:sanctum`, le frontend recevra un **401 Unauthenticated**.
680
+
668
681
  ```php
669
682
  use App\Http\Controllers\Api\NativeAuthController;
670
683
 
671
- // Routes SSO Native (pas d'auth requise)
684
+ // Routes PUBLIQUES (pas d'auth requise — l'utilisateur n'a pas encore de token)
672
685
  Route::get('/native/config', [NativeAuthController::class, 'config']);
673
686
  Route::post('/native/exchange', [NativeAuthController::class, 'exchange']);
674
687
 
675
- // Routes SSO Native (auth Sanctum requise)
688
+ // 🔒 Routes PROTÉGÉES (auth Sanctum requise — l'utilisateur a un token)
676
689
  Route::middleware('auth:sanctum')->group(function () {
677
690
  Route::post('/native/check-token', [NativeAuthController::class, 'checkToken']);
678
691
  Route::post('/native/logout', [NativeAuthController::class, 'logout']);
@@ -1370,20 +1383,27 @@ Toutes les APIs IAM retournent le même objet `user_infos` avec exactement **9 c
1370
1383
 
1371
1384
  ## Session & localStorage
1372
1385
 
1373
- Le package utilise **4 clés** dans `localStorage` pour persister la session :
1386
+ Le package utilise **5 clés** dans `localStorage` pour persister la session :
1374
1387
 
1375
1388
  | Clé | Contenu | Source | Valeurs possibles |
1376
1389
  |-----|---------|--------|-------------------|
1377
1390
  | `token` | Token Sanctum (bearer) | Réponse de `/api/native/exchange` | Chaîne `"1\|abc123..."` |
1378
1391
  | `auth_token` | Copie du token (compatibilité) | Même source que `token` | Idem |
1379
- | `user` | Objet `user_infos` sérialisé en JSON | Réponse de `/api/native/exchange` ou mise à jour via health check | `{"name":"...","email":"...",...}` |
1392
+ | `user` | Objet utilisateur enrichi sérialisé en JSON | Réponse de `/api/native/exchange` ou mise à jour via health check | `{"iam_reference":"USR-XXX","alias_reference":"ALI-XXX","name":"...","email":"...",...}` |
1380
1393
  | `account_type` | Type de compte | Déterminé lors du `exchange` selon le mode d'inscription | `"user"` (défaut) ou `"client"` (inscription phone-only) |
1394
+ | `alias_reference` | Référence alias utilisée lors de la connexion | Réponse de `/api/native/exchange` (champ `user.alias_reference`) | `"ALI-XXXXXXXX"` |
1395
+
1396
+ > **Note :** `account_type` et `alias_reference` sont stockés **séparément** de l'objet `user` en plus d'être inclus dans le JSON de la clé `user`.
1397
+
1398
+ #### Champs enrichis dans l'objet `user`
1381
1399
 
1382
- > **Note :** `account_type` est stocké **séparément** de l'objet `user` il n'est pas inclus dans le JSON de la clé `user`.
1400
+ L'objet `user` stocké en localStorage contient deux champs ajoutés automatiquement par le package :
1401
+ - `iam_reference` : la référence IAM de l'utilisateur (`USR-XXXXXXXX`), extraite de `user.reference`
1402
+ - `alias_reference` : la référence de l'alias utilisé lors de la connexion (`ALI-XXXXXXXX`), extraite de `user.alias_reference`
1383
1403
 
1384
1404
  ### Nettoyage
1385
1405
 
1386
- Lors du `logout()`, les 4 clés sont supprimées via `clearAuthToken()`.
1406
+ Lors du `logout()`, les 5 clés sont supprimées via `clearAuthToken()`.
1387
1407
 
1388
1408
  ### Accès programmatique
1389
1409
 
@@ -1391,8 +1411,9 @@ Lors du `logout()`, les 4 clés sont supprimées via `clearAuthToken()`.
1391
1411
  import { getAuthToken, getAuthUser, getAccountType } from '@ollaid/native-sso';
1392
1412
 
1393
1413
  const token = getAuthToken(); // string | null
1394
- const user = getAuthUser<UserInfos>(); // UserInfos | null
1414
+ const user = getAuthUser<UserInfos>(); // UserInfos | null — contient iam_reference et alias_reference
1395
1415
  const type = getAccountType(); // string | null
1416
+ const aliasRef = localStorage.getItem('alias_reference'); // string | null
1396
1417
  ```
1397
1418
 
1398
1419
  ---
@@ -14,7 +14,8 @@ export interface LoginModalProps {
14
14
  iamApiUrl: string;
15
15
  loading?: boolean;
16
16
  showSwitchToSignup?: boolean;
17
- debug?: boolean;
17
+ /** Type de compte par défaut à persister dans localStorage */
18
+ defaultAccountType?: 'user' | 'client';
18
19
  }
19
- export declare function LoginModal({ open, onOpenChange, onSwitchToSignup, onLoginSuccess, saasApiUrl, iamApiUrl, loading, showSwitchToSignup, debug, }: LoginModalProps): import("react/jsx-runtime").JSX.Element;
20
+ export declare function LoginModal({ open, onOpenChange, onSwitchToSignup, onLoginSuccess, saasApiUrl, iamApiUrl, loading, showSwitchToSignup, defaultAccountType, }: LoginModalProps): import("react/jsx-runtime").JSX.Element;
20
21
  export default LoginModal;
@@ -20,8 +20,8 @@ export interface NativeSSOPageProps {
20
20
  ccphone?: string;
21
21
  phone?: string;
22
22
  }) => void;
23
- /** Mode debug */
24
- debug?: boolean;
23
+ /** Type de compte à persister dans localStorage (défaut: 'user') */
24
+ accountType?: 'user' | 'client';
25
25
  /** Titre personnalisé */
26
26
  title?: string;
27
27
  /** Description personnalisée */
@@ -31,5 +31,5 @@ export interface NativeSSOPageProps {
31
31
  /** Masquer le footer "Propulsé par" */
32
32
  hideFooter?: boolean;
33
33
  }
34
- export declare function NativeSSOPage({ saasApiUrl, iamApiUrl, onLoginSuccess, onLogout, onOnboardingComplete, debug, title, description, logoUrl, hideFooter, }: NativeSSOPageProps): import("react/jsx-runtime").JSX.Element;
34
+ export declare function NativeSSOPage({ saasApiUrl, iamApiUrl, onLoginSuccess, onLogout, onOnboardingComplete, accountType, title, description, logoUrl, hideFooter, }: NativeSSOPageProps): import("react/jsx-runtime").JSX.Element;
35
35
  export default NativeSSOPage;
@@ -11,7 +11,6 @@ export interface PasswordRecoveryModalProps {
11
11
  onSuccess: () => void;
12
12
  saasApiUrl: string;
13
13
  iamApiUrl: string;
14
- debug?: boolean;
15
14
  }
16
- export declare function PasswordRecoveryModal({ open, onOpenChange, onSuccess, saasApiUrl, iamApiUrl, debug }: PasswordRecoveryModalProps): import("react/jsx-runtime").JSX.Element;
15
+ export declare function PasswordRecoveryModal({ open, onOpenChange, onSuccess, saasApiUrl, iamApiUrl }: PasswordRecoveryModalProps): import("react/jsx-runtime").JSX.Element;
17
16
  export default PasswordRecoveryModal;
@@ -12,7 +12,8 @@ export interface SignupModalProps {
12
12
  onSignupSuccess: (token: string, user: UserInfos) => void;
13
13
  saasApiUrl: string;
14
14
  iamApiUrl: string;
15
- debug?: boolean;
15
+ /** Type de compte par défaut à persister dans localStorage */
16
+ defaultAccountType?: 'user' | 'client';
16
17
  }
17
- export declare function SignupModal({ open, onOpenChange, onSwitchToLogin, onSignupSuccess, saasApiUrl, iamApiUrl, debug }: SignupModalProps): import("react/jsx-runtime").JSX.Element;
18
+ export declare function SignupModal({ open, onOpenChange, onSwitchToLogin, onSignupSuccess, saasApiUrl, iamApiUrl, defaultAccountType }: SignupModalProps): import("react/jsx-runtime").JSX.Element;
18
19
  export default SignupModal;
@@ -8,7 +8,6 @@ export interface UseMobilePasswordOptions {
8
8
  saasApiUrl: string;
9
9
  iamApiUrl: string;
10
10
  autoLoadCredentials?: boolean;
11
- debug?: boolean;
12
11
  }
13
12
  export declare function useMobilePassword(options: UseMobilePasswordOptions): {
14
13
  credentialsLoaded: boolean;
@@ -19,7 +19,6 @@ interface RegistrationConflict {
19
19
  export interface UseMobileRegistrationOptions {
20
20
  saasApiUrl: string;
21
21
  iamApiUrl: string;
22
- debug?: boolean;
23
22
  }
24
23
  export declare function useMobileRegistration(options?: UseMobileRegistrationOptions): {
25
24
  processToken: string | null;
@@ -12,8 +12,8 @@ export interface UseNativeAuthOptions {
12
12
  iamApiUrl: string;
13
13
  /** Charger les credentials automatiquement au montage */
14
14
  autoLoadCredentials?: boolean;
15
- /** Mode debug */
16
- debug?: boolean;
15
+ /** Type de compte par défaut à persister (défaut: 'user') */
16
+ defaultAccountType?: 'user' | 'client';
17
17
  }
18
18
  export declare function useNativeAuth(options: UseNativeAuthOptions): {
19
19
  credentialsLoaded: boolean;
@@ -117,7 +117,22 @@ export declare function useNativeAuth(options: UseNativeAuthOptions): {
117
117
  error_type?: undefined;
118
118
  } | {
119
119
  success: boolean;
120
- user: import("..").NativeUser;
120
+ user: {
121
+ iam_reference: string;
122
+ alias_reference: any;
123
+ id?: number;
124
+ reference: string;
125
+ name: string;
126
+ email?: string | null;
127
+ phone?: string;
128
+ ccphone?: string;
129
+ image_url?: string;
130
+ account_type?: "user" | "client";
131
+ town?: string;
132
+ country?: string;
133
+ address?: string;
134
+ auth_2fa?: boolean;
135
+ };
121
136
  callback_token: string;
122
137
  error?: undefined;
123
138
  requires_2fa?: undefined;
@@ -157,7 +172,22 @@ export declare function useNativeAuth(options: UseNativeAuthOptions): {
157
172
  error_type?: undefined;
158
173
  } | {
159
174
  success: boolean;
160
- user: import("..").NativeUser;
175
+ user: {
176
+ iam_reference: string;
177
+ alias_reference: any;
178
+ id?: number;
179
+ reference: string;
180
+ name: string;
181
+ email?: string | null;
182
+ phone?: string;
183
+ ccphone?: string;
184
+ image_url?: string;
185
+ account_type?: "user" | "client";
186
+ town?: string;
187
+ country?: string;
188
+ address?: string;
189
+ auth_2fa?: boolean;
190
+ };
161
191
  callback_token: string;
162
192
  error?: undefined;
163
193
  status?: undefined;
@@ -184,7 +214,22 @@ export declare function useNativeAuth(options: UseNativeAuthOptions): {
184
214
  error_type?: undefined;
185
215
  } | {
186
216
  success: boolean;
187
- user: import("..").NativeUser;
217
+ user: {
218
+ iam_reference: string;
219
+ alias_reference: any;
220
+ id?: number;
221
+ reference: string;
222
+ name: string;
223
+ email?: string | null;
224
+ phone?: string;
225
+ ccphone?: string;
226
+ image_url?: string;
227
+ account_type?: "user" | "client";
228
+ town?: string;
229
+ country?: string;
230
+ address?: string;
231
+ auth_2fa?: boolean;
232
+ };
188
233
  error?: undefined;
189
234
  error_type?: undefined;
190
235
  } | {
@@ -201,7 +246,22 @@ export declare function useNativeAuth(options: UseNativeAuthOptions): {
201
246
  error_type?: undefined;
202
247
  } | {
203
248
  success: boolean;
204
- user: import("..").NativeUser;
249
+ user: {
250
+ iam_reference: string;
251
+ alias_reference: any;
252
+ id?: number;
253
+ reference: string;
254
+ name: string;
255
+ email?: string | null;
256
+ phone?: string;
257
+ ccphone?: string;
258
+ image_url?: string;
259
+ account_type?: "user" | "client";
260
+ town?: string;
261
+ country?: string;
262
+ address?: string;
263
+ auth_2fa?: boolean;
264
+ };
205
265
  callback_token: string;
206
266
  error?: undefined;
207
267
  error_type?: undefined;
package/dist/index.cjs CHANGED
@@ -481,7 +481,8 @@ const STORAGE = {
481
481
  AUTH_TOKEN: "auth_token",
482
482
  TOKEN: "token",
483
483
  USER: "user",
484
- ACCOUNT_TYPE: "account_type"
484
+ ACCOUNT_TYPE: "account_type",
485
+ ALIAS_REFERENCE: "alias_reference"
485
486
  };
486
487
  const setAuthToken = (token) => {
487
488
  if (typeof localStorage !== "undefined") {
@@ -499,6 +500,7 @@ const clearAuthToken = () => {
499
500
  localStorage.removeItem(STORAGE.TOKEN);
500
501
  localStorage.removeItem(STORAGE.USER);
501
502
  localStorage.removeItem(STORAGE.ACCOUNT_TYPE);
503
+ localStorage.removeItem(STORAGE.ALIAS_REFERENCE);
502
504
  }
503
505
  };
504
506
  const setAuthUser = (user) => {
@@ -587,6 +589,10 @@ function getHeaders(token) {
587
589
  return headers;
588
590
  }
589
591
  let credentials = null;
592
+ let credentialsLoadedAt = 0;
593
+ let credentialsTtl = 300;
594
+ const DEFAULT_TTL = 300;
595
+ const REFRESH_MARGIN = 30;
590
596
  const nativeAuthService = {
591
597
  hasCredentials() {
592
598
  return credentials !== null;
@@ -594,6 +600,26 @@ const nativeAuthService = {
594
600
  getCredentials() {
595
601
  return credentials ? { ...credentials } : null;
596
602
  },
603
+ getCredentialsTtl() {
604
+ return credentialsTtl;
605
+ },
606
+ getCredentialsAge() {
607
+ if (!credentialsLoadedAt) return Infinity;
608
+ return (Date.now() - credentialsLoadedAt) / 1e3;
609
+ },
610
+ areCredentialsExpiringSoon() {
611
+ if (!credentials || !credentialsLoadedAt) return true;
612
+ const age = this.getCredentialsAge();
613
+ return age >= credentialsTtl - REFRESH_MARGIN;
614
+ },
615
+ async ensureFreshCredentials() {
616
+ if (!credentials || this.areCredentialsExpiringSoon()) {
617
+ if (isDebugMode()) {
618
+ console.log("🔄 [Native] Credentials expirés ou proches — auto-refresh");
619
+ }
620
+ await this.loadCredentials();
621
+ }
622
+ },
597
623
  async loadCredentials() {
598
624
  const config2 = getNativeAuthConfig();
599
625
  if (!config2.saasApiUrl) {
@@ -614,6 +640,8 @@ const nativeAuthService = {
614
640
  appKey: response.app_key,
615
641
  encryptedCredentials: response.encrypted_credentials
616
642
  };
643
+ credentialsLoadedAt = Date.now();
644
+ credentialsTtl = response.credentials_ttl || DEFAULT_TTL;
617
645
  if (typeof response.debug === "boolean") {
618
646
  const currentConfig = getNativeAuthConfig();
619
647
  if (currentConfig.debug !== true) {
@@ -621,11 +649,12 @@ const nativeAuthService = {
621
649
  }
622
650
  }
623
651
  if (isDebugMode()) {
624
- console.log("✅ [SaaS] Credentials chargés (debug:", response.debug ?? "non défini", ")");
652
+ console.log("✅ [SaaS] Credentials chargés (ttl:", credentialsTtl, "s, debug:", response.debug ?? "non défini", ")");
625
653
  }
626
654
  return credentials;
627
655
  },
628
656
  async encrypt(type, data) {
657
+ await this.ensureFreshCredentials();
629
658
  if (!credentials) {
630
659
  throw new ApiError("Credentials non chargés. Appelez loadCredentials() d'abord.", "auth");
631
660
  }
@@ -833,15 +862,18 @@ const nativeAuthService = {
833
862
  );
834
863
  clearAuthToken();
835
864
  credentials = null;
865
+ credentialsLoadedAt = 0;
836
866
  return response;
837
867
  } catch {
838
868
  clearAuthToken();
839
869
  credentials = null;
870
+ credentialsLoadedAt = 0;
840
871
  return { success: true };
841
872
  }
842
873
  },
843
874
  clearCredentials() {
844
875
  credentials = null;
876
+ credentialsLoadedAt = 0;
845
877
  },
846
878
  // ============================================
847
879
  // High-level methods
@@ -1024,14 +1056,14 @@ function getErrorMessage$2(err, context) {
1024
1056
  return { message: `Erreur lors de ${context}`, type: "unknown" };
1025
1057
  }
1026
1058
  function useMobilePassword(options) {
1027
- const { saasApiUrl, iamApiUrl, autoLoadCredentials = true, debug = false } = options;
1059
+ const { saasApiUrl, iamApiUrl, autoLoadCredentials = true } = options;
1028
1060
  const configuredRef = react.useRef(false);
1029
1061
  react.useEffect(() => {
1030
1062
  if (!configuredRef.current) {
1031
- setNativeAuthConfig({ saasApiUrl, iamApiUrl, debug });
1063
+ setNativeAuthConfig({ saasApiUrl, iamApiUrl });
1032
1064
  configuredRef.current = true;
1033
1065
  }
1034
- }, [saasApiUrl, iamApiUrl, debug]);
1066
+ }, [saasApiUrl, iamApiUrl]);
1035
1067
  const [state, setState] = react.useState({
1036
1068
  credentialsLoaded: false,
1037
1069
  processToken: null,
@@ -1267,7 +1299,7 @@ const backBtnStyle$2 = {
1267
1299
  color: C$3.gray700,
1268
1300
  zIndex: 10
1269
1301
  };
1270
- function PasswordRecoveryModal({ open, onOpenChange, onSuccess, saasApiUrl, iamApiUrl, debug = false }) {
1302
+ function PasswordRecoveryModal({ open, onOpenChange, onSuccess, saasApiUrl, iamApiUrl }) {
1271
1303
  const {
1272
1304
  status,
1273
1305
  loading: pwLoading,
@@ -1282,7 +1314,7 @@ function PasswordRecoveryModal({ open, onOpenChange, onSuccess, saasApiUrl, iamA
1282
1314
  resendOtp,
1283
1315
  reset: resetHook,
1284
1316
  clearError
1285
- } = useMobilePassword({ saasApiUrl, iamApiUrl, debug });
1317
+ } = useMobilePassword({ saasApiUrl, iamApiUrl });
1286
1318
  const [step, setStep] = react.useState("email");
1287
1319
  const [email, setEmail] = react.useState("");
1288
1320
  const [otp, setOtp] = react.useState("");
@@ -1569,11 +1601,22 @@ function useTokenHealthCheck(options) {
1569
1601
  }, [enabled, saasApiUrl, performCheck, debug]);
1570
1602
  }
1571
1603
  function saveSession(exchangeResult, accountType) {
1604
+ var _a, _b;
1572
1605
  const sanctumToken = exchangeResult.auth_token || exchangeResult.token;
1573
1606
  localStorage.setItem(STORAGE.AUTH_TOKEN, sanctumToken);
1574
1607
  localStorage.setItem(STORAGE.TOKEN, sanctumToken);
1575
- const userToStore = exchangeResult.user_infos ? { ...exchangeResult.user, ...exchangeResult.user_infos } : exchangeResult.user;
1576
- const acctType = accountType === "phone-only" ? "client" : "user";
1608
+ const baseUser = exchangeResult.user_infos ? { ...exchangeResult.user, ...exchangeResult.user_infos } : exchangeResult.user;
1609
+ const aliasRef = ((_a = exchangeResult.user) == null ? void 0 : _a.alias_reference) || exchangeResult.alias_reference || "";
1610
+ const iamRef = ((_b = exchangeResult.user) == null ? void 0 : _b.reference) || "";
1611
+ const userToStore = {
1612
+ ...baseUser,
1613
+ iam_reference: iamRef,
1614
+ alias_reference: aliasRef
1615
+ };
1616
+ if (aliasRef) {
1617
+ localStorage.setItem(STORAGE.ALIAS_REFERENCE, aliasRef);
1618
+ }
1619
+ const acctType = typeof accountType === "string" ? accountType : "user";
1577
1620
  localStorage.setItem(STORAGE.USER, JSON.stringify(userToStore));
1578
1621
  localStorage.setItem(STORAGE.ACCOUNT_TYPE, acctType);
1579
1622
  return { token: sanctumToken, user: userToStore };
@@ -1583,6 +1626,7 @@ function clearSession() {
1583
1626
  localStorage.removeItem(STORAGE.TOKEN);
1584
1627
  localStorage.removeItem(STORAGE.USER);
1585
1628
  localStorage.removeItem(STORAGE.ACCOUNT_TYPE);
1629
+ localStorage.removeItem(STORAGE.ALIAS_REFERENCE);
1586
1630
  }
1587
1631
  function getErrorMessage$1(err, context) {
1588
1632
  if (err instanceof Error) {
@@ -1597,14 +1641,15 @@ function getErrorMessage$1(err, context) {
1597
1641
  return { message: `Erreur lors de ${context}`, type: "unknown" };
1598
1642
  }
1599
1643
  function useNativeAuth(options) {
1600
- const { saasApiUrl, iamApiUrl, autoLoadCredentials = true, debug = false } = options;
1644
+ const { saasApiUrl, iamApiUrl, autoLoadCredentials = true, defaultAccountType = "user" } = options;
1601
1645
  const configuredRef = react.useRef(false);
1646
+ const debug = isDebugMode();
1602
1647
  react.useEffect(() => {
1603
1648
  if (!configuredRef.current) {
1604
- setNativeAuthConfig({ saasApiUrl, iamApiUrl, debug });
1649
+ setNativeAuthConfig({ saasApiUrl, iamApiUrl });
1605
1650
  configuredRef.current = true;
1606
1651
  }
1607
- }, [saasApiUrl, iamApiUrl, debug]);
1652
+ }, [saasApiUrl, iamApiUrl]);
1608
1653
  const [state, setState] = react.useState({
1609
1654
  credentialsLoaded: false,
1610
1655
  processToken: null,
@@ -1676,6 +1721,23 @@ function useNativeAuth(options) {
1676
1721
  loadCredentials();
1677
1722
  }
1678
1723
  }, [autoLoadCredentials, state.credentialsLoaded, state.user]);
1724
+ react.useEffect(() => {
1725
+ if (state.status === "completed" || !state.credentialsLoaded) return;
1726
+ const ttl = nativeAuthService.getCredentialsTtl();
1727
+ const refreshInterval = Math.max((ttl - 30) * 1e3, 3e4);
1728
+ if (debug) {
1729
+ console.log(`🔄 [Native] Auto-refresh credentials every ${refreshInterval / 1e3}s (TTL: ${ttl}s)`);
1730
+ }
1731
+ const timer = setInterval(async () => {
1732
+ try {
1733
+ await nativeAuthService.loadCredentials();
1734
+ if (debug) console.log("✅ [Native] Credentials auto-refreshed");
1735
+ } catch (err) {
1736
+ if (debug) console.warn("⚠️ [Native] Auto-refresh failed:", err);
1737
+ }
1738
+ }, refreshInterval);
1739
+ return () => clearInterval(timer);
1740
+ }, [state.status, state.credentialsLoaded, debug]);
1679
1741
  const loadCredentials = react.useCallback(async () => {
1680
1742
  setState((prev) => ({ ...prev, loading: true, error: null }));
1681
1743
  try {
@@ -1903,7 +1965,7 @@ function useNativeAuth(options) {
1903
1965
  if (response.success && response.callback_token) {
1904
1966
  const exchangeResult = await nativeAuthService.exchange(response.callback_token);
1905
1967
  if (exchangeResult.success) {
1906
- const { user: savedUser } = saveSession(exchangeResult, accountType);
1968
+ const { user: savedUser } = saveSession(exchangeResult, defaultAccountType);
1907
1969
  setState((prev) => ({
1908
1970
  ...prev,
1909
1971
  status: "completed",
@@ -1964,7 +2026,7 @@ function useNativeAuth(options) {
1964
2026
  if (response.success && response.callback_token) {
1965
2027
  const exchangeResult = await nativeAuthService.exchange(response.callback_token);
1966
2028
  if (exchangeResult.success) {
1967
- const { user: savedUser } = saveSession(exchangeResult, accountType);
2029
+ const { user: savedUser } = saveSession(exchangeResult, defaultAccountType);
1968
2030
  setState((prev) => ({
1969
2031
  ...prev,
1970
2032
  status: "completed",
@@ -2025,7 +2087,7 @@ function useNativeAuth(options) {
2025
2087
  if (response.success && response.callback_token) {
2026
2088
  const exchangeResult = await nativeAuthService.exchange(response.callback_token);
2027
2089
  if (exchangeResult.success) {
2028
- const { user: savedUser } = saveSession(exchangeResult, accountType);
2090
+ const { user: savedUser } = saveSession(exchangeResult, defaultAccountType);
2029
2091
  setState((prev) => ({
2030
2092
  ...prev,
2031
2093
  status: "completed",
@@ -2059,7 +2121,7 @@ function useNativeAuth(options) {
2059
2121
  if (response.success && response.callback_token) {
2060
2122
  const exchangeResult = await nativeAuthService.exchange(response.callback_token);
2061
2123
  if (exchangeResult.success) {
2062
- const { user: savedUser } = saveSession(exchangeResult, accountType);
2124
+ const { user: savedUser } = saveSession(exchangeResult, defaultAccountType);
2063
2125
  setState((prev) => ({
2064
2126
  ...prev,
2065
2127
  status: "completed",
@@ -2104,14 +2166,14 @@ function useNativeAuth(options) {
2104
2166
  }
2105
2167
  }, [state.processToken]);
2106
2168
  const setSession = react.useCallback((data) => {
2107
- const { user: savedUser } = saveSession(data, accountType);
2169
+ const { user: savedUser } = saveSession(data, defaultAccountType);
2108
2170
  setState((prev) => ({
2109
2171
  ...prev,
2110
2172
  user: savedUser,
2111
2173
  status: "completed",
2112
2174
  processToken: null
2113
2175
  }));
2114
- }, [accountType]);
2176
+ }, [defaultAccountType]);
2115
2177
  const logout = react.useCallback(async () => {
2116
2178
  const token = localStorage.getItem(STORAGE.AUTH_TOKEN) || localStorage.getItem(STORAGE.TOKEN);
2117
2179
  try {
@@ -2271,7 +2333,7 @@ function LoginModal({
2271
2333
  iamApiUrl,
2272
2334
  loading,
2273
2335
  showSwitchToSignup = true,
2274
- debug = false
2336
+ defaultAccountType
2275
2337
  }) {
2276
2338
  const {
2277
2339
  status,
@@ -2290,7 +2352,7 @@ function LoginModal({
2290
2352
  setSession,
2291
2353
  reset: resetAuth,
2292
2354
  clearError
2293
- } = useNativeAuth({ saasApiUrl, iamApiUrl, debug });
2355
+ } = useNativeAuth({ saasApiUrl, iamApiUrl, defaultAccountType });
2294
2356
  const [step, setStep] = react.useState("choice");
2295
2357
  const [email, setEmail] = react.useState("");
2296
2358
  const [password, setPassword] = react.useState("");
@@ -2799,8 +2861,7 @@ function LoginModal({
2799
2861
  onOpenChange: setShowPasswordRecovery,
2800
2862
  onSuccess: () => setShowPasswordRecovery(false),
2801
2863
  saasApiUrl,
2802
- iamApiUrl,
2803
- debug
2864
+ iamApiUrl
2804
2865
  }
2805
2866
  )
2806
2867
  ] });
@@ -3058,8 +3119,7 @@ function useMobileRegistration(options) {
3058
3119
  if (options && !configuredRef.current) {
3059
3120
  setNativeAuthConfig({
3060
3121
  saasApiUrl: options.saasApiUrl,
3061
- iamApiUrl: options.iamApiUrl,
3062
- debug: options.debug
3122
+ iamApiUrl: options.iamApiUrl
3063
3123
  });
3064
3124
  configuredRef.current = true;
3065
3125
  }
@@ -3358,7 +3418,7 @@ function SuccessOrbit() {
3358
3418
  })
3359
3419
  ] });
3360
3420
  }
3361
- function SignupModal({ open, onOpenChange, onSwitchToLogin, onSignupSuccess, saasApiUrl, iamApiUrl, debug = false }) {
3421
+ function SignupModal({ open, onOpenChange, onSwitchToLogin, onSignupSuccess, saasApiUrl, iamApiUrl, defaultAccountType }) {
3362
3422
  const {
3363
3423
  status,
3364
3424
  formData,
@@ -3374,7 +3434,7 @@ function SignupModal({ open, onOpenChange, onSwitchToLogin, onSignupSuccess, saa
3374
3434
  resendOtp,
3375
3435
  reset: resetReg,
3376
3436
  clearError
3377
- } = useMobileRegistration({ saasApiUrl, iamApiUrl, debug });
3437
+ } = useMobileRegistration({ saasApiUrl, iamApiUrl });
3378
3438
  const [step, setStep] = react.useState("intro");
3379
3439
  const [otpCode, setOtpCode] = react.useState("");
3380
3440
  const [password, setPassword] = react.useState("");
@@ -4075,7 +4135,7 @@ function NativeSSOPage({
4075
4135
  onLoginSuccess,
4076
4136
  onLogout,
4077
4137
  onOnboardingComplete,
4078
- debug,
4138
+ accountType = "user",
4079
4139
  title = "Un compte, plusieurs accès",
4080
4140
  description = "Connectez-vous avec votre compte Ollaid pour accéder à toutes les applications partenaires.",
4081
4141
  logoUrl,
@@ -4093,7 +4153,7 @@ function NativeSSOPage({
4093
4153
  }
4094
4154
  return null;
4095
4155
  });
4096
- const resolvedDebug = debug !== void 0 ? debug : isDebugMode();
4156
+ const resolvedDebug = isDebugMode();
4097
4157
  react.useEffect(() => {
4098
4158
  const root = document.documentElement;
4099
4159
  const originalValues = {};
@@ -4172,6 +4232,7 @@ function NativeSSOPage({
4172
4232
  localStorage.removeItem(STORAGE.TOKEN);
4173
4233
  localStorage.removeItem(STORAGE.USER);
4174
4234
  localStorage.removeItem(STORAGE.ACCOUNT_TYPE);
4235
+ localStorage.removeItem(STORAGE.ALIAS_REFERENCE);
4175
4236
  setSession(null);
4176
4237
  onLogout == null ? void 0 : onLogout();
4177
4238
  }, [onLogout]);
@@ -4270,7 +4331,7 @@ function NativeSSOPage({
4270
4331
  onLoginSuccess: handleLoginSuccess,
4271
4332
  saasApiUrl,
4272
4333
  iamApiUrl,
4273
- debug: resolvedDebug
4334
+ defaultAccountType: accountType
4274
4335
  }
4275
4336
  ),
4276
4337
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -4284,7 +4345,7 @@ function NativeSSOPage({
4284
4345
  onSignupSuccess: handleLoginSuccess,
4285
4346
  saasApiUrl,
4286
4347
  iamApiUrl,
4287
- debug: resolvedDebug
4348
+ defaultAccountType: accountType
4288
4349
  }
4289
4350
  ),
4290
4351
  pendingSession && /* @__PURE__ */ jsxRuntime.jsx(