@ollaid/native-sso 2.1.5 → 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.
- package/README.md +398 -63
- package/dist/components/AvatarCropModal.d.ts +16 -0
- package/dist/components/DebugPanel.d.ts +7 -2
- package/dist/components/LoginModal.d.ts +2 -2
- package/dist/components/NativeSSOPage.d.ts +11 -3
- package/dist/components/OnboardingModal.d.ts +14 -7
- package/dist/components/PasswordRecoveryModal.d.ts +1 -1
- package/dist/components/PhoneInput.d.ts +2 -1
- package/dist/components/SignupModal.d.ts +1 -1
- package/dist/components/ui.d.ts +4 -2
- package/dist/hooks/useLogout.d.ts +1 -1
- package/dist/hooks/useMobilePassword.d.ts +1 -1
- package/dist/hooks/useMobileRegistration.d.ts +2 -2
- package/dist/hooks/useNativeAuth.d.ts +8 -5
- package/dist/hooks/useTokenHealthCheck.d.ts +11 -1
- package/dist/index-Bpixveaz.js +489 -0
- package/dist/index-Bpixveaz.js.map +1 -0
- package/dist/index-DDOXM37y.cjs +488 -0
- package/dist/index-DDOXM37y.cjs.map +1 -0
- package/dist/index.cjs +9231 -414
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +8 -5
- package/dist/index.js +9232 -415
- package/dist/index.js.map +1 -1
- package/dist/provider.d.ts +4 -1
- package/dist/services/api.d.ts +76 -7
- package/dist/services/debugLogger.d.ts +1 -1
- package/dist/services/iamAccount.d.ts +1 -1
- package/dist/services/mobilePassword.d.ts +1 -1
- package/dist/services/mobileRegistration.d.ts +1 -1
- package/dist/services/nativeAuth.d.ts +3 -2
- package/dist/services/profile.d.ts +31 -0
- package/dist/services/profileChange.d.ts +30 -0
- package/dist/services/profileMedia.d.ts +16 -0
- package/dist/types/mobile.d.ts +1 -1
- package/dist/types/native.d.ts +23 -1
- package/dist/web-BQDVoI6q.cjs +146 -0
- package/dist/web-BQDVoI6q.cjs.map +1 -0
- package/dist/web-DPmAPlXS.js +146 -0
- package/dist/web-DPmAPlXS.js.map +1 -0
- package/package.json +11 -4
package/README.md
CHANGED
|
@@ -21,13 +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
|
-
|
|
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
|
-
|
|
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)
|
|
31
34
|
|
|
32
35
|
---
|
|
33
36
|
|
|
@@ -37,6 +40,69 @@ Package NPM Frontend-First pour l'authentification Native SSO Ollaid.
|
|
|
37
40
|
npm install @ollaid/native-sso
|
|
38
41
|
```
|
|
39
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
|
+
|
|
40
106
|
---
|
|
41
107
|
|
|
42
108
|
## Intégration rapide (3 étapes)
|
|
@@ -59,7 +125,7 @@ function App() {
|
|
|
59
125
|
return (
|
|
60
126
|
<Routes>
|
|
61
127
|
<Route
|
|
62
|
-
path="/auth/sso"
|
|
128
|
+
path="/auth/native-sso"
|
|
63
129
|
element={
|
|
64
130
|
<NativeSSOPage
|
|
65
131
|
saasApiUrl="https://mon-saas.com/api"
|
|
@@ -69,7 +135,7 @@ function App() {
|
|
|
69
135
|
console.log('Connecté !', user.name);
|
|
70
136
|
navigate('/dashboard');
|
|
71
137
|
}}
|
|
72
|
-
onLogout={() => navigate('/auth/sso')}
|
|
138
|
+
onLogout={() => navigate('/auth/native-sso')}
|
|
73
139
|
/>
|
|
74
140
|
}
|
|
75
141
|
/>
|
|
@@ -81,7 +147,7 @@ function App() {
|
|
|
81
147
|
|
|
82
148
|
### 3. C'est tout ✅
|
|
83
149
|
|
|
84
|
-
La page `/auth/sso` gère automatiquement :
|
|
150
|
+
La page `/auth/native-sso` gère automatiquement :
|
|
85
151
|
- ✅ Connexion par email (mot de passe + OTP)
|
|
86
152
|
- ✅ Connexion par téléphone (SMS OTP)
|
|
87
153
|
- ✅ Connexion par code d'accès
|
|
@@ -89,7 +155,7 @@ La page `/auth/sso` gère automatiquement :
|
|
|
89
155
|
- ✅ Récupération de mot de passe
|
|
90
156
|
- ✅ Grant access (inscription auto à une nouvelle app)
|
|
91
157
|
- ✅ 2FA (TOTP)
|
|
92
|
-
- ✅ Session persistée
|
|
158
|
+
- ✅ Session persistée via le storage configuré, par défaut `localStorage`
|
|
93
159
|
- ✅ Branding Ollaid SSO
|
|
94
160
|
|
|
95
161
|
---
|
|
@@ -100,19 +166,23 @@ La page `/auth/sso` gère automatiquement :
|
|
|
100
166
|
|------|------|--------|-------------|
|
|
101
167
|
| `saasApiUrl` | `string` | ✅ | URL du backend SaaS (ex: `https://mon-saas.com/api`) |
|
|
102
168
|
| `iamApiUrl` | `string` | ✅ | URL du backend IAM (ex: `https://identityam.ollaid.com/api`) |
|
|
103
|
-
| `accountType` | `'user' \| 'client'` | ❌ | Type de compte à persister dans
|
|
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. |
|
|
104
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). |
|
|
105
171
|
| `onLoginSuccess` | `(token: string, user: UserInfos) => void` | ❌ | Callback après connexion réussie |
|
|
106
172
|
| `onLogout` | `() => void` | ❌ | Callback après déconnexion |
|
|
107
|
-
| `
|
|
173
|
+
| `storage` | `NativeStorageAdapter` | ❌ | Stockage injecté pour WebView / Capacitor / secure storage natif. Si absent, le package utilise un `localStorage` chiffré puis un fallback mémoire. |
|
|
174
|
+
| `title` | `string` | ❌ | Titre personnalisé (défaut: "Un compte pour toutes vos applications") |
|
|
108
175
|
| `description` | `string` | ❌ | Description personnalisée |
|
|
109
176
|
| `logoUrl` | `string` | ❌ | URL du logo (remplace le slider) |
|
|
110
177
|
| `hideFooter` | `boolean` | ❌ | Masquer "Propulsé par iam.ollaid.com" |
|
|
111
|
-
| `onOnboardingComplete` | `(data: { image_url?: string; ccphone?: string; phone?: string }) => void` | ❌ | Callback après complétion de l'onboarding |
|
|
178
|
+
| `onOnboardingComplete` | `(data: { name?: string; image_url?: string; ccphone?: string; phone?: string; email?: string }) => void` | ❌ | Callback après complétion de l'onboarding |
|
|
112
179
|
| `redirectAfterLogin` | `string` | ❌ | Route vers laquelle rediriger après connexion réussie (ex: `/client/dashboard`). Utilise `window.location.href`. Compatible avec ou sans react-router. |
|
|
113
180
|
| `redirectAfterLogout` | `string` | ❌ | Route vers laquelle rediriger après déconnexion (ex: `/auth/client`). Utilise `window.location.href`. |
|
|
114
181
|
|
|
115
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.
|
|
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.
|
|
116
186
|
|
|
117
187
|
### Redirections automatiques (optionnel)
|
|
118
188
|
|
|
@@ -173,9 +243,9 @@ const handleLogout = async () => {
|
|
|
173
243
|
|
|
174
244
|
### Que fait `logout()` ?
|
|
175
245
|
|
|
176
|
-
1. **Révoque
|
|
177
|
-
2. **Révoque la session IAM** — `POST /api/iam/disconnect` (avec `
|
|
178
|
-
3. **Nettoie le
|
|
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
|
|
179
249
|
|
|
180
250
|
Les appels réseau sont en `Promise.allSettled` (best-effort) : même si le serveur est injoignable, le localStorage est **toujours** nettoyé.
|
|
181
251
|
|
|
@@ -183,12 +253,15 @@ Les appels réseau sont en `Promise.allSettled` (best-effort) : même si le serv
|
|
|
183
253
|
|
|
184
254
|
| Clé | Description |
|
|
185
255
|
|-----|-------------|
|
|
186
|
-
| `auth_token` | Token
|
|
256
|
+
| `auth_token` | Token de session SaaS actif |
|
|
187
257
|
| `token` | Token legacy |
|
|
188
258
|
| `user` | Objet utilisateur (avec `iam_reference`, `alias_reference`) |
|
|
189
259
|
| `account_type` | Type de compte (`user` ou `client`) |
|
|
190
260
|
| `alias_reference` | Référence de l'alias de connexion |
|
|
191
261
|
| `app_access_token_ref` | Référence de l'`AppAccessToken` IAM (pour revocation optimisée) |
|
|
262
|
+
| `refresh_token` | Refresh token SaaS (si activé) |
|
|
263
|
+
| `token_expires_at` | Expiration du token Sanctum (si fournie) |
|
|
264
|
+
| `refresh_expires_at` | Expiration du refresh token (si fournie) |
|
|
192
265
|
|
|
193
266
|
### ⛔ `clearAuthToken()` est déprécié
|
|
194
267
|
|
|
@@ -235,7 +308,7 @@ Backend SaaS:
|
|
|
235
308
|
configPrefix="iam"
|
|
236
309
|
accountType="user"
|
|
237
310
|
redirectAfterLogin="/dashboard"
|
|
238
|
-
redirectAfterLogout="/auth/sso"
|
|
311
|
+
redirectAfterLogout="/auth/native-sso"
|
|
239
312
|
/>
|
|
240
313
|
|
|
241
314
|
{/* Page login espace vendeur */}
|
|
@@ -329,7 +402,7 @@ return [
|
|
|
329
402
|
|
|
330
403
|
### Côté Backend SaaS — Controller multi-tenant
|
|
331
404
|
|
|
332
|
-
Tous les controllers Native (`config`, `exchange`, `check-token`, `logout`) doivent lire le header :
|
|
405
|
+
Tous les controllers Native (`config`, `exchange`, `check-token`, `refresh`, `logout`) doivent lire le header :
|
|
333
406
|
|
|
334
407
|
```php
|
|
335
408
|
class NativeConfigController extends Controller
|
|
@@ -374,7 +447,29 @@ class NativeConfigController extends Controller
|
|
|
374
447
|
}
|
|
375
448
|
```
|
|
376
449
|
|
|
377
|
-
> **⚠️ Important** : Appliquez la même logique `X-IAM-Config-Prefix` dans `exchange`, `check-token` et `logout`.
|
|
450
|
+
> **⚠️ Important** : Appliquez la même logique `X-IAM-Config-Prefix` dans `exchange`, `check-token`, `refresh` et `logout`.
|
|
451
|
+
|
|
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
|
+
|
|
456
|
+
- `X-Device-Id` (stable par appareil / webview)
|
|
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.
|
|
378
473
|
|
|
379
474
|
---
|
|
380
475
|
|
|
@@ -415,6 +510,14 @@ php artisan config:clear
|
|
|
415
510
|
php artisan config:cache
|
|
416
511
|
```
|
|
417
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
|
+
|
|
418
521
|
---
|
|
419
522
|
|
|
420
523
|
## Usage avancé (composants individuels)
|
|
@@ -618,7 +721,8 @@ import { useMobileRegistration } from '@ollaid/native-sso';
|
|
|
618
721
|
|
|
619
722
|
## Backend SaaS — Endpoints requis
|
|
620
723
|
|
|
621
|
-
Le backend SaaS (Laravel) doit exposer **
|
|
724
|
+
Le backend SaaS (Laravel) doit exposer **5 endpoints** : `config`, `exchange`, `check-token`, `refresh`, `logout`.
|
|
725
|
+
Voici les spécifications exactes :
|
|
622
726
|
|
|
623
727
|
### `GET /api/native/config`
|
|
624
728
|
|
|
@@ -826,6 +930,7 @@ Vérifie la validité du token Sanctum et retourne les infos utilisateur fraîch
|
|
|
826
930
|
**Réponse succès (200) :**
|
|
827
931
|
```json
|
|
828
932
|
{
|
|
933
|
+
"success": true,
|
|
829
934
|
"status": "connected",
|
|
830
935
|
"user": {
|
|
831
936
|
"name": "John Doe",
|
|
@@ -849,6 +954,7 @@ Route::post('/native/check-token', function (Request $request) {
|
|
|
849
954
|
$user = $request->user();
|
|
850
955
|
|
|
851
956
|
return response()->json([
|
|
957
|
+
'success' => true,
|
|
852
958
|
'status' => 'connected',
|
|
853
959
|
'user' => [
|
|
854
960
|
'name' => $user->name,
|
|
@@ -864,7 +970,46 @@ Route::post('/native/check-token', function (Request $request) {
|
|
|
864
970
|
})->middleware('auth:sanctum');
|
|
865
971
|
```
|
|
866
972
|
|
|
867
|
-
> **
|
|
973
|
+
> **Règle de déconnexion :** Le package ne déconnecte l'utilisateur **que** sur un **HTTP 401 explicite**. Tout HTTP 200 (quelle que soit la structure du body) confirme la session. Erreur réseau, timeout, 5xx, offline → session conservée, jamais de déconnexion inutile.
|
|
974
|
+
|
|
975
|
+
---
|
|
976
|
+
|
|
977
|
+
### `POST /api/native/refresh` (OBLIGATOIRE pour la stabilité)
|
|
978
|
+
|
|
979
|
+
Renouvelle la session **sans déconnecter**. Le package l'utilise :
|
|
980
|
+
- en **proactif** (avant expiration, si `expires_at` est fourni)
|
|
981
|
+
- en **récupération** quand `check-token` retourne `401` (tente un refresh avant logout)
|
|
982
|
+
|
|
983
|
+
**Body :**
|
|
984
|
+
```json
|
|
985
|
+
{ "refresh_token": "rt_..." }
|
|
986
|
+
```
|
|
987
|
+
|
|
988
|
+
**Recommandation (stabilité maximale) :** ne pas changer le token Sanctum.
|
|
989
|
+
Le refresh doit **prolonger `expires_at`** du token existant (le client garde son token actuel).
|
|
990
|
+
|
|
991
|
+
**Réponse succès (200) :**
|
|
992
|
+
```json
|
|
993
|
+
{
|
|
994
|
+
"success": true,
|
|
995
|
+
"expires_at": "2026-06-13T12:00:00+00:00",
|
|
996
|
+
"refresh_token": "rt_new_...",
|
|
997
|
+
"refresh_expires_at": "2026-08-13T12:00:00+00:00",
|
|
998
|
+
"user": { "name": "John Doe" }
|
|
999
|
+
}
|
|
1000
|
+
```
|
|
1001
|
+
|
|
1002
|
+
**Réponse refresh invalide (401) :**
|
|
1003
|
+
```json
|
|
1004
|
+
{
|
|
1005
|
+
"success": false,
|
|
1006
|
+
"error_type": "invalid_refresh",
|
|
1007
|
+
"message": "Refresh token invalide ou expiré"
|
|
1008
|
+
}
|
|
1009
|
+
```
|
|
1010
|
+
|
|
1011
|
+
> Si le refresh est invalide (`401 invalid_refresh`) : c'est une révocation explicite, la déconnexion est autorisée.
|
|
1012
|
+
> Si offline/timeout/5xx : ne jamais déconnecter.
|
|
868
1013
|
|
|
869
1014
|
---
|
|
870
1015
|
|
|
@@ -900,7 +1045,7 @@ Route::post('/native/logout', function (Request $request) {
|
|
|
900
1045
|
|
|
901
1046
|
## Controller Laravel Complet (copier-coller)
|
|
902
1047
|
|
|
903
|
-
Voici un `NativeAuthController.php` complet regroupant les
|
|
1048
|
+
Voici un `NativeAuthController.php` complet regroupant les 5 endpoints. Copiez-le dans `app/Http/Controllers/Api/NativeAuthController.php` :
|
|
904
1049
|
|
|
905
1050
|
```php
|
|
906
1051
|
<?php
|
|
@@ -1122,6 +1267,7 @@ class NativeAuthController extends Controller
|
|
|
1122
1267
|
$user = $request->user();
|
|
1123
1268
|
|
|
1124
1269
|
return response()->json([
|
|
1270
|
+
'success' => true,
|
|
1125
1271
|
'status' => 'connected',
|
|
1126
1272
|
'message' => 'Utilisateur connecté',
|
|
1127
1273
|
'user' => [
|
|
@@ -1152,7 +1298,6 @@ class NativeAuthController extends Controller
|
|
|
1152
1298
|
$user = $request->user();
|
|
1153
1299
|
|
|
1154
1300
|
if ($user) {
|
|
1155
|
-
$sanctumTokenPlain = $request->bearerToken();
|
|
1156
1301
|
$currentToken = $user->currentAccessToken();
|
|
1157
1302
|
$appAccessTokenRef = $currentToken?->app_access_token_ref ?? null;
|
|
1158
1303
|
|
|
@@ -1160,14 +1305,13 @@ class NativeAuthController extends Controller
|
|
|
1160
1305
|
$currentToken?->delete();
|
|
1161
1306
|
|
|
1162
1307
|
// Notifier l'IAM (fire-and-forget, timeout 5s)
|
|
1163
|
-
if ($
|
|
1308
|
+
if ($appAccessTokenRef) {
|
|
1164
1309
|
$iamPrefix = $request->attributes->get('iam_prefix', 'iam');
|
|
1165
1310
|
$iamApiUrl = config("services.{$iamPrefix}.api_url", 'https://identityam.ollaid.com/api');
|
|
1166
1311
|
try {
|
|
1167
|
-
Http::timeout(5)->post("{$iamApiUrl}/iam/disconnect",
|
|
1168
|
-
'sanctum_token' => $sanctumTokenPlain,
|
|
1312
|
+
Http::timeout(5)->post("{$iamApiUrl}/iam/disconnect", [
|
|
1169
1313
|
'app_access_token_ref' => $appAccessTokenRef,
|
|
1170
|
-
])
|
|
1314
|
+
]);
|
|
1171
1315
|
} catch (\Exception $e) {
|
|
1172
1316
|
Log::warning("[NativeSSO] IAM disconnect failed (non-blocking)", ['error' => $e->getMessage()]);
|
|
1173
1317
|
}
|
|
@@ -1340,6 +1484,14 @@ public function up(): void
|
|
|
1340
1484
|
|
|
1341
1485
|
> **Note :** Le champ `reference` est l'identifiant unique IAM de l'utilisateur. Le champ `alias_reference` identifie l'utilisateur dans le contexte d'une application spécifique.
|
|
1342
1486
|
|
|
1487
|
+
### Colonnes recommandées sur `personal_access_tokens` (Sanctum)
|
|
1488
|
+
|
|
1489
|
+
Pour la révocation synchronisée et la stabilité de session :
|
|
1490
|
+
- `app_access_token_ref` (révocation IAM ciblée)
|
|
1491
|
+
- `refresh_token_hash` + `refresh_expires_at` (refresh token)
|
|
1492
|
+
|
|
1493
|
+
Ces migrations sont détaillées dans `BACKEND_INTEGRATION.md` du package.
|
|
1494
|
+
|
|
1343
1495
|
---
|
|
1344
1496
|
|
|
1345
1497
|
## Flux d'authentification
|
|
@@ -1384,7 +1536,7 @@ public function up(): void
|
|
|
1384
1536
|
4. **Validate** — Le frontend envoie le mot de passe/OTP, l'IAM retourne un `callback_token`
|
|
1385
1537
|
5. **Exchange** — Le frontend envoie le `callback_token` au backend SaaS, qui le décrypte via l'IAM et crée une session Sanctum
|
|
1386
1538
|
|
|
1387
|
-
> **Important :** Le package gère les étapes 1-5 automatiquement. Le backend SaaS doit implémenter **
|
|
1539
|
+
> **Important :** Le package gère les étapes 1-5 automatiquement. Le backend SaaS doit implémenter **5 endpoints** (`config`, `exchange`, `check-token`, `refresh`, `logout`).
|
|
1388
1540
|
|
|
1389
1541
|
---
|
|
1390
1542
|
|
|
@@ -1892,30 +2044,61 @@ Toutes les APIs IAM retournent le même objet `user_infos` avec exactement **9 c
|
|
|
1892
2044
|
|
|
1893
2045
|
---
|
|
1894
2046
|
|
|
1895
|
-
## Session &
|
|
2047
|
+
## Session & storage
|
|
1896
2048
|
|
|
1897
|
-
|
|
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()`.
|
|
1898
2051
|
|
|
1899
2052
|
| Clé | Contenu | Source | Valeurs possibles |
|
|
1900
2053
|
|-----|---------|--------|-------------------|
|
|
1901
|
-
| `
|
|
1902
|
-
| `
|
|
1903
|
-
| `
|
|
1904
|
-
| `
|
|
1905
|
-
| `
|
|
1906
|
-
| `
|
|
1907
|
-
|
|
1908
|
-
|
|
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 |
|
|
2062
|
+
| `sso_image_last_status` | Statut du dernier onboarding profil | Mis à jour par `OnboardingModal` | `"true"` ou `"false"` |
|
|
2063
|
+
| `sso_image_last_check` | Timestamp du dernier contrôle profil | Mis à jour par `OnboardingModal` / sync profil | Millisecondes Unix |
|
|
2064
|
+
| `sso_image_recheck_at` | Timestamp de rappel après snooze | Mis à jour quand l'utilisateur passe l'onboarding | Millisecondes Unix |
|
|
2065
|
+
|
|
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.
|
|
1909
2069
|
|
|
1910
2070
|
#### Champs enrichis dans l'objet `user`
|
|
1911
2071
|
|
|
1912
|
-
L'objet `user` stocké
|
|
2072
|
+
L'objet `user` stocké dans `sso_user` contient deux champs ajoutés automatiquement par le package :
|
|
1913
2073
|
- `iam_reference` : la référence IAM de l'utilisateur (`USR-XXXXXXXX`), extraite de `user.reference`
|
|
1914
2074
|
- `alias_reference` : la référence de l'alias utilisé lors de la connexion (`ALI-XXXXXXXX`), extraite de `user.alias_reference`
|
|
1915
2075
|
|
|
1916
2076
|
### Nettoyage
|
|
1917
2077
|
|
|
1918
|
-
Lors du `logout()`, les
|
|
2078
|
+
Lors du `logout()`, les clés de session sont supprimées via `clearAuthToken()`.
|
|
2079
|
+
Les clés de rappel profil (`sso_image_*`) ne sont pas effacées, afin de conserver le comportement de relance après snooze.
|
|
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_`.
|
|
1919
2102
|
|
|
1920
2103
|
### Accès programmatique
|
|
1921
2104
|
|
|
@@ -1928,6 +2111,28 @@ const type = getAccountType(); // string | null
|
|
|
1928
2111
|
const aliasRef = localStorage.getItem('alias_reference'); // string | null
|
|
1929
2112
|
```
|
|
1930
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
|
+
|
|
1931
2136
|
---
|
|
1932
2137
|
|
|
1933
2138
|
## Déconnexion synchronisée
|
|
@@ -1942,7 +2147,7 @@ Le package implémente une **double revocation** ultra-fiable : il contacte **en
|
|
|
1942
2147
|
│ logout() │ │
|
|
1943
2148
|
└──────┬──────────┘ │
|
|
1944
2149
|
│ ① POST /native/logout │ ② POST /iam/disconnect
|
|
1945
|
-
│ (Sanctum token) │ (
|
|
2150
|
+
│ (Sanctum token) │ (app_access_token_ref)
|
|
1946
2151
|
▼ ▼
|
|
1947
2152
|
┌─────────────────┐ ┌─────────────────┐
|
|
1948
2153
|
│ SaaS API │──③ fire-and-forget──────▶│ IAM API │
|
|
@@ -1964,9 +2169,9 @@ Le package implémente une **double revocation** ultra-fiable : il contacte **en
|
|
|
1964
2169
|
Quand `useNativeAuth.logout()` est appelé (ou que l'utilisateur clique "Se déconnecter" dans `NativeSSOPage`) :
|
|
1965
2170
|
|
|
1966
2171
|
1. **Appels parallèles** (via `Promise.allSettled`, jamais bloquants) :
|
|
1967
|
-
- `POST /api/native/logout` → SaaS
|
|
1968
|
-
- `POST /api/iam/disconnect` → IAM révoque directement l'`AppAccessToken` via `
|
|
1969
|
-
2. **Nettoyage local garanti** : les
|
|
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`)
|
|
1970
2175
|
3. **Aucun blocage** : même si les deux appels échouent (offline, timeout), la déconnexion locale est instantanée
|
|
1971
2176
|
|
|
1972
2177
|
> **Fiabilité** : `Promise.allSettled` + `.catch()` sur chaque appel. L'appel IAM a un timeout court (5s) pour ne jamais ralentir l'UX.
|
|
@@ -1977,10 +2182,9 @@ Le package contacte directement l'IAM pour révoquer l'`AppAccessToken` lié à
|
|
|
1977
2182
|
|
|
1978
2183
|
| Paramètre | Type | Description |
|
|
1979
2184
|
|-----------|------|-------------|
|
|
1980
|
-
| `
|
|
1981
|
-
| `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 |
|
|
1982
2186
|
|
|
1983
|
-
L'IAM cherche
|
|
2187
|
+
L'IAM cherche par `app_access_token_ref` (lookup par PK, O(1)).
|
|
1984
2188
|
|
|
1985
2189
|
### Déconnexion externe (hors package)
|
|
1986
2190
|
|
|
@@ -2000,8 +2204,8 @@ navigate('/auth/login');
|
|
|
2000
2204
|
|
|
2001
2205
|
`logout()` effectue automatiquement :
|
|
2002
2206
|
1. `POST /api/native/logout` → révoque le Sanctum token
|
|
2003
|
-
2. `POST /api/iam/disconnect` → révoque l'AppAccessToken IAM
|
|
2004
|
-
3. `clearAuthToken()` → nettoie les
|
|
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
|
|
2005
2209
|
|
|
2006
2210
|
### Hook `useLogout()` (recommandé pour React)
|
|
2007
2211
|
|
|
@@ -2041,18 +2245,18 @@ const LogoutButton = () => {
|
|
|
2041
2245
|
|
|
2042
2246
|
### Détection automatique des sessions révoquées
|
|
2043
2247
|
|
|
2044
|
-
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 `
|
|
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.
|
|
2045
2249
|
|
|
2046
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.
|
|
2047
2251
|
|
|
2048
2252
|
### Prérequis backend
|
|
2049
2253
|
|
|
2050
|
-
1. Votre endpoint `POST /api/native/logout` **doit** notifier l'IAM après avoir
|
|
2051
|
-
2. L'IAM **doit** exposer `POST /api/iam/disconnect` acceptant `{
|
|
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 }`
|
|
2052
2256
|
|
|
2053
2257
|
---
|
|
2054
2258
|
|
|
2055
|
-
Modal post-connexion qui invite l'utilisateur à compléter les informations manquantes de son profil.
|
|
2259
|
+
Modal post-connexion qui invite l'utilisateur à compléter les informations manquantes de son profil, ou à éditer ses informations complètes depuis un SaaS.
|
|
2056
2260
|
|
|
2057
2261
|
### Props
|
|
2058
2262
|
|
|
@@ -2061,35 +2265,102 @@ Modal post-connexion qui invite l'utilisateur à compléter les informations man
|
|
|
2061
2265
|
| `open` | `boolean` | ✅ | Contrôle l'ouverture de la modal |
|
|
2062
2266
|
| `onOpenChange` | `(open: boolean) => void` | ✅ | Callback changement d'état |
|
|
2063
2267
|
| `user` | `NativeUser` | ✅ | Objet utilisateur courant (pour détecter les champs manquants) |
|
|
2268
|
+
| `variant` | `'missing' \| 'edit'` | ❌ | `missing` affiche uniquement les champs absents, `edit` affiche les champs de base en mode édition complet |
|
|
2064
2269
|
| `onComplete` | `(data) => void` | ✅ | Callback avec les données saisies |
|
|
2065
2270
|
| `onSkip` | `() => void` | ✅ | Callback si l'utilisateur passe l'étape |
|
|
2066
2271
|
|
|
2067
2272
|
### Champs affichés
|
|
2068
2273
|
|
|
2069
|
-
La modal
|
|
2070
|
-
|
|
2071
|
-
- **
|
|
2072
|
-
- **
|
|
2274
|
+
La modal gère **deux modes** :
|
|
2275
|
+
|
|
2276
|
+
- **Mode `missing`** : affiche uniquement les champs manquants
|
|
2277
|
+
- **Nom complet** — si `user.name` est vide
|
|
2278
|
+
- **Photo de profil** — si `user.image_url` est vide (max 2 Mo, JPG/PNG)
|
|
2279
|
+
- **Numéro de téléphone** — si `user.phone` est vide
|
|
2280
|
+
- **Adresse email** — si `user.email` est vide
|
|
2281
|
+
- **Mode `edit`** : affiche les champs de base éditables même si le profil est déjà complet
|
|
2282
|
+
- Nom complet
|
|
2283
|
+
- Photo de profil
|
|
2284
|
+
- Numéro de téléphone en lecture seule avec bouton `Changer téléphone`
|
|
2285
|
+
- Adresse email en lecture seule avec bouton `Changer email`
|
|
2073
2286
|
|
|
2074
2287
|
### Callback `onComplete`
|
|
2075
2288
|
|
|
2076
2289
|
```ts
|
|
2077
2290
|
onComplete: (data: {
|
|
2291
|
+
name?: string; // Nom complet (si fourni ou modifié)
|
|
2078
2292
|
image_url?: string; // Base64 de la photo (si ajoutée)
|
|
2079
2293
|
ccphone?: string; // Indicatif (si téléphone ajouté)
|
|
2080
2294
|
phone?: string; // Numéro (si téléphone ajouté)
|
|
2081
|
-
email?: string; // Email (si renseigné
|
|
2295
|
+
email?: string; // Email (si renseigné)
|
|
2082
2296
|
}) => void;
|
|
2083
2297
|
```
|
|
2084
2298
|
|
|
2085
2299
|
### Condition de soumission
|
|
2086
2300
|
|
|
2087
2301
|
L'utilisateur **doit** :
|
|
2088
|
-
1.
|
|
2089
|
-
2. Fournir une photo
|
|
2090
|
-
3. Fournir un téléphone valide
|
|
2302
|
+
1. Fournir un nom si le nom est affiché
|
|
2303
|
+
2. Fournir une photo si elle est affichée
|
|
2304
|
+
3. Fournir un téléphone valide si le champ est affiché
|
|
2305
|
+
4. Fournir un email valide si le champ est affiché
|
|
2306
|
+
|
|
2307
|
+
Après connexion, la page autonome attend 5 minutes avant d'ouvrir cette modal si le profil est incomplet.
|
|
2308
|
+
Si l'utilisateur la ferme sans compléter, le package enregistre un snooze de 8 heures (`sso_image_last_status=false`, `sso_image_last_check=now`, `sso_image_recheck_at=now+8h`).
|
|
2309
|
+
Un sync profil best-effort relit ensuite l'état utilisateur toutes les 30 minutes et remet `sso_image_last_status=true` dès que le profil est complet.
|
|
2310
|
+
|
|
2311
|
+
### Mode automatique
|
|
2091
2312
|
|
|
2092
|
-
|
|
2313
|
+
Le mode automatique est piloté par `NativeSSOPage` :
|
|
2314
|
+
- la modal s'ouvre après le délai de 5 minutes si des infos sont manquantes,
|
|
2315
|
+
- elle reste sur un écran de chargement tant que l'hydratation IAM n'a pas renvoyé le profil,
|
|
2316
|
+
- elle affiche ensuite uniquement les champs manquants,
|
|
2317
|
+
- si l'utilisateur ferme la modal, le rappel est repoussé de 8 heures.
|
|
2318
|
+
|
|
2319
|
+
### Mode manuel depuis un SaaS
|
|
2320
|
+
|
|
2321
|
+
Quand vous ouvrez la modal depuis votre SaaS via un bouton "Infos profil" ou "Modifier mon profil", utilisez `variant="edit"`.
|
|
2322
|
+
|
|
2323
|
+
Exemple :
|
|
2324
|
+
|
|
2325
|
+
```tsx
|
|
2326
|
+
import { useState } from 'react';
|
|
2327
|
+
import { OnboardingModal } from '@ollaid/native-sso';
|
|
2328
|
+
|
|
2329
|
+
export function ProfileButton({ user }: { user: NativeUser }) {
|
|
2330
|
+
const [open, setOpen] = useState(false);
|
|
2331
|
+
|
|
2332
|
+
return (
|
|
2333
|
+
<>
|
|
2334
|
+
<button type="button" onClick={() => setOpen(true)}>
|
|
2335
|
+
Infos profil
|
|
2336
|
+
</button>
|
|
2337
|
+
|
|
2338
|
+
<OnboardingModal
|
|
2339
|
+
open={open}
|
|
2340
|
+
onOpenChange={setOpen}
|
|
2341
|
+
onDismiss={() => setOpen(false)}
|
|
2342
|
+
user={user}
|
|
2343
|
+
variant="edit"
|
|
2344
|
+
profileHydrating={false}
|
|
2345
|
+
onComplete={(data) => {
|
|
2346
|
+
// Mettre à jour votre cache local / localStorage avec data.user_infos
|
|
2347
|
+
setOpen(false);
|
|
2348
|
+
}}
|
|
2349
|
+
onSkip={() => setOpen(false)}
|
|
2350
|
+
/>
|
|
2351
|
+
</>
|
|
2352
|
+
);
|
|
2353
|
+
}
|
|
2354
|
+
```
|
|
2355
|
+
|
|
2356
|
+
Dans ce mode, le changement de téléphone/email ouvre un sous-flux OTP dans la même modal:
|
|
2357
|
+
1. saisie du nouveau téléphone/email,
|
|
2358
|
+
2. envoi du premier OTP sur le contact actuel,
|
|
2359
|
+
3. vérification du premier OTP,
|
|
2360
|
+
4. envoi d'un second OTP sur le nouveau contact,
|
|
2361
|
+
5. confirmation finale et mise à jour du profil.
|
|
2362
|
+
|
|
2363
|
+
Les écrans de changement restent en `static backdrop` côté package: un clic hors modal ne ferme pas le flux.
|
|
2093
2364
|
|
|
2094
2365
|
### Exemple
|
|
2095
2366
|
|
|
@@ -2100,6 +2371,7 @@ import { OnboardingModal } from '@ollaid/native-sso';
|
|
|
2100
2371
|
open={showOnboarding}
|
|
2101
2372
|
onOpenChange={setShowOnboarding}
|
|
2102
2373
|
user={currentUser}
|
|
2374
|
+
variant="edit"
|
|
2103
2375
|
onComplete={async (data) => {
|
|
2104
2376
|
// Envoyer les données au backend pour mise à jour
|
|
2105
2377
|
await api.updateProfile(data);
|
|
@@ -2138,8 +2410,8 @@ Hook qui vérifie périodiquement la validité du token Sanctum via `POST /api/n
|
|
|
2138
2410
|
|
|
2139
2411
|
Quand le SaaS retourne un 401 (token révoqué par un admin, session expirée, etc.) :
|
|
2140
2412
|
|
|
2141
|
-
1. **Appel IAM** — Le package appelle `POST /api/iam/disconnect` avec `
|
|
2142
|
-
2. **Nettoyage localStorage** — Les
|
|
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
|
|
2143
2415
|
3. **Réinitialisation de l'état** — L'interface revient à l'écran de connexion
|
|
2144
2416
|
|
|
2145
2417
|
> **Philosophie** : Ne déconnecter que sur un rejet explicite du serveur (401). Jamais sur un problème réseau.
|
|
@@ -2207,13 +2479,57 @@ if (config('services.iam.debug')) {
|
|
|
2207
2479
|
|
|
2208
2480
|
### Bonnes pratiques
|
|
2209
2481
|
|
|
2210
|
-
- ✅ Le token Sanctum est stocké
|
|
2482
|
+
- ✅ Le token Sanctum est stocké via le storage configuré, par défaut `localStorage`
|
|
2211
2483
|
- ✅ Les credentials IAM sont gardés **en mémoire uniquement** (jamais persistés)
|
|
2212
2484
|
- ✅ Le device ID est un identifiant aléatoire (pas de fingerprinting invasif)
|
|
2213
2485
|
- ✅ Le logout est single-session (ne déconnecte pas les autres appareils)
|
|
2214
2486
|
- ✅ Le health check ne déconnecte que sur 401 explicite
|
|
2215
2487
|
- ✅ Les photos sont validées à 2 Mo max côté client
|
|
2216
|
-
- ✅ Les lectures
|
|
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.
|
|
2217
2533
|
|
|
2218
2534
|
---
|
|
2219
2535
|
|
|
@@ -2243,11 +2559,17 @@ if (config('services.iam.debug')) {
|
|
|
2243
2559
|
- `nativeAuthService` — Service d'authentification
|
|
2244
2560
|
- `mobilePasswordService` — Service mot de passe
|
|
2245
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
|
|
2246
2565
|
- `iamAccountService` — Service APIs IAM Account (link-phone, link-email, refresh-user-info, update-avatar, reset-avatar)
|
|
2247
2566
|
- `logout` — Déconnexion complète (double révocation SaaS + IAM + nettoyage localStorage)
|
|
2248
2567
|
- `getAuthToken` — Récupérer le token depuis localStorage
|
|
2249
2568
|
- `getAuthUser` — Récupérer l'utilisateur depuis localStorage
|
|
2250
2569
|
- `getAccountType` — Récupérer le type de compte depuis localStorage
|
|
2570
|
+
- `getDeviceId` — Récupérer/générer le `X-Device-Id` (persisté)
|
|
2571
|
+
- `getSessionUuid` — Récupérer/générer le `X-Session-UUID` (persisté)
|
|
2572
|
+
- `STORAGE_KEYS` — Constantes des clés localStorage utilisées par le package
|
|
2251
2573
|
|
|
2252
2574
|
### Types
|
|
2253
2575
|
- `UserInfos`, `NativeAuthState`, `NativeAuthStatus`, `NativeCredentials`, etc.
|
|
@@ -2352,3 +2674,16 @@ npm publish --access public # 3. Publier sur npm
|
|
|
2352
2674
|
## Licence
|
|
2353
2675
|
|
|
2354
2676
|
Propriétaire — Ollaid © 2026
|
|
2677
|
+
|
|
2678
|
+
---
|
|
2679
|
+
|
|
2680
|
+
## Webhooks & Health Check (Backend)
|
|
2681
|
+
|
|
2682
|
+
Pour garantir la fiabilité et la synchronisation en temps réel (ex: révocation instantanée d'une session bannie), votre backend doit implémenter deux briques supplémentaires.
|
|
2683
|
+
|
|
2684
|
+
Consultez le guide détaillé : [**WEBHOOKS_HEALTH.md**](./WEBHOOKS_HEALTH.md)
|
|
2685
|
+
|
|
2686
|
+
| Brique | Rôle |
|
|
2687
|
+
|--------|------|
|
|
2688
|
+
| **Health Check** | Permet à l'IAM de vérifier que votre SaaS est "Healthy" et bien configuré. |
|
|
2689
|
+
| **Webhooks** | Permet à l'IAM de notifier votre SaaS d'événements critiques (suspension, révocation). |
|