@ollaid/native-sso 2.1.3 → 2.1.5
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 +28 -30
- package/dist/components/DebugPanel.d.ts +1 -1
- package/dist/components/LoginModal.d.ts +1 -1
- package/dist/components/NativeSSOPage.d.ts +1 -1
- package/dist/components/OnboardingModal.d.ts +1 -1
- package/dist/components/PasswordRecoveryModal.d.ts +1 -1
- package/dist/components/SignupModal.d.ts +1 -1
- package/dist/components/ui.d.ts +1 -1
- package/dist/hooks/useLogout.d.ts +1 -1
- package/dist/hooks/useMobilePassword.d.ts +1 -1
- package/dist/hooks/useMobileRegistration.d.ts +1 -1
- package/dist/hooks/useNativeAuth.d.ts +1 -1
- package/dist/hooks/useTokenHealthCheck.d.ts +1 -1
- package/dist/index.cjs +10 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +10 -20
- package/dist/index.js.map +1 -1
- package/dist/provider.d.ts +1 -1
- package/dist/services/api.d.ts +1 -1
- 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 +1 -1
- package/dist/types/mobile.d.ts +1 -1
- package/dist/types/native.d.ts +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -638,7 +638,7 @@ Retourne un **token opaque chiffré** (`encrypted_credentials`) contenant les cr
|
|
|
638
638
|
```
|
|
639
639
|
|
|
640
640
|
**Principe :**
|
|
641
|
-
Le SaaS chiffre `
|
|
641
|
+
Le SaaS chiffre `secret_key + timestamp` en AES-256-CBC avec `OPENSSL_RAW_DATA`, en utilisant la `secret_key` elle-même comme clé de chiffrement (SHA-256 → 32 bytes).
|
|
642
642
|
Le frontend transporte le blob opaque + l'`app_key` en clair (non sensible) vers l'IAM.
|
|
643
643
|
L'IAM retrouve la `secret_key` via l'`app_key` dans sa table `applications`, puis déchiffre le blob.
|
|
644
644
|
|
|
@@ -648,24 +648,26 @@ L'IAM retrouve la `secret_key` via l'`app_key` dans sa table `applications`, pui
|
|
|
648
648
|
Route::get('/native/config', function () {
|
|
649
649
|
$appKey = config('services.iam.app_key');
|
|
650
650
|
$secretKey = config('services.iam.secret_key');
|
|
651
|
+
$iamApiUrl = config('services.iam.api_url');
|
|
651
652
|
|
|
652
653
|
// Clé AES = SHA-256 de la secret_key (32 bytes binaires)
|
|
653
|
-
$
|
|
654
|
+
$encryptionKey = hash('sha256', $secretKey, true);
|
|
654
655
|
$iv = random_bytes(16);
|
|
655
656
|
|
|
656
657
|
$payload = json_encode([
|
|
657
|
-
'app_key' => $appKey,
|
|
658
658
|
'secret_key' => $secretKey,
|
|
659
659
|
'ts' => time(),
|
|
660
660
|
]);
|
|
661
661
|
|
|
662
|
-
$encrypted = openssl_encrypt($payload, '
|
|
662
|
+
$encrypted = openssl_encrypt($payload, 'AES-256-CBC', $encryptionKey, OPENSSL_RAW_DATA, $iv);
|
|
663
663
|
|
|
664
664
|
return response()->json([
|
|
665
|
-
'success'
|
|
666
|
-
'app_key'
|
|
667
|
-
'encrypted_credentials' => base64_encode($iv . '::' . $encrypted),
|
|
668
|
-
'
|
|
665
|
+
'success' => true,
|
|
666
|
+
'app_key' => $appKey, // En clair (non sensible, sert d'identifiant)
|
|
667
|
+
'encrypted_credentials' => base64_encode($iv . '::' . base64_encode($encrypted)),
|
|
668
|
+
'iam_api_url' => $iamApiUrl,
|
|
669
|
+
'credentials_ttl' => 300,
|
|
670
|
+
'debug' => (bool) config('services.iam.debug'),
|
|
669
671
|
]);
|
|
670
672
|
});
|
|
671
673
|
```
|
|
@@ -680,12 +682,12 @@ if (!$app) {
|
|
|
680
682
|
}
|
|
681
683
|
|
|
682
684
|
// 2. Déchiffrer avec la secret_key de l'application
|
|
683
|
-
$
|
|
685
|
+
$encryptionKey = hash('sha256', $app->secret_key, true);
|
|
684
686
|
$decoded = base64_decode($request->encrypted_credentials);
|
|
685
|
-
[$iv, $
|
|
687
|
+
[$iv, $ciphertextB64] = explode('::', $decoded, 2);
|
|
686
688
|
|
|
687
689
|
$payload = json_decode(
|
|
688
|
-
openssl_decrypt($
|
|
690
|
+
openssl_decrypt(base64_decode($ciphertextB64), 'AES-256-CBC', $encryptionKey, OPENSSL_RAW_DATA, $iv),
|
|
689
691
|
true
|
|
690
692
|
);
|
|
691
693
|
|
|
@@ -694,7 +696,6 @@ if (!$payload || time() - $payload['ts'] > 300) {
|
|
|
694
696
|
return response()->json(['success' => false, 'message' => 'Credentials expirés ou invalides'], 401);
|
|
695
697
|
}
|
|
696
698
|
|
|
697
|
-
$appKey = $payload['app_key'];
|
|
698
699
|
$secretKey = $payload['secret_key'];
|
|
699
700
|
// ... valider et continuer le flux
|
|
700
701
|
```
|
|
@@ -721,8 +722,8 @@ $secretKey = $payload['secret_key'];
|
|
|
721
722
|
|
|
722
723
|
**Logique backend :**
|
|
723
724
|
1. Recevoir le `callback_token`
|
|
724
|
-
2. Appeler l'IAM `POST /
|
|
725
|
-
3. L'IAM retourne les `user_infos` (9 champs standardisés)
|
|
725
|
+
2. Appeler l'IAM `POST /iam/auth/decrypt` avec les credentials dans les headers (`X-IAM-App-Key`, `X-IAM-Secret-Key`) et le token dans le body
|
|
726
|
+
3. L'IAM retourne les `user_infos` (9 champs standardisés) + `app_access_token_ref`
|
|
726
727
|
4. Créer ou mettre à jour l'utilisateur local
|
|
727
728
|
5. Générer un token Sanctum
|
|
728
729
|
6. Retourner le token + user
|
|
@@ -753,16 +754,14 @@ $secretKey = $payload['secret_key'];
|
|
|
753
754
|
```php
|
|
754
755
|
// routes/api.php
|
|
755
756
|
Route::post('/native/exchange', function (Request $request) {
|
|
756
|
-
$
|
|
757
|
-
|
|
758
|
-
// ⚠️ IMPORTANT : Remplacer les espaces par '+' avant décryptage
|
|
759
|
-
$callbackToken = str_replace(' ', '+', $callbackToken);
|
|
757
|
+
$iamApiUrl = config('services.iam.api_url');
|
|
760
758
|
|
|
761
|
-
// Appel IAM pour décrypter
|
|
762
|
-
$response = Http::
|
|
763
|
-
'
|
|
764
|
-
'
|
|
765
|
-
|
|
759
|
+
// Appel IAM pour décrypter — credentials dans les HEADERS
|
|
760
|
+
$response = Http::withHeaders([
|
|
761
|
+
'X-IAM-App-Key' => config('services.iam.app_key'),
|
|
762
|
+
'X-IAM-Secret-Key' => config('services.iam.secret_key'),
|
|
763
|
+
])->post("{$iamApiUrl}/iam/auth/decrypt", [
|
|
764
|
+
'token' => $request->callback_token,
|
|
766
765
|
]);
|
|
767
766
|
|
|
768
767
|
if (!$response->successful() || !$response->json('success')) {
|
|
@@ -773,7 +772,9 @@ Route::post('/native/exchange', function (Request $request) {
|
|
|
773
772
|
], 401);
|
|
774
773
|
}
|
|
775
774
|
|
|
776
|
-
$
|
|
775
|
+
$data = $response->json();
|
|
776
|
+
$userInfos = $data['user_infos'];
|
|
777
|
+
$appAccessTokenRef = $data['app_access_token_ref'] ?? null;
|
|
777
778
|
|
|
778
779
|
// Créer ou mettre à jour l'utilisateur local
|
|
779
780
|
$user = User::updateOrCreate(
|
|
@@ -786,16 +787,13 @@ Route::post('/native/exchange', function (Request $request) {
|
|
|
786
787
|
'image' => $userInfos['image_url'] ?? null,
|
|
787
788
|
'alias_reference' => $userInfos['alias_reference'],
|
|
788
789
|
'user_infos' => json_encode($userInfos),
|
|
789
|
-
'password' => bcrypt(Str::random(32)),
|
|
790
|
+
'password' => bcrypt(Str::random(32)),
|
|
790
791
|
]
|
|
791
792
|
);
|
|
792
793
|
|
|
793
794
|
// Générer un token Sanctum
|
|
794
795
|
$token = $user->createToken('native-sso')->plainTextToken;
|
|
795
796
|
|
|
796
|
-
// Récupérer app_access_token_ref depuis la réponse IAM
|
|
797
|
-
$appAccessTokenRef = $response->json('user_infos.app_access_token_ref');
|
|
798
|
-
|
|
799
797
|
return response()->json([
|
|
800
798
|
'success' => true,
|
|
801
799
|
'token' => $token,
|
|
@@ -1290,7 +1288,7 @@ Ajoutez ces variables dans le fichier `.env` du backend SaaS :
|
|
|
1290
1288
|
# Credentials IAM (récupérés depuis le dashboard iam.ollaid.com)
|
|
1291
1289
|
IAM_APP_KEY=oiam_ak_xxxxxxxxxxxxxxxxxxxxxxxx
|
|
1292
1290
|
IAM_SECRET_KEY=oiam_sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
|
1293
|
-
|
|
1291
|
+
IAM_API_URL=https://identityam.ollaid.com/api
|
|
1294
1292
|
|
|
1295
1293
|
# Mode debug — contrôle le DebugPanel et les logs côté frontend
|
|
1296
1294
|
# true : active le DebugPanel + logs console + détails d'erreur dans les réponses JSON
|
|
@@ -1307,7 +1305,7 @@ Et dans `config/services.php` :
|
|
|
1307
1305
|
'iam' => [
|
|
1308
1306
|
'app_key' => env('IAM_APP_KEY'),
|
|
1309
1307
|
'secret_key' => env('IAM_SECRET_KEY'),
|
|
1310
|
-
'
|
|
1308
|
+
'api_url' => env('IAM_API_URL', 'https://identityam.ollaid.com/api'),
|
|
1311
1309
|
'debug' => env('IAM_DEBUG', false), // Active le debug côté frontend (false si absent)
|
|
1312
1310
|
],
|
|
1313
1311
|
```
|
|
@@ -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 1.
|
|
5
|
+
* @version 2.1.4
|
|
6
6
|
*/
|
|
7
7
|
interface DebugPanelProps {
|
|
8
8
|
saasApiUrl: string;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* NativeSSOPage — Page autonome complète pour @ollaid/native-sso
|
|
3
3
|
* Design aligné sur /sso/auth (fond primary, card blanche, ShieldCheck branding)
|
|
4
4
|
*
|
|
5
|
-
* @version 2.
|
|
5
|
+
* @version 2.1.4
|
|
6
6
|
*/
|
|
7
7
|
import type { UserInfos } from '../types/native';
|
|
8
8
|
export interface NativeSSOPageProps {
|
|
@@ -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 1.
|
|
5
|
+
* @version 2.1.4
|
|
6
6
|
*/
|
|
7
7
|
import type { UserInfos } from '../types/native';
|
|
8
8
|
export interface SignupModalProps {
|
package/dist/components/ui.d.ts
CHANGED
|
@@ -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 1.
|
|
6
|
+
* @version 2.1.4
|
|
7
7
|
*/
|
|
8
8
|
import React from 'react';
|
|
9
9
|
export declare function IconShieldCheck(props: React.SVGProps<SVGSVGElement>): import("react/jsx-runtime").JSX.Element;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Hook d'authentification Native SSO v1.0
|
|
3
3
|
* Architecture Frontend-First avec appels directs à l'IAM
|
|
4
4
|
*
|
|
5
|
-
* @version 1.
|
|
5
|
+
* @version 2.1.4
|
|
6
6
|
*/
|
|
7
7
|
import type { NativeAuthStatus, NativeExchangeResponse, AccountType } from '../types/native';
|
|
8
8
|
export interface UseNativeAuthOptions {
|
|
@@ -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.
|
|
13
|
+
* @version 2.1.4
|
|
14
14
|
*/
|
|
15
15
|
import type { UserInfos } from '../types/native';
|
|
16
16
|
export interface UseTokenHealthCheckOptions {
|
package/dist/index.cjs
CHANGED
|
@@ -2529,17 +2529,11 @@ function LoginModal({
|
|
|
2529
2529
|
setPhone(initialPhone);
|
|
2530
2530
|
}
|
|
2531
2531
|
}, [open, initialPhone]);
|
|
2532
|
-
const
|
|
2533
|
-
|
|
2534
|
-
const
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
setLoginSuccess(true);
|
|
2538
|
-
} else {
|
|
2539
|
-
setLocalError("Erreur lors de la finalisation de la connexion");
|
|
2540
|
-
}
|
|
2541
|
-
} catch {
|
|
2542
|
-
setLocalError("Erreur de connexion au serveur");
|
|
2532
|
+
const finalizeLogin = (result) => {
|
|
2533
|
+
if (result.success && result.user) {
|
|
2534
|
+
const token = localStorage.getItem("native_auth_token") || localStorage.getItem("auth_token") || "";
|
|
2535
|
+
setLoginData({ token, user: result.user });
|
|
2536
|
+
setLoginSuccess(true);
|
|
2543
2537
|
}
|
|
2544
2538
|
};
|
|
2545
2539
|
const handleEmailCheck = async () => {
|
|
@@ -2569,7 +2563,7 @@ function LoginModal({
|
|
|
2569
2563
|
return;
|
|
2570
2564
|
}
|
|
2571
2565
|
const result = await submitPassword(password);
|
|
2572
|
-
|
|
2566
|
+
finalizeLogin(result);
|
|
2573
2567
|
};
|
|
2574
2568
|
const handleEmailOtpVerify = async () => {
|
|
2575
2569
|
setLocalError(null);
|
|
@@ -2579,7 +2573,7 @@ function LoginModal({
|
|
|
2579
2573
|
return;
|
|
2580
2574
|
}
|
|
2581
2575
|
const result = await submitOtp(emailOtpCode);
|
|
2582
|
-
|
|
2576
|
+
finalizeLogin(result);
|
|
2583
2577
|
};
|
|
2584
2578
|
const handlePhoneInit = async () => {
|
|
2585
2579
|
setLocalError(null);
|
|
@@ -2599,7 +2593,7 @@ function LoginModal({
|
|
|
2599
2593
|
return;
|
|
2600
2594
|
}
|
|
2601
2595
|
const result = await submitOtp(phoneOtpCode);
|
|
2602
|
-
|
|
2596
|
+
finalizeLogin(result);
|
|
2603
2597
|
};
|
|
2604
2598
|
const handleAccessOtpSubmit = async () => {
|
|
2605
2599
|
setLocalError(null);
|
|
@@ -2609,17 +2603,13 @@ function LoginModal({
|
|
|
2609
2603
|
return;
|
|
2610
2604
|
}
|
|
2611
2605
|
const result = await loginWithAccessOtp(accessOtpCode);
|
|
2612
|
-
|
|
2613
|
-
if (result.callback_token) {
|
|
2614
|
-
await exchangeCallbackToken(result.callback_token);
|
|
2615
|
-
}
|
|
2616
|
-
}
|
|
2606
|
+
finalizeLogin(result);
|
|
2617
2607
|
};
|
|
2618
2608
|
const handleGrantAccess = async () => {
|
|
2619
2609
|
setLocalError(null);
|
|
2620
2610
|
clearError();
|
|
2621
2611
|
const result = await grantAccess();
|
|
2622
|
-
|
|
2612
|
+
finalizeLogin(result);
|
|
2623
2613
|
};
|
|
2624
2614
|
const handleResendOTP = async () => {
|
|
2625
2615
|
if (resendCooldown > 0) return;
|