@ollaid/native-sso 2.1.2 → 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 +64 -53
- 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
|
@@ -359,13 +359,14 @@ class NativeConfigController extends Controller
|
|
|
359
359
|
$payload = json_encode(['secret_key' => $secretKey, 'ts' => time()]);
|
|
360
360
|
$key = hash('sha256', $secretKey, true);
|
|
361
361
|
$iv = random_bytes(16);
|
|
362
|
-
$encrypted = openssl_encrypt($payload, 'AES-256-CBC', $key,
|
|
363
|
-
$encryptedCredentials = base64_encode($iv . '::' . $encrypted);
|
|
362
|
+
$encrypted = openssl_encrypt($payload, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
|
|
363
|
+
$encryptedCredentials = base64_encode($iv . '::' . base64_encode($encrypted));
|
|
364
364
|
|
|
365
365
|
return response()->json([
|
|
366
366
|
'success' => true,
|
|
367
367
|
'app_key' => $appKey,
|
|
368
368
|
'encrypted_credentials' => $encryptedCredentials,
|
|
369
|
+
'iam_api_url' => config("services.{$prefix}.api_url", 'https://identityam.ollaid.com/api'),
|
|
369
370
|
'credentials_ttl' => 300,
|
|
370
371
|
'debug' => $debug,
|
|
371
372
|
]);
|
|
@@ -637,7 +638,7 @@ Retourne un **token opaque chiffré** (`encrypted_credentials`) contenant les cr
|
|
|
637
638
|
```
|
|
638
639
|
|
|
639
640
|
**Principe :**
|
|
640
|
-
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).
|
|
641
642
|
Le frontend transporte le blob opaque + l'`app_key` en clair (non sensible) vers l'IAM.
|
|
642
643
|
L'IAM retrouve la `secret_key` via l'`app_key` dans sa table `applications`, puis déchiffre le blob.
|
|
643
644
|
|
|
@@ -647,24 +648,26 @@ L'IAM retrouve la `secret_key` via l'`app_key` dans sa table `applications`, pui
|
|
|
647
648
|
Route::get('/native/config', function () {
|
|
648
649
|
$appKey = config('services.iam.app_key');
|
|
649
650
|
$secretKey = config('services.iam.secret_key');
|
|
651
|
+
$iamApiUrl = config('services.iam.api_url');
|
|
650
652
|
|
|
651
653
|
// Clé AES = SHA-256 de la secret_key (32 bytes binaires)
|
|
652
|
-
$
|
|
654
|
+
$encryptionKey = hash('sha256', $secretKey, true);
|
|
653
655
|
$iv = random_bytes(16);
|
|
654
656
|
|
|
655
657
|
$payload = json_encode([
|
|
656
|
-
'app_key' => $appKey,
|
|
657
658
|
'secret_key' => $secretKey,
|
|
658
659
|
'ts' => time(),
|
|
659
660
|
]);
|
|
660
661
|
|
|
661
|
-
$encrypted = openssl_encrypt($payload, '
|
|
662
|
+
$encrypted = openssl_encrypt($payload, 'AES-256-CBC', $encryptionKey, OPENSSL_RAW_DATA, $iv);
|
|
662
663
|
|
|
663
664
|
return response()->json([
|
|
664
|
-
'success'
|
|
665
|
-
'app_key'
|
|
666
|
-
'encrypted_credentials' => base64_encode($iv . '::' . $encrypted),
|
|
667
|
-
'
|
|
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'),
|
|
668
671
|
]);
|
|
669
672
|
});
|
|
670
673
|
```
|
|
@@ -679,12 +682,12 @@ if (!$app) {
|
|
|
679
682
|
}
|
|
680
683
|
|
|
681
684
|
// 2. Déchiffrer avec la secret_key de l'application
|
|
682
|
-
$
|
|
685
|
+
$encryptionKey = hash('sha256', $app->secret_key, true);
|
|
683
686
|
$decoded = base64_decode($request->encrypted_credentials);
|
|
684
|
-
[$iv, $
|
|
687
|
+
[$iv, $ciphertextB64] = explode('::', $decoded, 2);
|
|
685
688
|
|
|
686
689
|
$payload = json_decode(
|
|
687
|
-
openssl_decrypt($
|
|
690
|
+
openssl_decrypt(base64_decode($ciphertextB64), 'AES-256-CBC', $encryptionKey, OPENSSL_RAW_DATA, $iv),
|
|
688
691
|
true
|
|
689
692
|
);
|
|
690
693
|
|
|
@@ -693,7 +696,6 @@ if (!$payload || time() - $payload['ts'] > 300) {
|
|
|
693
696
|
return response()->json(['success' => false, 'message' => 'Credentials expirés ou invalides'], 401);
|
|
694
697
|
}
|
|
695
698
|
|
|
696
|
-
$appKey = $payload['app_key'];
|
|
697
699
|
$secretKey = $payload['secret_key'];
|
|
698
700
|
// ... valider et continuer le flux
|
|
699
701
|
```
|
|
@@ -720,8 +722,8 @@ $secretKey = $payload['secret_key'];
|
|
|
720
722
|
|
|
721
723
|
**Logique backend :**
|
|
722
724
|
1. Recevoir le `callback_token`
|
|
723
|
-
2. Appeler l'IAM `POST /
|
|
724
|
-
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`
|
|
725
727
|
4. Créer ou mettre à jour l'utilisateur local
|
|
726
728
|
5. Générer un token Sanctum
|
|
727
729
|
6. Retourner le token + user
|
|
@@ -752,16 +754,14 @@ $secretKey = $payload['secret_key'];
|
|
|
752
754
|
```php
|
|
753
755
|
// routes/api.php
|
|
754
756
|
Route::post('/native/exchange', function (Request $request) {
|
|
755
|
-
$
|
|
756
|
-
|
|
757
|
-
// ⚠️ IMPORTANT : Remplacer les espaces par '+' avant décryptage
|
|
758
|
-
$callbackToken = str_replace(' ', '+', $callbackToken);
|
|
757
|
+
$iamApiUrl = config('services.iam.api_url');
|
|
759
758
|
|
|
760
|
-
// Appel IAM pour décrypter
|
|
761
|
-
$response = Http::
|
|
762
|
-
'
|
|
763
|
-
'
|
|
764
|
-
|
|
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,
|
|
765
765
|
]);
|
|
766
766
|
|
|
767
767
|
if (!$response->successful() || !$response->json('success')) {
|
|
@@ -772,7 +772,9 @@ Route::post('/native/exchange', function (Request $request) {
|
|
|
772
772
|
], 401);
|
|
773
773
|
}
|
|
774
774
|
|
|
775
|
-
$
|
|
775
|
+
$data = $response->json();
|
|
776
|
+
$userInfos = $data['user_infos'];
|
|
777
|
+
$appAccessTokenRef = $data['app_access_token_ref'] ?? null;
|
|
776
778
|
|
|
777
779
|
// Créer ou mettre à jour l'utilisateur local
|
|
778
780
|
$user = User::updateOrCreate(
|
|
@@ -785,16 +787,13 @@ Route::post('/native/exchange', function (Request $request) {
|
|
|
785
787
|
'image' => $userInfos['image_url'] ?? null,
|
|
786
788
|
'alias_reference' => $userInfos['alias_reference'],
|
|
787
789
|
'user_infos' => json_encode($userInfos),
|
|
788
|
-
'password' => bcrypt(Str::random(32)),
|
|
790
|
+
'password' => bcrypt(Str::random(32)),
|
|
789
791
|
]
|
|
790
792
|
);
|
|
791
793
|
|
|
792
794
|
// Générer un token Sanctum
|
|
793
795
|
$token = $user->createToken('native-sso')->plainTextToken;
|
|
794
796
|
|
|
795
|
-
// Récupérer app_access_token_ref depuis la réponse IAM
|
|
796
|
-
$appAccessTokenRef = $response->json('user_infos.app_access_token_ref');
|
|
797
|
-
|
|
798
797
|
return response()->json([
|
|
799
798
|
'success' => true,
|
|
800
799
|
'token' => $token,
|
|
@@ -944,17 +943,19 @@ class NativeAuthController extends Controller
|
|
|
944
943
|
$aesKey = hash('sha256', $secretKey, true);
|
|
945
944
|
$iv = random_bytes(16);
|
|
946
945
|
$payload = json_encode([
|
|
947
|
-
'app_key' => $appKey,
|
|
948
946
|
'secret_key' => $secretKey,
|
|
949
947
|
'ts' => time(),
|
|
950
948
|
]);
|
|
951
949
|
|
|
952
|
-
$encrypted = openssl_encrypt($payload, 'aes-256-cbc', $aesKey,
|
|
950
|
+
$encrypted = openssl_encrypt($payload, 'aes-256-cbc', $aesKey, OPENSSL_RAW_DATA, $iv);
|
|
951
|
+
$encryptedCredentials = base64_encode($iv . '::' . base64_encode($encrypted));
|
|
953
952
|
|
|
954
953
|
return response()->json([
|
|
955
954
|
'success' => true,
|
|
956
955
|
'app_key' => $appKey, // En clair (non sensible, sert d'identifiant pour l'IAM)
|
|
957
|
-
'encrypted_credentials' =>
|
|
956
|
+
'encrypted_credentials' => $encryptedCredentials,
|
|
957
|
+
'iam_api_url' => config('services.iam.api_url', 'https://identityam.ollaid.com/api'),
|
|
958
|
+
'credentials_ttl' => 300,
|
|
958
959
|
'debug' => (bool) config('services.iam.debug'), // Contrôlé par IAM_DEBUG dans .env
|
|
959
960
|
]);
|
|
960
961
|
}
|
|
@@ -983,18 +984,17 @@ class NativeAuthController extends Controller
|
|
|
983
984
|
], 400);
|
|
984
985
|
}
|
|
985
986
|
|
|
986
|
-
// ⚠️ IMPORTANT : Remplacer les espaces par '+' (encodage URL)
|
|
987
|
-
$callbackToken = str_replace(' ', '+', $callbackToken);
|
|
988
|
-
|
|
989
987
|
try {
|
|
990
|
-
$response = Http::timeout(30)
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
'
|
|
994
|
-
'
|
|
995
|
-
'
|
|
996
|
-
]
|
|
997
|
-
|
|
988
|
+
$response = Http::timeout(30)
|
|
989
|
+
->withHeaders([
|
|
990
|
+
'Content-Type' => 'application/json',
|
|
991
|
+
'Accept' => 'application/json',
|
|
992
|
+
'X-IAM-App-Key' => config('services.iam.app_key'),
|
|
993
|
+
'X-IAM-Secret-Key' => config('services.iam.secret_key'),
|
|
994
|
+
])
|
|
995
|
+
->post(config('services.iam.api_url') . '/iam/auth/decrypt', [
|
|
996
|
+
'token' => $callbackToken,
|
|
997
|
+
]);
|
|
998
998
|
|
|
999
999
|
if (!$response->successful() || !$response->json('success')) {
|
|
1000
1000
|
$error = $response->json();
|
|
@@ -1052,8 +1052,15 @@ class NativeAuthController extends Controller
|
|
|
1052
1052
|
$expiresAt = now()->addDays(30);
|
|
1053
1053
|
$token = $user->createToken('native-sso', ['*'], $expiresAt);
|
|
1054
1054
|
|
|
1055
|
-
// Récupérer app_access_token_ref depuis la réponse IAM
|
|
1056
|
-
$appAccessTokenRef = $
|
|
1055
|
+
// Récupérer app_access_token_ref depuis la racine de la réponse IAM
|
|
1056
|
+
$appAccessTokenRef = $data['app_access_token_ref'] ?? null;
|
|
1057
|
+
|
|
1058
|
+
// Stocker la ref dans le token Sanctum pour le webhook de révocation
|
|
1059
|
+
if ($appAccessTokenRef) {
|
|
1060
|
+
$token->accessToken->forceFill([
|
|
1061
|
+
'app_access_token_ref' => $appAccessTokenRef,
|
|
1062
|
+
])->save();
|
|
1063
|
+
}
|
|
1057
1064
|
|
|
1058
1065
|
return response()->json([
|
|
1059
1066
|
'success' => true,
|
|
@@ -1115,8 +1122,9 @@ class NativeAuthController extends Controller
|
|
|
1115
1122
|
$user = $request->user();
|
|
1116
1123
|
|
|
1117
1124
|
return response()->json([
|
|
1118
|
-
'status'
|
|
1119
|
-
'
|
|
1125
|
+
'status' => 'connected',
|
|
1126
|
+
'message' => 'Utilisateur connecté',
|
|
1127
|
+
'user' => [
|
|
1120
1128
|
'name' => $user->name,
|
|
1121
1129
|
'email' => $user->email,
|
|
1122
1130
|
'ccphone' => $user->ccphone,
|
|
@@ -1145,14 +1153,17 @@ class NativeAuthController extends Controller
|
|
|
1145
1153
|
|
|
1146
1154
|
if ($user) {
|
|
1147
1155
|
$sanctumTokenPlain = $request->bearerToken();
|
|
1148
|
-
$user->currentAccessToken()
|
|
1156
|
+
$currentToken = $user->currentAccessToken();
|
|
1157
|
+
$appAccessTokenRef = $currentToken?->app_access_token_ref ?? null;
|
|
1158
|
+
|
|
1159
|
+
// Supprimer le token APRÈS avoir lu la ref
|
|
1160
|
+
$currentToken?->delete();
|
|
1149
1161
|
|
|
1150
1162
|
// Notifier l'IAM (fire-and-forget, timeout 5s)
|
|
1151
|
-
if ($sanctumTokenPlain) {
|
|
1163
|
+
if ($sanctumTokenPlain || $appAccessTokenRef) {
|
|
1152
1164
|
$iamPrefix = $request->attributes->get('iam_prefix', 'iam');
|
|
1153
1165
|
$iamApiUrl = config("services.{$iamPrefix}.api_url", 'https://identityam.ollaid.com/api');
|
|
1154
1166
|
try {
|
|
1155
|
-
$appAccessTokenRef = $user->currentAccessToken()->app_access_token_ref ?? null;
|
|
1156
1167
|
Http::timeout(5)->post("{$iamApiUrl}/iam/disconnect", array_filter([
|
|
1157
1168
|
'sanctum_token' => $sanctumTokenPlain,
|
|
1158
1169
|
'app_access_token_ref' => $appAccessTokenRef,
|
|
@@ -1277,7 +1288,7 @@ Ajoutez ces variables dans le fichier `.env` du backend SaaS :
|
|
|
1277
1288
|
# Credentials IAM (récupérés depuis le dashboard iam.ollaid.com)
|
|
1278
1289
|
IAM_APP_KEY=oiam_ak_xxxxxxxxxxxxxxxxxxxxxxxx
|
|
1279
1290
|
IAM_SECRET_KEY=oiam_sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
|
1280
|
-
|
|
1291
|
+
IAM_API_URL=https://identityam.ollaid.com/api
|
|
1281
1292
|
|
|
1282
1293
|
# Mode debug — contrôle le DebugPanel et les logs côté frontend
|
|
1283
1294
|
# true : active le DebugPanel + logs console + détails d'erreur dans les réponses JSON
|
|
@@ -1294,7 +1305,7 @@ Et dans `config/services.php` :
|
|
|
1294
1305
|
'iam' => [
|
|
1295
1306
|
'app_key' => env('IAM_APP_KEY'),
|
|
1296
1307
|
'secret_key' => env('IAM_SECRET_KEY'),
|
|
1297
|
-
'
|
|
1308
|
+
'api_url' => env('IAM_API_URL', 'https://identityam.ollaid.com/api'),
|
|
1298
1309
|
'debug' => env('IAM_DEBUG', false), // Active le debug côté frontend (false si absent)
|
|
1299
1310
|
],
|
|
1300
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;
|