@ollaid/native-sso 2.8.2 → 2.8.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +15 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +15 -12
- package/dist/index.js.map +1 -1
- package/dist/services/api.d.ts +2 -0
- package/dist/types/native.d.ts +1 -0
- package/docs/10_login-redirect.md +103 -0
- package/docs/11_session-refresh-resilience.md +130 -0
- package/docs/12_login_mode.md +55 -0
- package/docs/13_must_have_working.md +60 -0
- package/docs/14_backend_env_key.md +51 -0
- package/docs/1_quick-start.md +87 -0
- package/docs/2_backend-contract.md +200 -0
- package/docs/3_storage-security.md +54 -0
- package/docs/4_webhooks.md +48 -0
- package/docs/5_iam-account.md +190 -0
- package/docs/6_advanced-services.md +115 -0
- package/docs/7_migration-notes.md +16 -0
- package/docs/8_update_infos.md +139 -0
- package/docs/9_password_magic_link.md +84 -0
- package/docs/README.md +66 -0
- package/package.json +6 -3
- package/scripts/copy-docs.mjs +36 -0
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# Update Infos
|
|
2
|
+
|
|
3
|
+
Version: `2.8.4`
|
|
4
|
+
|
|
5
|
+
Ce document décrit le flux recommandé pour la modal profil `OnboardingModal` quand un SaaS veut synchroniser les informations utilisateur avec le package `@ollaid/native-sso`.
|
|
6
|
+
|
|
7
|
+
## Objectif
|
|
8
|
+
|
|
9
|
+
- IAM reste la source de vérité.
|
|
10
|
+
- Le SaaS garde une copie locale de `user.user_infos`.
|
|
11
|
+
- Quand le modal s’ouvre, il hydrate les champs depuis IAM.
|
|
12
|
+
- Quand l’utilisateur enregistre, IAM est mis à jour en premier.
|
|
13
|
+
- Après succès IAM, le SaaS est mis à jour immédiatement.
|
|
14
|
+
|
|
15
|
+
## Flux recommandé
|
|
16
|
+
|
|
17
|
+
### 1. Ouverture du modal
|
|
18
|
+
|
|
19
|
+
Quand le SaaS ouvre la modal profil:
|
|
20
|
+
|
|
21
|
+
- afficher `OnboardingModal`
|
|
22
|
+
- passer le `user` courant
|
|
23
|
+
- utiliser `variant="edit"` si l’utilisateur modifie son profil depuis le SaaS
|
|
24
|
+
- garder `profileHydrating={true}` tant que les données ne sont pas encore chargées
|
|
25
|
+
|
|
26
|
+
Si vous n’utilisez pas `NativeSSOPage`, la couche SaaS doit d’abord hydrater le profil depuis IAM, puis ouvrir la modal avec les données reçues.
|
|
27
|
+
|
|
28
|
+
Pendant cette phase, la modal doit afficher un spinner de chargement.
|
|
29
|
+
|
|
30
|
+
### 2. Hydratation depuis IAM
|
|
31
|
+
|
|
32
|
+
Le package récupère les infos depuis IAM via son service profil:
|
|
33
|
+
|
|
34
|
+
- `profileService.getProfile()`
|
|
35
|
+
- endpoint IAM: `GET /backoffice/profile`
|
|
36
|
+
|
|
37
|
+
Dans le flux autonome `NativeSSOPage`, cette hydratation est déjà gérée par le package.
|
|
38
|
+
|
|
39
|
+
Les données récupérées doivent remplir les inputs du formulaire:
|
|
40
|
+
|
|
41
|
+
- `name`
|
|
42
|
+
- `image_url`
|
|
43
|
+
- `ccphone`
|
|
44
|
+
- `phone`
|
|
45
|
+
- `email`
|
|
46
|
+
- `address`
|
|
47
|
+
- `town`
|
|
48
|
+
- `country`
|
|
49
|
+
|
|
50
|
+
Si IAM renvoie une donnée plus fraîche que celle du SaaS, la valeur IAM gagne.
|
|
51
|
+
|
|
52
|
+
### 3. Mise à jour depuis la modal
|
|
53
|
+
|
|
54
|
+
Quand l’utilisateur clique sur `Enregistrer`:
|
|
55
|
+
|
|
56
|
+
- le package envoie l’update vers IAM via `profileService.updateProfile()`
|
|
57
|
+
- endpoint IAM: `PUT /backoffice/profile`
|
|
58
|
+
- IAM valide, normalise et renvoie la version finale du profil
|
|
59
|
+
|
|
60
|
+
IAM reste prioritaire sur la validation et la normalisation des champs.
|
|
61
|
+
|
|
62
|
+
### 4. Synchronisation immédiate vers le SaaS
|
|
63
|
+
|
|
64
|
+
Après succès IAM:
|
|
65
|
+
|
|
66
|
+
- le package appelle `onComplete`
|
|
67
|
+
- `onComplete` contient les données finales sous forme `user_infos`
|
|
68
|
+
- le SaaS doit persister immédiatement ces données dans son propre utilisateur
|
|
69
|
+
|
|
70
|
+
Le SaaS peut:
|
|
71
|
+
|
|
72
|
+
- mettre à jour son cache local
|
|
73
|
+
- appeler son backend pour enregistrer `user.user_infos`
|
|
74
|
+
- recharger la session utilisateur si besoin
|
|
75
|
+
|
|
76
|
+
## Règle d’or
|
|
77
|
+
|
|
78
|
+
La hiérarchie correcte est:
|
|
79
|
+
|
|
80
|
+
1. IAM
|
|
81
|
+
2. package SSO
|
|
82
|
+
3. SaaS
|
|
83
|
+
|
|
84
|
+
Donc:
|
|
85
|
+
|
|
86
|
+
- lecture depuis IAM
|
|
87
|
+
- écriture vers IAM
|
|
88
|
+
- réplication immédiate vers le SaaS
|
|
89
|
+
|
|
90
|
+
## Exemple d’intégration SaaS
|
|
91
|
+
|
|
92
|
+
```tsx
|
|
93
|
+
import { useState } from 'react';
|
|
94
|
+
import { OnboardingModal } from '@ollaid/native-sso';
|
|
95
|
+
|
|
96
|
+
export function ProfileSettings({ user, api }: { user: NativeUser; api: any }) {
|
|
97
|
+
const [open, setOpen] = useState(false);
|
|
98
|
+
|
|
99
|
+
return (
|
|
100
|
+
<>
|
|
101
|
+
<button type="button" onClick={() => setOpen(true)}>
|
|
102
|
+
Modifier mon profil
|
|
103
|
+
</button>
|
|
104
|
+
|
|
105
|
+
<OnboardingModal
|
|
106
|
+
open={open}
|
|
107
|
+
onOpenChange={setOpen}
|
|
108
|
+
onDismiss={() => setOpen(false)}
|
|
109
|
+
user={user}
|
|
110
|
+
variant="edit"
|
|
111
|
+
profileHydrating={false}
|
|
112
|
+
onComplete={async (data) => {
|
|
113
|
+
await api.updateCurrentUser({
|
|
114
|
+
user_infos: data.user_infos,
|
|
115
|
+
});
|
|
116
|
+
setOpen(false);
|
|
117
|
+
}}
|
|
118
|
+
onSkip={() => setOpen(false)}
|
|
119
|
+
/>
|
|
120
|
+
</>
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Cas du mode automatique
|
|
126
|
+
|
|
127
|
+
Quand `NativeSSOPage` gère l’auto-onboarding:
|
|
128
|
+
|
|
129
|
+
- la modal s’ouvre si le profil est incomplet
|
|
130
|
+
- le package hydrate les données depuis IAM
|
|
131
|
+
- les champs manquants sont affichés
|
|
132
|
+
- à la validation, IAM est mis à jour puis le SaaS est synchronisé
|
|
133
|
+
|
|
134
|
+
## Ce que le SaaS doit retenir
|
|
135
|
+
|
|
136
|
+
- N’inversez pas la priorité des sources.
|
|
137
|
+
- Ne traitez pas le SaaS comme source de vérité du profil.
|
|
138
|
+
- Ne contournez pas `onComplete`.
|
|
139
|
+
- Si le SaaS modifie `user.user_infos` hors modal, il doit garder la même logique de miroir vers IAM au prochain refresh.
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Password Magic Link Flow
|
|
2
|
+
|
|
3
|
+
Version: `2.8.4`
|
|
4
|
+
|
|
5
|
+
Ce document décrit le flux recommandé pour ouvrir le modal de changement de mot de passe sans faire d'appel direct du navigateur vers IAM.
|
|
6
|
+
|
|
7
|
+
## Objectif
|
|
8
|
+
|
|
9
|
+
- Le frontend SaaS ouvre la modal mot de passe.
|
|
10
|
+
- Le package `@ollaid/native-sso` appelle le backend SaaS.
|
|
11
|
+
- Le backend SaaS appelle IAM en server-to-server sur `POST /api/backoffice/auth/password-link`.
|
|
12
|
+
- IAM renvoie un `magic_token` ou une URL de redirection.
|
|
13
|
+
- Le backend SaaS renvoie au package une URL de redirection prête à ouvrir.
|
|
14
|
+
- Le navigateur est redirigé vers IAM.
|
|
15
|
+
|
|
16
|
+
## Pourquoi ce flux
|
|
17
|
+
|
|
18
|
+
- Il évite le CORS entre navigateur et IAM pour cette action.
|
|
19
|
+
- Il centralise l'authentification et la journalisation côté SaaS.
|
|
20
|
+
- Il laisse IAM gérer la génération du lien magique.
|
|
21
|
+
|
|
22
|
+
## Contrat attendu côté SaaS
|
|
23
|
+
|
|
24
|
+
Endpoint conseillé:
|
|
25
|
+
|
|
26
|
+
```http
|
|
27
|
+
POST /api/native/password-link
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Headers envoyés par le package:
|
|
31
|
+
|
|
32
|
+
- `Authorization: Bearer <token>` si disponible
|
|
33
|
+
- `X-App-Access-Token-Ref` si présent dans le storage
|
|
34
|
+
- `X-IAM-Config-Prefix` si le package est configuré avec un préfixe multi-tenant
|
|
35
|
+
- `X-Device-*` pour le contexte appareil
|
|
36
|
+
|
|
37
|
+
Body:
|
|
38
|
+
|
|
39
|
+
```json
|
|
40
|
+
{}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Réponse recommandée:
|
|
44
|
+
|
|
45
|
+
```json
|
|
46
|
+
{
|
|
47
|
+
"success": true,
|
|
48
|
+
"redirect_url": "https://identityam.ollaid.com/auth/auto-connect?magic_token=xxx",
|
|
49
|
+
"magic_token": "xxx",
|
|
50
|
+
"expires_at": "2026-05-18T12:00:00+00:00"
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Le backend SaaS peut aussi renvoyer `sso_url` pour compatibilité, mais `redirect_url` est la forme à privilégier.
|
|
55
|
+
|
|
56
|
+
## Contrat backend SaaS -> IAM
|
|
57
|
+
|
|
58
|
+
Le backend SaaS doit appeler IAM en interne:
|
|
59
|
+
|
|
60
|
+
```http
|
|
61
|
+
POST https://identityam.ollaid.com/api/backoffice/auth/password-link
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
IAM répond avec:
|
|
65
|
+
|
|
66
|
+
```json
|
|
67
|
+
{
|
|
68
|
+
"success": true,
|
|
69
|
+
"magic_token": "xxx",
|
|
70
|
+
"sso_url": "https://identityam.ollaid.com/auth/auto-connect?magic_token=xxx",
|
|
71
|
+
"expires_at": "2026-05-18T12:00:00+00:00"
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Le backend SaaS doit ensuite:
|
|
76
|
+
|
|
77
|
+
1. valider l'utilisateur courant
|
|
78
|
+
2. relayer la requête vers IAM
|
|
79
|
+
3. retourner au package une URL de redirection prête à ouvrir
|
|
80
|
+
|
|
81
|
+
## Intégration package
|
|
82
|
+
|
|
83
|
+
Le composant `PasswordRedirectModal` du package utilise `saasApiUrl`.
|
|
84
|
+
`iamApiUrl` reste supporté temporairement pour compatibilité ascendante, mais il ne doit plus être utilisé pour ce flux.
|
package/docs/README.md
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Native SSO Docs
|
|
2
|
+
|
|
3
|
+
Version: `2.8.4`
|
|
4
|
+
|
|
5
|
+
Docs courtes et pratiques pour `@ollaid/native-sso`.
|
|
6
|
+
|
|
7
|
+
## Démarrage
|
|
8
|
+
|
|
9
|
+
1. Lisez [Quick Start](./1_quick-start.md)
|
|
10
|
+
2. Vérifiez le contrat backend dans [Backend Contract](./2_backend-contract.md)
|
|
11
|
+
3. Vérifiez le stockage et la sécurité dans [Storage & Security](./3_storage-security.md)
|
|
12
|
+
4. Vérifiez les webhooks dans [Webhooks](./4_webhooks.md)
|
|
13
|
+
5. Si vous utilisez les APIs IAM Account server-to-server, lisez [IAM Account](./5_iam-account.md)
|
|
14
|
+
6. Si vous utilisez les helpers avancés, lisez [Advanced Services](./6_advanced-services.md)
|
|
15
|
+
7. Consultez les notes de migration dans [Migration Notes](./7_migration-notes.md)
|
|
16
|
+
8. Pour la synchro bidirectionnelle des infos profil, lisez [Update Infos](./8_update_infos.md)
|
|
17
|
+
9. Pour le flux de redirection mot de passe via backend SaaS, lisez [Password Magic Link](./9_password_magic_link.md)
|
|
18
|
+
10. Pour la redirection après connexion et le flux `needs_access`, lisez [Login Redirect & Access Flow](./10_login-redirect.md)
|
|
19
|
+
11. Pour la persistance des sessions, le refresh token et la résilience réseau, lisez [Session Refresh & Resilience](./11_session-refresh-resilience.md)
|
|
20
|
+
12. Pour le détail du flux `needs_access` et du bypass `BYPASS=true`, lisez [Needs Access & Bypass](./12_login_mode.md)
|
|
21
|
+
13. Pour la vérification finale des fonctionnalités critiques, lisez [Must Have Working](./13_must_have_working.md)
|
|
22
|
+
14. Pour les variables d'environnement backend IAM SSO, lisez [Backend Env Key](./14_backend_env_key.md)
|
|
23
|
+
|
|
24
|
+
## Principe
|
|
25
|
+
|
|
26
|
+
- Le package chiffre les données de session au repos dans son storage.
|
|
27
|
+
- Le frontend SaaS ne lit pas le storage directement.
|
|
28
|
+
- Le frontend SaaS demande la session au package via `getSsoSessionSnapshot()`.
|
|
29
|
+
- La déconnexion passe par `logout()`.
|
|
30
|
+
- Les APIs IAM Account (`iamAccountService`) sont server-to-server uniquement.
|
|
31
|
+
- Les helpers avancés (`mobilePasswordService`, `profileChangeService`, `profileMediaService`) sont documentés séparément.
|
|
32
|
+
|
|
33
|
+
## Checklist SaaS
|
|
34
|
+
|
|
35
|
+
- Fournir `redirectAfterLogin` sur `NativeSSOPage` si vous ne voulez pas rester sur la page SSO après connexion.
|
|
36
|
+
- Fournir `redirectAfterLogout` si vous voulez une sortie vers une page métier.
|
|
37
|
+
- Côté backend, renvoyer `needs_access` quand l'utilisateur est authentifié mais n'a pas encore accès à cette application.
|
|
38
|
+
- Si le SaaS active `BYPASS=true`, le backend peut auto-créer l'accès et finaliser la connexion sans afficher le modal.
|
|
39
|
+
- Ne pas appeler le callback final de redirection tant que `grantAccess()` n'a pas terminé, sauf si `BYPASS=true`.
|
|
40
|
+
|
|
41
|
+
## Onboarding profil
|
|
42
|
+
|
|
43
|
+
La modal `OnboardingModal` gère deux modes:
|
|
44
|
+
|
|
45
|
+
- `missing`:
|
|
46
|
+
- `name`
|
|
47
|
+
- `image_url`
|
|
48
|
+
- `phone`
|
|
49
|
+
- `email`
|
|
50
|
+
- `address`
|
|
51
|
+
- `town`
|
|
52
|
+
- `country`
|
|
53
|
+
- `edit`:
|
|
54
|
+
- nom complet
|
|
55
|
+
- photo de profil
|
|
56
|
+
- téléphone
|
|
57
|
+
- email
|
|
58
|
+
- adresse
|
|
59
|
+
- ville
|
|
60
|
+
- pays
|
|
61
|
+
|
|
62
|
+
Le mode automatique piloté par `NativeSSOPage` ouvre la modal après le délai configuré si l’un de ces champs est manquant. Le modal reste scrollable à l’intérieur via le conteneur de contenu dédié.
|
|
63
|
+
|
|
64
|
+
Quand vous ouvrez la modal depuis votre SaaS, utilisez `variant="edit"` pour afficher le formulaire complet éditable.
|
|
65
|
+
|
|
66
|
+
Le changement de téléphone ou d’email ouvre un sous-flux OTP dans la même modal, avec une fermeture bloquée tant que le flux est en cours.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ollaid/native-sso",
|
|
3
|
-
"version": "2.8.
|
|
3
|
+
"version": "2.8.4",
|
|
4
4
|
"description": "Package NPM fullstack pour l'authentification Native SSO Ollaid - Frontend-First (Link APIs & Refresh support)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
@@ -14,11 +14,14 @@
|
|
|
14
14
|
}
|
|
15
15
|
},
|
|
16
16
|
"files": [
|
|
17
|
-
"dist"
|
|
17
|
+
"dist",
|
|
18
|
+
"docs",
|
|
19
|
+
"scripts"
|
|
18
20
|
],
|
|
19
21
|
"scripts": {
|
|
20
22
|
"build": "vite build && tsc --emitDeclarationOnly --declaration --outDir dist",
|
|
21
|
-
"dev": "vite build --watch"
|
|
23
|
+
"dev": "vite build --watch",
|
|
24
|
+
"postinstall": "node ./scripts/copy-docs.mjs"
|
|
22
25
|
},
|
|
23
26
|
"peerDependencies": {
|
|
24
27
|
"@capacitor/device": "^7.0.0 || ^8.0.0",
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import process from 'node:process';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
|
|
6
|
+
const packageRoot = path.dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
const docsSourceDir = path.resolve(packageRoot, '../docs');
|
|
8
|
+
const projectRoot = process.env.INIT_CWD
|
|
9
|
+
? path.resolve(process.env.INIT_CWD)
|
|
10
|
+
: process.cwd();
|
|
11
|
+
const targetDir = path.resolve(projectRoot, 'docs/ollaid@sso_package');
|
|
12
|
+
|
|
13
|
+
async function main() {
|
|
14
|
+
let entries;
|
|
15
|
+
try {
|
|
16
|
+
entries = await fs.readdir(docsSourceDir, { withFileTypes: true });
|
|
17
|
+
} catch {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
await fs.rm(targetDir, { recursive: true, force: true });
|
|
22
|
+
await fs.mkdir(targetDir, { recursive: true });
|
|
23
|
+
|
|
24
|
+
for (const entry of entries) {
|
|
25
|
+
if (!entry.isFile() || !entry.name.endsWith('.md')) continue;
|
|
26
|
+
|
|
27
|
+
const sourceFile = path.join(docsSourceDir, entry.name);
|
|
28
|
+
const targetFile = path.join(targetDir, entry.name);
|
|
29
|
+
await fs.copyFile(sourceFile, targetFile);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
main().catch((error) => {
|
|
34
|
+
console.error('[ollaid-native-sso] doc copy failed:', error);
|
|
35
|
+
process.exitCode = 1;
|
|
36
|
+
});
|