@ollaid/native-sso 2.5.0 → 2.6.0

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.
Files changed (40) hide show
  1. package/README.md +229 -43
  2. package/dist/components/AvatarCropModal.d.ts +1 -1
  3. package/dist/components/DebugPanel.d.ts +1 -1
  4. package/dist/components/LoginModal.d.ts +1 -1
  5. package/dist/components/NativeSSOPage.d.ts +4 -2
  6. package/dist/components/OnboardingModal.d.ts +1 -1
  7. package/dist/components/PasswordRecoveryModal.d.ts +1 -1
  8. package/dist/components/SignupModal.d.ts +1 -1
  9. package/dist/components/ui.d.ts +1 -1
  10. package/dist/hooks/useLogout.d.ts +1 -1
  11. package/dist/hooks/useMobilePassword.d.ts +1 -1
  12. package/dist/hooks/useMobileRegistration.d.ts +2 -2
  13. package/dist/hooks/useNativeAuth.d.ts +8 -5
  14. package/dist/hooks/useTokenHealthCheck.d.ts +1 -1
  15. package/dist/index-Bpixveaz.js +489 -0
  16. package/dist/index-Bpixveaz.js.map +1 -0
  17. package/dist/index-DDOXM37y.cjs +488 -0
  18. package/dist/index-DDOXM37y.cjs.map +1 -0
  19. package/dist/index.cjs +7118 -184
  20. package/dist/index.cjs.map +1 -1
  21. package/dist/index.d.ts +4 -3
  22. package/dist/index.js +7118 -184
  23. package/dist/index.js.map +1 -1
  24. package/dist/provider.d.ts +4 -1
  25. package/dist/services/api.d.ts +52 -10
  26. package/dist/services/debugLogger.d.ts +1 -1
  27. package/dist/services/iamAccount.d.ts +1 -1
  28. package/dist/services/mobilePassword.d.ts +1 -1
  29. package/dist/services/mobileRegistration.d.ts +1 -1
  30. package/dist/services/nativeAuth.d.ts +1 -1
  31. package/dist/services/profile.d.ts +1 -1
  32. package/dist/services/profileChange.d.ts +1 -1
  33. package/dist/services/profileMedia.d.ts +1 -1
  34. package/dist/types/mobile.d.ts +1 -1
  35. package/dist/types/native.d.ts +1 -1
  36. package/dist/web-BQDVoI6q.cjs +146 -0
  37. package/dist/web-BQDVoI6q.cjs.map +1 -0
  38. package/dist/web-DPmAPlXS.js +146 -0
  39. package/dist/web-DPmAPlXS.js.map +1 -0
  40. package/package.json +10 -3
package/README.md CHANGED
@@ -21,14 +21,16 @@ Package NPM Frontend-First pour l'authentification Native SSO Ollaid.
21
21
  12. [Configuration .env Laravel](#configuration-env-laravel)
22
22
  13. [Migration Laravel](#migration-laravel)
23
23
  14. [Flux d'authentification](#flux-dauthentification)
24
- 15. [Session & localStorage](#session--localstorage)
24
+ 15. [Session & storage](#session--storage)
25
25
  16. [Déconnexion synchronisée](#déconnexion-synchronisée)
26
26
  17. [OnboardingModal](#onboardingmodal)
27
27
  18. [useTokenHealthCheck](#usetokenhealthcheck)
28
28
  19. [Sécurité](#sécurité)
29
29
  20. [Exports](#exports)
30
- 21. [Publication & Installation npm](#publication--installation-npm)
31
- 22. [Webhooks & Health Check (Backend)](#webhooks--health-check-backend)
30
+ 21. [Publication & Installation npm](#publication--installation-npm)
31
+ 22. [Webhooks & Health Check (Backend)](#webhooks--health-check-backend)
32
+ 23. [Migration sécurité Web / Capacitor](#migration-sécurité-web--capacitor)
33
+ 24. [Métadonnées device](#métadonnées-device)
32
34
 
33
35
  ---
34
36
 
@@ -38,6 +40,69 @@ Package NPM Frontend-First pour l'authentification Native SSO Ollaid.
38
40
  npm install @ollaid/native-sso
39
41
  ```
40
42
 
43
+ ### Compatibilité Capacitor
44
+
45
+ Le package détecte les métadonnées device via `@capacitor/device` quand l'app consommatrice est une app Capacitor.
46
+
47
+ - Capacitor 7: installez `@capacitor/device@^7.x`
48
+ - Capacitor 8: installez `@capacitor/device@^8.x`
49
+
50
+ Le package déclare `@capacitor/device` comme **peer dependency optionnelle**. Il ne force donc pas une version unique pour tous les SaaS intégrateurs.
51
+
52
+ Par défaut, le package chiffre les données persistées dans `localStorage` avec un wrapper interne. Si votre app fournit un `storage` natif plus robuste, il sera utilisé à la place.
53
+
54
+ ## Métadonnées device
55
+
56
+ Sur les nouvelles connexions, le package envoie automatiquement au backend SaaS les informations utiles pour identifier la session:
57
+
58
+ - `X-Device-Id`
59
+ - `X-Session-UUID`
60
+ - `X-Device-Name`
61
+ - `X-Device-Model`
62
+ - `X-Device-Manufacturer`
63
+ - `X-Device-Operating-System`
64
+ - `X-Device-Os-Version`
65
+ - `X-Device-Platform`
66
+ - `X-Device-Browser`
67
+ - `X-Device-Language`
68
+ - `X-Device-WebView-Version`
69
+ - `X-Device-Is-Native`
70
+ - `X-Device-Label`
71
+
72
+ Ces données servent à enrichir l'affichage backoffice et à rendre les sessions plus lisibles. Elles ne remplacent pas la géolocalisation IP côté backend, qui reste responsable de `city / region / country`.
73
+
74
+ ## Migration sécurité Web / Capacitor
75
+
76
+ Cette section répond à la question la plus importante pour une montée de version en production :
77
+
78
+ - **Installer le nouveau package suffit-il ?**
79
+ - **Oui** pour les changements purement frontend qui gardent le même contrat API.
80
+ - **Non** pour les durcissements de sécurité qui changent le stockage de session, les cookies, ou la synchronisation backend.
81
+
82
+ - **Faut-il aussi modifier le SaaS ?**
83
+ - **Oui** si vous voulez appliquer les recommandations de sécurité de cet audit.
84
+ - **Oui** également si vous voulez une vraie stratégie différente entre **Web** et **Capacitor**.
85
+
86
+ ### Règle simple
87
+
88
+ | Cas | Action |
89
+ |---|---|
90
+ | Mise à jour UI / corrections sans changement de contrat | Installer la nouvelle version du package suffit généralement |
91
+ | Sécurité Web avec cookies HttpOnly | Il faut aussi mettre à jour le backend SaaS |
92
+ | Sécurité Capacitor / mobile natif | Il faut adapter le SaaS et l'app mobile, pas seulement le package |
93
+ | Anti-rejeu webhook / durcissement IAM | Il faut modifier le backend SaaS et parfois l'IAM |
94
+
95
+ ### Recommandation de déploiement
96
+
97
+ 1. Garder la version actuelle compatible en prod.
98
+ 2. Ajouter les migrations backend requises avant d'activer les nouvelles règles de sécurité.
99
+ 3. Déployer le nouveau package sur un environnement de test.
100
+ 4. Vérifier séparément les parcours :
101
+ - Web
102
+ - Capacitor iOS
103
+ - Capacitor Android
104
+ 5. Basculer en production seulement après validation des webhooks, logout et refresh.
105
+
41
106
  ---
42
107
 
43
108
  ## Intégration rapide (3 étapes)
@@ -90,7 +155,7 @@ La page `/auth/native-sso` gère automatiquement :
90
155
  - ✅ Récupération de mot de passe
91
156
  - ✅ Grant access (inscription auto à une nouvelle app)
92
157
  - ✅ 2FA (TOTP)
93
- - ✅ Session persistée en localStorage
158
+ - ✅ Session persistée via le storage configuré, par défaut `localStorage`
94
159
  - ✅ Branding Ollaid SSO
95
160
 
96
161
  ---
@@ -101,10 +166,11 @@ La page `/auth/native-sso` gère automatiquement :
101
166
  |------|------|--------|-------------|
102
167
  | `saasApiUrl` | `string` | ✅ | URL du backend SaaS (ex: `https://mon-saas.com/api`) |
103
168
  | `iamApiUrl` | `string` | ✅ | URL du backend IAM (ex: `https://identityam.ollaid.com/api`) |
104
- | `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. |
169
+ | `accountType` | `'user' \| 'client'` | ❌ | Type de compte à persister dans le storage configuré (défaut: `'user'`). Utile si vous avez plusieurs pages SSO avec des rôles différents. |
105
170
  | `configPrefix` | `string` | ❌ | **Multi-tenant** : préfixe de configuration IAM côté backend (défaut: `'iam'`). Permet à un même backend SaaS de gérer N applications IAM. Voir [Multi-Tenant](#multi-tenant-plusieurs-applications-sur-le-même-backend). |
106
171
  | `onLoginSuccess` | `(token: string, user: UserInfos) => void` | ❌ | Callback après connexion réussie |
107
172
  | `onLogout` | `() => void` | ❌ | Callback après déconnexion |
173
+ | `storage` | `NativeStorageAdapter` | ❌ | Stockage injecté pour WebView / Capacitor / secure storage natif. Si absent, le package utilise un `localStorage` chiffré puis un fallback mémoire. |
108
174
  | `title` | `string` | ❌ | Titre personnalisé (défaut: "Un compte pour toutes vos applications") |
109
175
  | `description` | `string` | ❌ | Description personnalisée |
110
176
  | `logoUrl` | `string` | ❌ | URL du logo (remplace le slider) |
@@ -115,6 +181,8 @@ La page `/auth/native-sso` gère automatiquement :
115
181
 
116
182
  > **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. Le `DebugPanel` est **réactif** : il apparaît automatiquement après le chargement des credentials si `debug: true` est retourné par le backend.
117
183
  > Quand le `DebugPanel` est visible, il expose aussi des boutons de test pour ouvrir `Connexion`, `Inscription`, `Infos profile` et un reset du rappel profil.
184
+ >
185
+ > **Note Capacitor** : si votre app mobile utilise un secure storage natif, fournissez un adapter via `storage` afin d'aller au-delà du `localStorage` chiffré par défaut du package.
118
186
 
119
187
  ### Redirections automatiques (optionnel)
120
188
 
@@ -175,9 +243,9 @@ const handleLogout = async () => {
175
243
 
176
244
  ### Que fait `logout()` ?
177
245
 
178
- 1. **Révoque le token SaaS** — `POST /api/native/logout` (supprime le Sanctum token)
179
- 2. **Révoque la session IAM** — `POST /api/iam/disconnect` (avec `sanctum_token` + `app_access_token_ref`)
180
- 3. **Nettoie le localStorage** — supprime les clés de session du package
246
+ 1. **Révoque la session SaaS** — `POST /api/native/logout`
247
+ 2. **Révoque la session IAM** — `POST /api/iam/disconnect` (avec `app_access_token_ref`)
248
+ 3. **Nettoie le stockage local** — supprime les clés de session du package
181
249
 
182
250
  Les appels réseau sont en `Promise.allSettled` (best-effort) : même si le serveur est injoignable, le localStorage est **toujours** nettoyé.
183
251
 
@@ -185,7 +253,7 @@ Les appels réseau sont en `Promise.allSettled` (best-effort) : même si le serv
185
253
 
186
254
  | Clé | Description |
187
255
  |-----|-------------|
188
- | `auth_token` | Token Sanctum actif |
256
+ | `auth_token` | Token de session SaaS actif |
189
257
  | `token` | Token legacy |
190
258
  | `user` | Objet utilisateur (avec `iam_reference`, `alias_reference`) |
191
259
  | `account_type` | Type de compte (`user` ou `client`) |
@@ -381,9 +449,27 @@ class NativeConfigController extends Controller
381
449
 
382
450
  > **⚠️ Important** : Appliquez la même logique `X-IAM-Config-Prefix` dans `exchange`, `check-token`, `refresh` et `logout`.
383
451
 
384
- Le package envoie aussi :
452
+ ## Device metadata & session identity
453
+
454
+ Le package envoie automatiquement des headers de contexte device sur les requêtes d'authentification et de session :
455
+
385
456
  - `X-Device-Id` (stable par appareil / webview)
386
457
  - `X-Session-UUID` (UUID stable par instance, pour différencier plusieurs sessions sur un même device)
458
+ - `X-Device-Name`
459
+ - `X-Device-Model`
460
+ - `X-Device-Manufacturer`
461
+ - `X-Device-Operating-System`
462
+ - `X-Device-Os-Version`
463
+ - `X-Device-Platform`
464
+ - `X-Device-Browser`
465
+ - `X-Device-Language`
466
+ - `X-Device-WebView-Version`
467
+ - `X-Device-Is-Native`
468
+ - `X-Device-Label`
469
+
470
+ Ces valeurs servent à enrichir la session IAM et l'affichage backoffice. Elles sont utiles pour la traçabilité, mais ne doivent pas être utilisées comme preuve d'identité ou comme facteur d'autorisation à elles seules.
471
+
472
+ > **Note** : la géolocalisation `city / region / country` n'est pas fournie par le package. Elle est calculée côté backend à partir de l'IP observée.
387
473
 
388
474
  ---
389
475
 
@@ -424,6 +510,14 @@ php artisan config:clear
424
510
  php artisan config:cache
425
511
  ```
426
512
 
513
+ ### Sécurité et stockage
514
+
515
+ - Les métadonnées device sont du contexte, pas des secrets.
516
+ - Les tokens d'authentification doivent rester dans un stockage adapté à votre plateforme.
517
+ - Sur Capacitor, utilisez un secure storage natif si vous manipulez des données sensibles longue durée.
518
+ - Ne déduisez jamais les droits utilisateur à partir des seuls headers device.
519
+ - Le package fournit désormais un socle fiable d'identité de session pour les nouvelles connexions; les seules variations restantes viennent du contexte réseau ou du terminal exposé par l'environnement, pas du flux SSO lui-même.
520
+
427
521
  ---
428
522
 
429
523
  ## Usage avancé (composants individuels)
@@ -1204,7 +1298,6 @@ class NativeAuthController extends Controller
1204
1298
  $user = $request->user();
1205
1299
 
1206
1300
  if ($user) {
1207
- $sanctumTokenPlain = $request->bearerToken();
1208
1301
  $currentToken = $user->currentAccessToken();
1209
1302
  $appAccessTokenRef = $currentToken?->app_access_token_ref ?? null;
1210
1303
 
@@ -1212,14 +1305,13 @@ class NativeAuthController extends Controller
1212
1305
  $currentToken?->delete();
1213
1306
 
1214
1307
  // Notifier l'IAM (fire-and-forget, timeout 5s)
1215
- if ($sanctumTokenPlain || $appAccessTokenRef) {
1308
+ if ($appAccessTokenRef) {
1216
1309
  $iamPrefix = $request->attributes->get('iam_prefix', 'iam');
1217
1310
  $iamApiUrl = config("services.{$iamPrefix}.api_url", 'https://identityam.ollaid.com/api');
1218
1311
  try {
1219
- Http::timeout(5)->post("{$iamApiUrl}/iam/disconnect", array_filter([
1220
- 'sanctum_token' => $sanctumTokenPlain,
1312
+ Http::timeout(5)->post("{$iamApiUrl}/iam/disconnect", [
1221
1313
  'app_access_token_ref' => $appAccessTokenRef,
1222
- ]));
1314
+ ]);
1223
1315
  } catch (\Exception $e) {
1224
1316
  Log::warning("[NativeSSO] IAM disconnect failed (non-blocking)", ['error' => $e->getMessage()]);
1225
1317
  }
@@ -1952,36 +2044,62 @@ Toutes les APIs IAM retournent le même objet `user_infos` avec exactement **9 c
1952
2044
 
1953
2045
  ---
1954
2046
 
1955
- ## Session & localStorage
2047
+ ## Session & storage
1956
2048
 
1957
- Le package utilise **9 clés** dans `localStorage` pour persister la session et le suivi du profil :
2049
+ Par défaut, le package utilise un petit ensemble de clés préfixées `sso_` dans `localStorage` pour persister la session et le suivi du profil.
2050
+ Vous pouvez injecter un `storage` différent via `NativeSSOPage`, `NativeSSOProvider`, `useNativeAuth` ou `setNativeStorage()`.
1958
2051
 
1959
2052
  | Clé | Contenu | Source | Valeurs possibles |
1960
2053
  |-----|---------|--------|-------------------|
1961
- | `token` | Token Sanctum (bearer) | Réponse de `/api/native/exchange` | Chaîne `"1\|abc123..."` |
1962
- | `auth_token` | Copie du token (compatibilité) | Même source que `token` | Idem |
1963
- | `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":"...",...}` |
1964
- | `account_type` | Type de compte | Déterminé lors du `exchange` selon le mode d'inscription | `"user"` (défaut) ou `"client"` (inscription phone-only) |
1965
- | `alias_reference` | Référence alias utilisée lors de la connexion | Réponse de `/api/native/exchange` (champ `user.alias_reference`) | `"ALI-XXXXXXXX"` |
1966
- | `app_access_token_ref` | Référence de l'`AppAccessToken` IAM | Réponse de `/api/native/exchange` (champ `app_access_token_ref`) | `"42"` ou `"aat_ref_abc123"` |
2054
+ | `sso_auth_token` | Token Sanctum (bearer) canonique | Réponse de `/api/native/exchange` | Chaîne `"1\|abc123..."` |
2055
+ | `sso_token` | Alias rétrocompatible en lecture | Même source que `sso_auth_token` | Idem |
2056
+ | `sso_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":"...",...}` |
2057
+ | `sso_account_type` | Type de compte | Déterminé lors du `exchange` selon le mode d'inscription | `"user"` (défaut) ou `"client"` (inscription phone-only) |
2058
+ | `sso_alias_reference` | Référence alias utilisée lors de la connexion | Réponse de `/api/native/exchange` (champ `user.alias_reference`) | `"ALI-XXXXXXXX"` |
2059
+ | `sso_app_access_token_ref` | Référence de l'`AppAccessToken` IAM | Réponse de `/api/native/exchange` (champ `app_access_token_ref`) | `"42"` ou `"aat_ref_abc123"` |
2060
+ | `sso_device_id` | Identifiant stable de l'appareil | Généré par le package | Chaîne stable |
2061
+ | `sso_session_uuid` | UUID stable de la session | Généré par le package | UUID |
1967
2062
  | `sso_image_last_status` | Statut du dernier onboarding profil | Mis à jour par `OnboardingModal` | `"true"` ou `"false"` |
1968
2063
  | `sso_image_last_check` | Timestamp du dernier contrôle profil | Mis à jour par `OnboardingModal` / sync profil | Millisecondes Unix |
1969
2064
  | `sso_image_recheck_at` | Timestamp de rappel après snooze | Mis à jour quand l'utilisateur passe l'onboarding | Millisecondes Unix |
1970
2065
 
1971
- > **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`.
1972
- > **Note :** `sso_image_last_status`, `sso_image_last_check` et `sso_image_recheck_at` vivent dans le `localStorage` du SaaS et servent au rappel d'onboarding du profil.
2066
+ > **Note :** `sso_account_type` et `sso_alias_reference` sont stockés **séparément** de l'objet `user` en plus d'être inclus dans le JSON de `sso_user`.
2067
+ > **Note :** `sso_image_last_status`, `sso_image_last_check` et `sso_image_recheck_at` vivent dans le storage configuré du SaaS et servent au rappel d'onboarding du profil.
2068
+ > **Note sécurité :** la règle d’activité doit être gérée côté backend avec `last_active_at`. Si `last_active_at` dépasse 6 mois, la session doit être révoquée côté SaaS puis côté IAM.
1973
2069
 
1974
2070
  #### Champs enrichis dans l'objet `user`
1975
2071
 
1976
- L'objet `user` stocké en localStorage contient deux champs ajoutés automatiquement par le package :
2072
+ L'objet `user` stocké dans `sso_user` contient deux champs ajoutés automatiquement par le package :
1977
2073
  - `iam_reference` : la référence IAM de l'utilisateur (`USR-XXXXXXXX`), extraite de `user.reference`
1978
2074
  - `alias_reference` : la référence de l'alias utilisé lors de la connexion (`ALI-XXXXXXXX`), extraite de `user.alias_reference`
1979
2075
 
1980
2076
  ### Nettoyage
1981
2077
 
1982
- Lors du `logout()`, les 6 clés de session sont supprimées via `clearAuthToken()`.
2078
+ Lors du `logout()`, les clés de session sont supprimées via `clearAuthToken()`.
1983
2079
  Les clés de rappel profil (`sso_image_*`) ne sont pas effacées, afin de conserver le comportement de relance après snooze.
1984
2080
 
2081
+ ### API locale pour le frontend hôte
2082
+
2083
+ Quand votre frontend SaaS a besoin d'un état de session, il doit appeler le package au lieu de lire les clés du storage directement.
2084
+
2085
+ ```ts
2086
+ import { getSsoSessionSnapshot } from '@ollaid/native-sso';
2087
+
2088
+ const session = getSsoSessionSnapshot();
2089
+ // {
2090
+ // authToken,
2091
+ // refreshToken,
2092
+ // appAccessTokenRef,
2093
+ // aliasReference,
2094
+ // accountType,
2095
+ // deviceId,
2096
+ // sessionUuid,
2097
+ // user
2098
+ // }
2099
+ ```
2100
+
2101
+ Cette API retourne les valeurs déchiffrées par le package et évite au frontend hôte de dépendre du détail des clés `sso_`.
2102
+
1985
2103
  ### Accès programmatique
1986
2104
 
1987
2105
  ```ts
@@ -1993,6 +2111,28 @@ const type = getAccountType(); // string | null
1993
2111
  const aliasRef = localStorage.getItem('alias_reference'); // string | null
1994
2112
  ```
1995
2113
 
2114
+ ### Accès via l'API locale du package
2115
+
2116
+ Le frontend SaaS doit utiliser l'API locale du package pour récupérer l'état SSO, au lieu de lire le storage directement.
2117
+
2118
+ ```ts
2119
+ import { getSsoSessionSnapshot, hasSsoSession } from '@ollaid/native-sso';
2120
+
2121
+ const session = getSsoSessionSnapshot();
2122
+
2123
+ if (hasSsoSession()) {
2124
+ console.log(session.authToken);
2125
+ console.log(session.refreshToken);
2126
+ console.log(session.appAccessTokenRef);
2127
+ console.log(session.aliasReference);
2128
+ console.log(session.deviceId);
2129
+ console.log(session.sessionUuid);
2130
+ console.log(session.user);
2131
+ }
2132
+ ```
2133
+
2134
+ Cette API retourne les valeurs déchiffrées et garde le détail des clés `sso_` encapsulé dans le package.
2135
+
1996
2136
  ---
1997
2137
 
1998
2138
  ## Déconnexion synchronisée
@@ -2007,7 +2147,7 @@ Le package implémente une **double revocation** ultra-fiable : il contacte **en
2007
2147
  │ logout() │ │
2008
2148
  └──────┬──────────┘ │
2009
2149
  │ ① POST /native/logout │ ② POST /iam/disconnect
2010
- │ (Sanctum token) │ (sanctum_token + app_access_token_ref)
2150
+ │ (Sanctum token) │ (app_access_token_ref)
2011
2151
  ▼ ▼
2012
2152
  ┌─────────────────┐ ┌─────────────────┐
2013
2153
  │ SaaS API │──③ fire-and-forget──────▶│ IAM API │
@@ -2029,9 +2169,9 @@ Le package implémente une **double revocation** ultra-fiable : il contacte **en
2029
2169
  Quand `useNativeAuth.logout()` est appelé (ou que l'utilisateur clique "Se déconnecter" dans `NativeSSOPage`) :
2030
2170
 
2031
2171
  1. **Appels parallèles** (via `Promise.allSettled`, jamais bloquants) :
2032
- - `POST /api/native/logout` → SaaS supprime le Sanctum token + notifie l'IAM (fire-and-forget)
2033
- - `POST /api/iam/disconnect` → IAM révoque directement l'`AppAccessToken` via `sanctum_token` + `app_access_token_ref` (lookup optimisé)
2034
- 2. **Nettoyage local garanti** : les 6 clés localStorage sont supprimées (`token`, `auth_token`, `user`, `account_type`, `alias_reference`, `app_access_token_ref`)
2172
+ - `POST /api/native/logout` → SaaS révoque sa session locale
2173
+ - `POST /api/iam/disconnect` → IAM révoque directement l'`AppAccessToken` via `app_access_token_ref`
2174
+ 2. **Nettoyage local garanti** : les clés de session sont supprimées (`auth_token`, `token`, `user`, `account_type`, `alias_reference`, `app_access_token_ref`)
2035
2175
  3. **Aucun blocage** : même si les deux appels échouent (offline, timeout), la déconnexion locale est instantanée
2036
2176
 
2037
2177
  > **Fiabilité** : `Promise.allSettled` + `.catch()` sur chaque appel. L'appel IAM a un timeout court (5s) pour ne jamais ralentir l'UX.
@@ -2042,10 +2182,9 @@ Le package contacte directement l'IAM pour révoquer l'`AppAccessToken` lié à
2042
2182
 
2043
2183
  | Paramètre | Type | Description |
2044
2184
  |-----------|------|-------------|
2045
- | `sanctum_token` | `string` | Le token Sanctum stocké localement, utilisé pour identifier l'`AppAccessToken` à révoquer |
2046
- | `app_access_token_ref` | `string` | (recommandé) Référence directe de l'`AppAccessToken` IAM — lookup instantané par PK |
2185
+ | `app_access_token_ref` | `string` | Référence directe de l'`AppAccessToken` IAM lookup instantané par PK |
2047
2186
 
2048
- L'IAM cherche d'abord par `app_access_token_ref` (lookup par PK, O(1)), puis fallback sur `sanctum_token` (index), puis `iam_token` (hash). Le passage de `app_access_token_ref` est **recommandé** pour des performances optimales.
2187
+ L'IAM cherche par `app_access_token_ref` (lookup par PK, O(1)).
2049
2188
 
2050
2189
  ### Déconnexion externe (hors package)
2051
2190
 
@@ -2065,8 +2204,8 @@ navigate('/auth/login');
2065
2204
 
2066
2205
  `logout()` effectue automatiquement :
2067
2206
  1. `POST /api/native/logout` → révoque le Sanctum token
2068
- 2. `POST /api/iam/disconnect` → révoque l'AppAccessToken IAM (avec `sanctum_token` + `app_access_token_ref`)
2069
- 3. `clearAuthToken()` → nettoie les 6 clés localStorage
2207
+ 2. `POST /api/iam/disconnect` → révoque l'AppAccessToken IAM via `app_access_token_ref`
2208
+ 3. `clearAuthToken()` → nettoie les clés de session
2070
2209
 
2071
2210
  ### Hook `useLogout()` (recommandé pour React)
2072
2211
 
@@ -2106,14 +2245,14 @@ const LogoutButton = () => {
2106
2245
 
2107
2246
  ### Détection automatique des sessions révoquées
2108
2247
 
2109
- Le [health check](#usetokenhealthcheck) (toutes les 2 min) détecte automatiquement si un token a été révoqué côté SaaS (par un admin, par la limite de sessions, etc.). Si le serveur répond `401`, le package **révoque aussi l'IAM** (`POST /api/iam/disconnect` avec `sanctum_token` + `app_access_token_ref`) puis déconnecte proprement l'utilisateur.
2248
+ Le [health check](#usetokenhealthcheck) (toutes les 2 min) détecte automatiquement si un token a été révoqué côté SaaS (par un admin, par la limite de sessions, etc.). Si le serveur répond `401`, le package **révoque aussi l'IAM** (`POST /api/iam/disconnect` avec `app_access_token_ref`) puis déconnecte proprement l'utilisateur.
2110
2249
 
2111
2250
  > **Important** : seul un `401` explicite déclenche la déconnexion automatique. Les erreurs réseau ou serveur (5xx) ne déclenchent **pas** de déconnexion pour éviter les déconnexions intempestives.
2112
2251
 
2113
2252
  ### Prérequis backend
2114
2253
 
2115
- 1. Votre endpoint `POST /api/native/logout` **doit** notifier l'IAM après avoir supprimé le token Sanctum (voir [BACKEND_INTEGRATION.md](./BACKEND_INTEGRATION.md))
2116
- 2. L'IAM **doit** exposer `POST /api/iam/disconnect` acceptant `{ sanctum_token, app_access_token_ref }` pour la revocation directe par le package
2254
+ 1. Votre endpoint `POST /api/native/logout` **doit** révoquer la session SaaS locale et peut notifier l'IAM de manière best-effort après avoir récupéré `app_access_token_ref` (voir [BACKEND_INTEGRATION.md](./BACKEND_INTEGRATION.md))
2255
+ 2. L'IAM **doit** exposer `POST /api/iam/disconnect` acceptant `{ app_access_token_ref }`
2117
2256
 
2118
2257
  ---
2119
2258
 
@@ -2271,8 +2410,8 @@ Hook qui vérifie périodiquement la validité du token Sanctum via `POST /api/n
2271
2410
 
2272
2411
  Quand le SaaS retourne un 401 (token révoqué par un admin, session expirée, etc.) :
2273
2412
 
2274
- 1. **Appel IAM** — Le package appelle `POST /api/iam/disconnect` avec `sanctum_token` + `app_access_token_ref` (fire-and-forget, 5s timeout) pour révoquer l'`AppAccessToken` correspondant
2275
- 2. **Nettoyage localStorage** — Les 6 clés de session sont supprimées
2413
+ 1. **Appel IAM** — Le package appelle `POST /api/iam/disconnect` avec `app_access_token_ref` (fire-and-forget, 5s timeout) pour révoquer l'`AppAccessToken` correspondant
2414
+ 2. **Nettoyage localStorage** — Les clés de session sont supprimées
2276
2415
  3. **Réinitialisation de l'état** — L'interface revient à l'écran de connexion
2277
2416
 
2278
2417
  > **Philosophie** : Ne déconnecter que sur un rejet explicite du serveur (401). Jamais sur un problème réseau.
@@ -2340,13 +2479,57 @@ if (config('services.iam.debug')) {
2340
2479
 
2341
2480
  ### Bonnes pratiques
2342
2481
 
2343
- - ✅ Le token Sanctum est stocké en `localStorage` (standard pour SPA)
2482
+ - ✅ Le token Sanctum est stocké via le storage configuré, par défaut `localStorage`
2344
2483
  - ✅ Les credentials IAM sont gardés **en mémoire uniquement** (jamais persistés)
2345
2484
  - ✅ Le device ID est un identifiant aléatoire (pas de fingerprinting invasif)
2346
2485
  - ✅ Le logout est single-session (ne déconnecte pas les autres appareils)
2347
2486
  - ✅ Le health check ne déconnecte que sur 401 explicite
2348
2487
  - ✅ Les photos sont validées à 2 Mo max côté client
2349
- - ✅ Les lectures `localStorage` sont protégées par try/catch
2488
+ - ✅ Les lectures storage sont protégées par try/catch
2489
+
2490
+ ---
2491
+
2492
+ ## Migration sécurité Web / Capacitor
2493
+
2494
+ Cette section résume l'impact réel d'une mise à niveau en production.
2495
+
2496
+ ### Est-ce qu'un simple `npm install` suffit ?
2497
+
2498
+ - **Oui**, si vous ne changez que des comportements frontend compatibles avec le contrat actuel.
2499
+ - **Non**, si vous voulez appliquer les recommandations de sécurité de l'audit ou changer le stockage de session.
2500
+
2501
+ ### Est-ce qu'il faut modifier les SaaS ?
2502
+
2503
+ Oui dans les cas suivants :
2504
+
2505
+ - passage à des cookies HttpOnly côté Web
2506
+ - durcissement du logout et du refresh
2507
+ - ajout de l'anti-rejeu sur les webhooks
2508
+ - durcissement de la gestion des redirections
2509
+ - stratégie différente pour Capacitor / mobile natif
2510
+
2511
+ ### Règle simple
2512
+
2513
+ | Cas | Action |
2514
+ |---|---|
2515
+ | Correction UI sans changement de contrat | Installer la nouvelle version du package suffit généralement |
2516
+ | Sécurité Web | Mettre à jour le package **et** le backend SaaS |
2517
+ | Sécurité Capacitor / mobile | Mettre à jour le package **et** l'application mobile, parfois aussi le backend SaaS |
2518
+ | Anti-rejeu webhook / intégrité crypto | Mettre à jour le backend SaaS et l'IAM |
2519
+
2520
+ ### Compatibilité Web / Capacitor
2521
+
2522
+ - **Web** : `localStorage` fonctionne techniquement, mais ce n'est pas le modèle le plus sûr.
2523
+ - **Capacitor / WebView** : `localStorage` n'est pas un coffre-fort. Si vous avez besoin d'une sécurité plus forte, utilisez un stockage natif sécurisé ou évitez de conserver des secrets longue durée dans le WebView.
2524
+ - **Conclusion** : le package reste compatible avec les deux environnements, mais la stratégie de persistance de session doit être adaptée côté application consommatrice.
2525
+
2526
+ ### Ordre de déploiement recommandé
2527
+
2528
+ 1. Déployer les migrations backend nécessaires.
2529
+ 2. Mettre à jour le package npm.
2530
+ 3. Tester le Web.
2531
+ 4. Tester Capacitor iOS et Android.
2532
+ 5. Activer la nouvelle stratégie de sécurité en production.
2350
2533
 
2351
2534
  ---
2352
2535
 
@@ -2376,6 +2559,9 @@ if (config('services.iam.debug')) {
2376
2559
  - `nativeAuthService` — Service d'authentification
2377
2560
  - `mobilePasswordService` — Service mot de passe
2378
2561
  - `setNativeAuthConfig` — Configuration manuelle des URLs
2562
+ - `getSsoSessionSnapshot` — Snapshot local déchiffré de la session
2563
+ - `hasSsoSession` — Vérifie si une session SSO locale existe
2564
+ - `setNativeStorage` / `getNativeStorage` — Injection du storage session pour WebView / Capacitor / secure storage natif
2379
2565
  - `iamAccountService` — Service APIs IAM Account (link-phone, link-email, refresh-user-info, update-avatar, reset-avatar)
2380
2566
  - `logout` — Déconnexion complète (double révocation SaaS + IAM + nettoyage localStorage)
2381
2567
  - `getAuthToken` — Récupérer le token depuis localStorage
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Version réécrite from scratch pour éviter les états qui bloquent le bouton Valider.
5
5
  *
6
- * @version 2.5.0
6
+ * @version 2.6.0
7
7
  */
8
8
  export interface AvatarCropModalProps {
9
9
  open: boolean;
@@ -2,7 +2,7 @@
2
2
  * DebugPanel — Panneau de debug flottant pour @ollaid/native-sso
3
3
  * Affiche l'historique des appels API en temps réel (style terminal)
4
4
  * N'apparaît que quand debug=true
5
- * @version 2.5.0
5
+ * @version 2.6.0
6
6
  */
7
7
  export type DebugOnboardingPreset = 'current' | 'photo' | 'phone' | 'email' | 'all';
8
8
  interface DebugPanelProps {
@@ -2,7 +2,7 @@
2
2
  * Login Modal for @ollaid/native-sso
3
3
  * Complete login flow aligned with Native SSO design
4
4
  *
5
- * @version 2.5.0
5
+ * @version 2.6.0
6
6
  */
7
7
  import type { UserInfos } from '../types/native';
8
8
  export interface LoginModalProps {
@@ -2,9 +2,10 @@
2
2
  * NativeSSOPage — Page autonome complète pour @ollaid/native-sso
3
3
  * Design aligné sur le parcours Native SSO (fond primary, card blanche, ShieldCheck branding)
4
4
  *
5
- * @version 2.5.0
5
+ * @version 2.6.0
6
6
  */
7
7
  import type { UserInfos } from '../types/native';
8
+ import type { NativeStorageAdapter } from '../services/api';
8
9
  export interface NativeSSOPageProps {
9
10
  saasApiUrl: string;
10
11
  iamApiUrl: string;
@@ -29,6 +30,7 @@ export interface NativeSSOPageProps {
29
30
  hideFooter?: boolean;
30
31
  redirectAfterLogin?: string;
31
32
  redirectAfterLogout?: string;
33
+ storage?: NativeStorageAdapter;
32
34
  }
33
- export declare function NativeSSOPage({ saasApiUrl, iamApiUrl, onLoginSuccess, onLogout, onOnboardingComplete, accountType, configPrefix, title, description, logoUrl, hideFooter, redirectAfterLogin, redirectAfterLogout, }: NativeSSOPageProps): import("react/jsx-runtime").JSX.Element;
35
+ export declare function NativeSSOPage({ saasApiUrl, iamApiUrl, onLoginSuccess, onLogout, onOnboardingComplete, accountType, configPrefix, title, description, logoUrl, hideFooter, redirectAfterLogin, redirectAfterLogout, storage, }: NativeSSOPageProps): import("react/jsx-runtime").JSX.Element;
34
36
  export default NativeSSOPage;
@@ -3,7 +3,7 @@
3
3
  * Mode `missing` : champs absents uniquement
4
4
  * Mode `edit` : édition complète du profil depuis le SaaS
5
5
  *
6
- * @version 2.5.0
6
+ * @version 2.6.0
7
7
  */
8
8
  import type { NativeUser, UserInfos } from '../types/native';
9
9
  export interface OnboardingModalProps {
@@ -3,7 +3,7 @@
3
3
  * Flow: email → method-choice → OTP → new password → success
4
4
  * Design aligned with web SSO
5
5
  *
6
- * @version 2.5.0
6
+ * @version 2.6.0
7
7
  */
8
8
  export interface PasswordRecoveryModalProps {
9
9
  open: boolean;
@@ -2,7 +2,7 @@
2
2
  * Signup Modal for @ollaid/native-sso — Design aligned with web SSO
3
3
  * Full signup flow: intro → account-type → info → OTP → password → confirm → success
4
4
  *
5
- * @version 2.5.0
5
+ * @version 2.6.0
6
6
  */
7
7
  import type { UserInfos } from '../types/native';
8
8
  export interface SignupModalProps {
@@ -3,7 +3,7 @@
3
3
  * Lightweight replacements for shadcn/ui components + inline SVG icons
4
4
  * No external dependencies required
5
5
  *
6
- * @version 2.5.0
6
+ * @version 2.6.0
7
7
  */
8
8
  import React from 'react';
9
9
  export declare function IconShieldCheck(props: React.SVGProps<SVGSVGElement>): import("react/jsx-runtime").JSX.Element;
@@ -22,7 +22,7 @@
22
22
  * };
23
23
  * ```
24
24
  *
25
- * @version 2.5.0
25
+ * @version 2.6.0
26
26
  */
27
27
  export interface UseLogoutOptions {
28
28
  /** Callback appelé après une déconnexion réussie (redirection, toast, etc.) */
@@ -2,7 +2,7 @@
2
2
  * Hook de récupération de mot de passe v1.0
3
3
  * Architecture Frontend-First avec appels directs à l'IAM
4
4
  *
5
- * @version 2.5.0
5
+ * @version 2.6.0
6
6
  */
7
7
  export interface UseMobilePasswordOptions {
8
8
  saasApiUrl: string;
@@ -2,7 +2,7 @@
2
2
  * Hook d'inscription Mobile SSO v1.0
3
3
  * Gère le flow: init → verify-otp → complete
4
4
  *
5
- * @version 2.5.0
5
+ * @version 2.6.0
6
6
  */
7
7
  import type { MobileRegistrationFormData, AccountType } from '../types/mobile';
8
8
  interface RegistrationConflict {
@@ -41,7 +41,7 @@ export declare function useMobileRegistration(options?: UseMobileRegistrationOpt
41
41
  error_type?: undefined;
42
42
  } | {
43
43
  success: boolean;
44
- error_type: any;
44
+ error_type: string | undefined;
45
45
  otp_code_dev?: undefined;
46
46
  otp_method?: undefined;
47
47
  otp_sent_to?: undefined;
@@ -2,8 +2,9 @@
2
2
  * Hook d'authentification Native SSO v1.0
3
3
  * Architecture Frontend-First avec appels directs à l'IAM
4
4
  *
5
- * @version 2.5.0
5
+ * @version 2.6.0
6
6
  */
7
+ import { type NativeStorageAdapter } from '../services/api';
7
8
  import type { NativeAuthStatus, NativeExchangeResponse, AccountType } from '../types/native';
8
9
  export interface UseNativeAuthOptions {
9
10
  /** URL du Backend SaaS */
@@ -19,6 +20,8 @@ export interface UseNativeAuthOptions {
19
20
  * Permet le multi-tenant dynamique : 'iam', 'iam_vendor', 'iam_client', etc.
20
21
  */
21
22
  configPrefix?: string;
23
+ /** Stockage injecté pour les apps natives / Capacitor */
24
+ storage?: NativeStorageAdapter;
22
25
  }
23
26
  export declare function useNativeAuth(options: UseNativeAuthOptions): {
24
27
  credentialsLoaded: boolean;
@@ -126,7 +129,7 @@ export declare function useNativeAuth(options: UseNativeAuthOptions): {
126
129
  success: boolean;
127
130
  user: {
128
131
  iam_reference: string;
129
- alias_reference: any;
132
+ alias_reference: string;
130
133
  id?: number;
131
134
  reference: string;
132
135
  name: string;
@@ -181,7 +184,7 @@ export declare function useNativeAuth(options: UseNativeAuthOptions): {
181
184
  success: boolean;
182
185
  user: {
183
186
  iam_reference: string;
184
- alias_reference: any;
187
+ alias_reference: string;
185
188
  id?: number;
186
189
  reference: string;
187
190
  name: string;
@@ -223,7 +226,7 @@ export declare function useNativeAuth(options: UseNativeAuthOptions): {
223
226
  success: boolean;
224
227
  user: {
225
228
  iam_reference: string;
226
- alias_reference: any;
229
+ alias_reference: string;
227
230
  id?: number;
228
231
  reference: string;
229
232
  name: string;
@@ -255,7 +258,7 @@ export declare function useNativeAuth(options: UseNativeAuthOptions): {
255
258
  success: boolean;
256
259
  user: {
257
260
  iam_reference: string;
258
- alias_reference: any;
261
+ alias_reference: string;
259
262
  id?: number;
260
263
  reference: string;
261
264
  name: string;
@@ -10,7 +10,7 @@
10
10
  * - Si 401 → révoque l'IAM (POST /iam/disconnect) + nettoie le frontend
11
11
  * - Ne déconnecte PAS si offline ou serveur inaccessible
12
12
  *
13
- * @version 2.5.0
13
+ * @version 2.6.0
14
14
  */
15
15
  import type { UserInfos } from '../types/native';
16
16
  export interface UseTokenHealthCheckOptions {