react-native-nitro-auth 0.5.3 → 0.5.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 +60 -30
- package/android/build.gradle +2 -5
- package/android/src/main/cpp/JniOnLoad.cpp +3 -1
- package/android/src/main/cpp/PlatformAuth+Android.cpp +95 -29
- package/android/src/main/java/com/auth/AuthAdapter.kt +124 -126
- package/android/src/main/java/com/auth/NitroAuthModule.kt +8 -1
- package/cpp/AuthCache.cpp +0 -44
- package/cpp/AuthCache.hpp +0 -7
- package/cpp/HybridAuth.cpp +20 -2
- package/cpp/HybridAuth.hpp +1 -0
- package/ios/AuthAdapter.swift +64 -28
- package/lib/commonjs/Auth.web.js +96 -43
- package/lib/commonjs/Auth.web.js.map +1 -1
- package/lib/commonjs/index.js +23 -1
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/service.js +33 -8
- package/lib/commonjs/service.js.map +1 -1
- package/lib/commonjs/use-auth.js +51 -54
- package/lib/commonjs/use-auth.js.map +1 -1
- package/lib/commonjs/utils/auth-error.js +37 -0
- package/lib/commonjs/utils/auth-error.js.map +1 -0
- package/lib/module/Auth.web.js +96 -43
- package/lib/module/Auth.web.js.map +1 -1
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/service.js +33 -8
- package/lib/module/service.js.map +1 -1
- package/lib/module/use-auth.js +51 -54
- package/lib/module/use-auth.js.map +1 -1
- package/lib/module/utils/auth-error.js +30 -0
- package/lib/module/utils/auth-error.js.map +1 -0
- package/lib/typescript/commonjs/Auth.web.d.ts +7 -0
- package/lib/typescript/commonjs/Auth.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/index.d.ts +1 -0
- package/lib/typescript/commonjs/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/service.d.ts.map +1 -1
- package/lib/typescript/commonjs/use-auth.d.ts +2 -1
- package/lib/typescript/commonjs/use-auth.d.ts.map +1 -1
- package/lib/typescript/commonjs/utils/auth-error.d.ts +16 -0
- package/lib/typescript/commonjs/utils/auth-error.d.ts.map +1 -0
- package/lib/typescript/module/Auth.web.d.ts +7 -0
- package/lib/typescript/module/Auth.web.d.ts.map +1 -1
- package/lib/typescript/module/index.d.ts +1 -0
- package/lib/typescript/module/index.d.ts.map +1 -1
- package/lib/typescript/module/service.d.ts.map +1 -1
- package/lib/typescript/module/use-auth.d.ts +2 -1
- package/lib/typescript/module/use-auth.d.ts.map +1 -1
- package/lib/typescript/module/utils/auth-error.d.ts +16 -0
- package/lib/typescript/module/utils/auth-error.d.ts.map +1 -0
- package/nitrogen/generated/android/NitroAuthOnLoad.cpp +22 -17
- package/nitrogen/generated/android/NitroAuthOnLoad.hpp +13 -4
- package/package.json +7 -7
- package/react-native-nitro-auth.podspec +1 -1
- package/src/Auth.web.ts +124 -50
- package/src/index.ts +1 -0
- package/src/service.ts +34 -8
- package/src/use-auth.ts +81 -114
- package/src/utils/auth-error.ts +49 -0
- package/ios/KeychainStore.swift +0 -43
package/README.md
CHANGED
|
@@ -71,11 +71,11 @@ bun add react-native-nitro-auth react-native-nitro-modules
|
|
|
71
71
|
|
|
72
72
|
### Requirements
|
|
73
73
|
|
|
74
|
-
| Dependency | Version
|
|
75
|
-
| ---------------------------- |
|
|
76
|
-
| `react-native` | `>= 0.75.0`
|
|
77
|
-
| `react-native-nitro-modules` | `>= 0.
|
|
78
|
-
| `react` | `*`
|
|
74
|
+
| Dependency | Version |
|
|
75
|
+
| ---------------------------- | ------------ |
|
|
76
|
+
| `react-native` | `>= 0.75.0` |
|
|
77
|
+
| `react-native-nitro-modules` | `>= 0.35.0` |
|
|
78
|
+
| `react` | `*` |
|
|
79
79
|
|
|
80
80
|
For Expo projects, rebuild native code after installation:
|
|
81
81
|
|
|
@@ -670,17 +670,25 @@ const freshToken = await AuthService.getAccessToken();
|
|
|
670
670
|
|
|
671
671
|
### Standardized Error Codes
|
|
672
672
|
|
|
673
|
-
|
|
673
|
+
All errors thrown by `AuthService` and `useAuth` are `AuthError` instances with a type-safe `code` field (always a valid `AuthErrorCode`) and an optional `underlyingMessage` with the raw provider string when it differs from the code.
|
|
674
674
|
|
|
675
675
|
```ts
|
|
676
|
+
import { AuthError } from "react-native-nitro-auth";
|
|
677
|
+
|
|
676
678
|
try {
|
|
677
679
|
await login("google");
|
|
678
680
|
} catch (e) {
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
681
|
+
if (e instanceof AuthError) {
|
|
682
|
+
switch (e.code) {
|
|
683
|
+
case "cancelled":
|
|
684
|
+
// User closed the popup/picker
|
|
685
|
+
break;
|
|
686
|
+
case "network_error":
|
|
687
|
+
// Connection issues
|
|
688
|
+
break;
|
|
689
|
+
default:
|
|
690
|
+
console.error(e.code, e.underlyingMessage);
|
|
691
|
+
}
|
|
684
692
|
}
|
|
685
693
|
}
|
|
686
694
|
```
|
|
@@ -701,24 +709,24 @@ try {
|
|
|
701
709
|
|
|
702
710
|
### Native Error Metadata
|
|
703
711
|
|
|
704
|
-
|
|
712
|
+
`AuthError` carries the raw provider/native message in `underlyingMessage` when the platform error didn't map to a known code:
|
|
705
713
|
|
|
706
714
|
```ts
|
|
707
|
-
|
|
708
|
-
const { user } = useAuth();
|
|
709
|
-
if (user?.underlyingError) {
|
|
710
|
-
console.warn("Auth warning:", user.underlyingError);
|
|
711
|
-
}
|
|
715
|
+
import { AuthError } from "react-native-nitro-auth";
|
|
712
716
|
|
|
713
|
-
// From error (on failure)
|
|
714
717
|
try {
|
|
715
718
|
await login("google");
|
|
716
719
|
} catch (e) {
|
|
717
|
-
|
|
718
|
-
|
|
720
|
+
if (e instanceof AuthError) {
|
|
721
|
+
// e.code is always a valid AuthErrorCode
|
|
722
|
+
// e.underlyingMessage is the original native string (or undefined if it equalled the code)
|
|
723
|
+
console.log(e.code, e.underlyingMessage);
|
|
724
|
+
}
|
|
719
725
|
}
|
|
720
726
|
```
|
|
721
727
|
|
|
728
|
+
The `AuthUser.underlyingError` field carries a raw warning string when the provider returns one alongside a successful result.
|
|
729
|
+
|
|
722
730
|
### Troubleshooting
|
|
723
731
|
|
|
724
732
|
- `configuration_error`: verify client IDs, URL schemes, and redirect URIs are set for the current platform.
|
|
@@ -797,6 +805,9 @@ This is useful for scenarios where:
|
|
|
797
805
|
```ts
|
|
798
806
|
import {
|
|
799
807
|
AuthService,
|
|
808
|
+
AuthError,
|
|
809
|
+
isAuthErrorCode,
|
|
810
|
+
toAuthErrorCode,
|
|
800
811
|
SocialButton,
|
|
801
812
|
useAuth,
|
|
802
813
|
type UseAuthReturn,
|
|
@@ -869,7 +880,7 @@ declare function useAuth(): UseAuthReturn;
|
|
|
869
880
|
| `user` | `AuthUser \| undefined` | Current in-memory user |
|
|
870
881
|
| `scopes` | `string[]` | Current granted scopes |
|
|
871
882
|
| `loading` | `boolean` | `true` while an auth operation is in-flight |
|
|
872
|
-
| `error` | `
|
|
883
|
+
| `error` | `AuthError \| undefined` | Last operation error (typed, safe to switch on `.code`) |
|
|
873
884
|
| `hasPlayServices` | `boolean` | Android Play Services availability |
|
|
874
885
|
| `login` | `(provider: AuthProvider, options?: LoginOptions) => Promise<void>` | Starts provider login |
|
|
875
886
|
| `logout` | `() => void` | Clears current session |
|
|
@@ -965,17 +976,36 @@ There is no public `setStorageAdapter`/`setJSStorageAdapter` API in this package
|
|
|
965
976
|
| `nitroAuthWebStorage` | `"session" \| "local" \| "memory"` | `"session"` | Storage for non-sensitive web cache |
|
|
966
977
|
| `nitroAuthPersistTokensOnWeb` | `boolean` | `false` | Persist sensitive tokens on web storage instead of memory |
|
|
967
978
|
|
|
968
|
-
###
|
|
979
|
+
### `AuthError`
|
|
980
|
+
|
|
981
|
+
All thrown errors from `AuthService` and `useAuth` are `AuthError` instances.
|
|
982
|
+
|
|
983
|
+
```ts
|
|
984
|
+
class AuthError extends Error {
|
|
985
|
+
readonly code: AuthErrorCode; // Always a valid AuthErrorCode — safe to switch on
|
|
986
|
+
readonly underlyingMessage?: string; // Raw native/platform string when it differs from code
|
|
987
|
+
static from(e: unknown): AuthError; // Wraps any value; passes AuthError instances through
|
|
988
|
+
}
|
|
969
989
|
|
|
970
|
-
|
|
990
|
+
function isAuthErrorCode(value: string): value is AuthErrorCode;
|
|
991
|
+
function toAuthErrorCode(raw: string): AuthErrorCode; // Returns "unknown" for unrecognized strings
|
|
992
|
+
```
|
|
971
993
|
|
|
972
|
-
|
|
|
973
|
-
|
|
|
974
|
-
| `cancelled`
|
|
975
|
-
| `timeout`
|
|
976
|
-
| `popup_blocked`
|
|
977
|
-
| `network_error`
|
|
978
|
-
| `configuration_error`
|
|
994
|
+
| `code` | Meaning |
|
|
995
|
+
| ---------------------- | ---------------------------------------------- |
|
|
996
|
+
| `cancelled` | User cancelled the login flow |
|
|
997
|
+
| `timeout` | Provider popup did not complete before timeout |
|
|
998
|
+
| `popup_blocked` | Browser blocked popup opening |
|
|
999
|
+
| `network_error` | Network failure |
|
|
1000
|
+
| `configuration_error` | Missing/invalid provider configuration |
|
|
1001
|
+
| `unsupported_provider` | Provider not supported on this platform |
|
|
1002
|
+
| `invalid_state` | PKCE state mismatch (possible CSRF) |
|
|
1003
|
+
| `invalid_nonce` | Nonce mismatch in token response |
|
|
1004
|
+
| `token_error` | Token exchange failed |
|
|
1005
|
+
| `no_id_token` | No `id_token` in token response |
|
|
1006
|
+
| `parse_error` | Failed to parse token response |
|
|
1007
|
+
| `refresh_failed` | Refresh token flow failed |
|
|
1008
|
+
| `unknown` | Unrecognized error |
|
|
979
1009
|
|
|
980
1010
|
## Quality Gates
|
|
981
1011
|
|
package/android/build.gradle
CHANGED
|
@@ -93,7 +93,7 @@ dependencies {
|
|
|
93
93
|
implementation project(":react-native-nitro-modules")
|
|
94
94
|
|
|
95
95
|
// Google Sign-In SDK (full scope support)
|
|
96
|
-
implementation "com.google.android.gms:play-services-auth:21.
|
|
96
|
+
implementation "com.google.android.gms:play-services-auth:21.5.1"
|
|
97
97
|
|
|
98
98
|
// Activity result APIs
|
|
99
99
|
implementation "androidx.activity:activity-ktx:1.9.3"
|
|
@@ -104,8 +104,5 @@ dependencies {
|
|
|
104
104
|
// Google Credential Manager (One-Tap / Passkeys)
|
|
105
105
|
implementation "androidx.credentials:credentials:1.5.0"
|
|
106
106
|
implementation "androidx.credentials:credentials-play-services-auth:1.5.0"
|
|
107
|
-
implementation "com.google.android.libraries.identity.googleid:googleid:1.
|
|
108
|
-
|
|
109
|
-
// Secure storage (EncryptedSharedPreferences)
|
|
110
|
-
implementation "androidx.security:security-crypto:1.0.0"
|
|
107
|
+
implementation "com.google.android.libraries.identity.googleid:googleid:1.2.0"
|
|
111
108
|
}
|
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
#include <fbjni/fbjni.h>
|
|
7
7
|
#include <NitroModules/NitroLogger.hpp>
|
|
8
8
|
#include <NitroModules/Promise.hpp>
|
|
9
|
+
#include <exception>
|
|
10
|
+
#include <stdexcept>
|
|
9
11
|
|
|
10
12
|
namespace margelo::nitro::NitroAuth {
|
|
11
13
|
|
|
@@ -24,6 +26,33 @@ static std::shared_ptr<Promise<AuthUser>> gScopesPromise;
|
|
|
24
26
|
static std::shared_ptr<Promise<AuthTokens>> gRefreshPromise;
|
|
25
27
|
static std::shared_ptr<Promise<std::optional<AuthUser>>> gSilentPromise;
|
|
26
28
|
static std::mutex gMutex;
|
|
29
|
+
static jclass gAuthAdapterClass = nullptr;
|
|
30
|
+
static jmethodID gLoginMethod = nullptr;
|
|
31
|
+
static jmethodID gRequestScopesMethod = nullptr;
|
|
32
|
+
|
|
33
|
+
static void ensureAuthAdapterMethods(JNIEnv* env) {
|
|
34
|
+
if (gAuthAdapterClass != nullptr && gLoginMethod != nullptr && gRequestScopesMethod != nullptr) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
jclass localAdapterClass = env->FindClass("com/auth/AuthAdapter");
|
|
39
|
+
if (localAdapterClass == nullptr) {
|
|
40
|
+
throw std::runtime_error("Unable to resolve com/auth/AuthAdapter");
|
|
41
|
+
}
|
|
42
|
+
gAuthAdapterClass = static_cast<jclass>(env->NewGlobalRef(localAdapterClass));
|
|
43
|
+
env->DeleteLocalRef(localAdapterClass);
|
|
44
|
+
|
|
45
|
+
gLoginMethod = env->GetStaticMethodID(
|
|
46
|
+
gAuthAdapterClass,
|
|
47
|
+
"loginSync",
|
|
48
|
+
"(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;ZZZLjava/lang/String;Ljava/lang/String;)V"
|
|
49
|
+
);
|
|
50
|
+
gRequestScopesMethod = env->GetStaticMethodID(
|
|
51
|
+
gAuthAdapterClass,
|
|
52
|
+
"requestScopesSync",
|
|
53
|
+
"(Landroid/content/Context;[Ljava/lang/String;)V"
|
|
54
|
+
);
|
|
55
|
+
}
|
|
27
56
|
|
|
28
57
|
std::shared_ptr<Promise<AuthUser>> PlatformAuth::login(AuthProvider provider, const std::optional<LoginOptions>& options) {
|
|
29
58
|
auto promise = Promise<AuthUser>::create();
|
|
@@ -35,6 +64,9 @@ std::shared_ptr<Promise<AuthUser>> PlatformAuth::login(AuthProvider provider, co
|
|
|
35
64
|
|
|
36
65
|
{
|
|
37
66
|
std::lock_guard<std::mutex> lock(gMutex);
|
|
67
|
+
if (gLoginPromise) {
|
|
68
|
+
gLoginPromise->reject(std::make_exception_ptr(std::runtime_error("Login request superseded by a newer request")));
|
|
69
|
+
}
|
|
38
70
|
gLoginPromise = promise;
|
|
39
71
|
}
|
|
40
72
|
|
|
@@ -71,30 +103,47 @@ std::shared_ptr<Promise<AuthUser>> PlatformAuth::login(AuthProvider provider, co
|
|
|
71
103
|
}
|
|
72
104
|
|
|
73
105
|
JNIEnv* env = Environment::current();
|
|
106
|
+
try {
|
|
107
|
+
ensureAuthAdapterMethods(env);
|
|
108
|
+
} catch (...) {
|
|
109
|
+
promise->reject(std::current_exception());
|
|
110
|
+
return promise;
|
|
111
|
+
}
|
|
74
112
|
jclass stringClass = env->FindClass("java/lang/String");
|
|
75
113
|
jobjectArray jScopes = env->NewObjectArray(scopes.size(), stringClass, nullptr);
|
|
76
114
|
for (size_t i = 0; i < scopes.size(); i++) {
|
|
77
115
|
env->SetObjectArrayElement(jScopes, i, make_jstring(scopes[i]).get());
|
|
78
116
|
}
|
|
79
117
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
118
|
+
local_ref<JString> providerRef = make_jstring(providerStr);
|
|
119
|
+
local_ref<JString> loginHintRef;
|
|
120
|
+
local_ref<JString> tenantRef;
|
|
121
|
+
local_ref<JString> promptRef;
|
|
122
|
+
|
|
123
|
+
if (loginHint.has_value()) {
|
|
124
|
+
loginHintRef = make_jstring(loginHint.value());
|
|
125
|
+
}
|
|
126
|
+
if (tenant.has_value()) {
|
|
127
|
+
tenantRef = make_jstring(tenant.value());
|
|
128
|
+
}
|
|
129
|
+
if (prompt.has_value()) {
|
|
130
|
+
promptRef = make_jstring(prompt.value());
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
env->CallStaticVoidMethod(gAuthAdapterClass, gLoginMethod,
|
|
88
134
|
contextPtr,
|
|
89
|
-
|
|
135
|
+
providerRef.get(),
|
|
90
136
|
nullptr,
|
|
91
137
|
jScopes,
|
|
92
|
-
|
|
138
|
+
loginHintRef.get(),
|
|
93
139
|
(jboolean)useOneTap,
|
|
94
140
|
(jboolean)forceAccountPicker,
|
|
95
141
|
(jboolean)useLegacyGoogleSignIn,
|
|
96
|
-
|
|
97
|
-
|
|
142
|
+
tenantRef.get(),
|
|
143
|
+
promptRef.get());
|
|
144
|
+
|
|
145
|
+
env->DeleteLocalRef(jScopes);
|
|
146
|
+
env->DeleteLocalRef(stringClass);
|
|
98
147
|
|
|
99
148
|
return promise;
|
|
100
149
|
}
|
|
@@ -109,20 +158,28 @@ std::shared_ptr<Promise<AuthUser>> PlatformAuth::requestScopes(const std::vector
|
|
|
109
158
|
|
|
110
159
|
{
|
|
111
160
|
std::lock_guard<std::mutex> lock(gMutex);
|
|
161
|
+
if (gScopesPromise) {
|
|
162
|
+
gScopesPromise->reject(std::make_exception_ptr(std::runtime_error("Scope request superseded by a newer request")));
|
|
163
|
+
}
|
|
112
164
|
gScopesPromise = promise;
|
|
113
165
|
}
|
|
114
166
|
|
|
115
167
|
JNIEnv* env = Environment::current();
|
|
168
|
+
try {
|
|
169
|
+
ensureAuthAdapterMethods(env);
|
|
170
|
+
} catch (...) {
|
|
171
|
+
promise->reject(std::current_exception());
|
|
172
|
+
return promise;
|
|
173
|
+
}
|
|
116
174
|
jclass stringClass = env->FindClass("java/lang/String");
|
|
117
175
|
jobjectArray jScopes = env->NewObjectArray(scopes.size(), stringClass, nullptr);
|
|
118
176
|
for (size_t i = 0; i < scopes.size(); i++) {
|
|
119
177
|
env->SetObjectArrayElement(jScopes, i, make_jstring(scopes[i]).get());
|
|
120
178
|
}
|
|
121
179
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
env->CallStaticVoidMethod(adapterClass, requestMethod, contextPtr, jScopes);
|
|
180
|
+
env->CallStaticVoidMethod(gAuthAdapterClass, gRequestScopesMethod, contextPtr, jScopes);
|
|
181
|
+
env->DeleteLocalRef(jScopes);
|
|
182
|
+
env->DeleteLocalRef(stringClass);
|
|
126
183
|
return promise;
|
|
127
184
|
}
|
|
128
185
|
|
|
@@ -136,6 +193,9 @@ std::shared_ptr<Promise<AuthTokens>> PlatformAuth::refreshToken() {
|
|
|
136
193
|
|
|
137
194
|
{
|
|
138
195
|
std::lock_guard<std::mutex> lock(gMutex);
|
|
196
|
+
if (gRefreshPromise) {
|
|
197
|
+
gRefreshPromise->reject(std::make_exception_ptr(std::runtime_error("Refresh request superseded by a newer request")));
|
|
198
|
+
}
|
|
139
199
|
gRefreshPromise = promise;
|
|
140
200
|
}
|
|
141
201
|
|
|
@@ -155,6 +215,9 @@ std::shared_ptr<Promise<std::optional<AuthUser>>> PlatformAuth::silentRestore()
|
|
|
155
215
|
|
|
156
216
|
{
|
|
157
217
|
std::lock_guard<std::mutex> lock(gMutex);
|
|
218
|
+
if (gSilentPromise) {
|
|
219
|
+
gSilentPromise->reject(std::make_exception_ptr(std::runtime_error("Silent restore superseded by a newer request")));
|
|
220
|
+
}
|
|
158
221
|
gSilentPromise = promise;
|
|
159
222
|
}
|
|
160
223
|
|
|
@@ -182,8 +245,8 @@ void PlatformAuth::logout() {
|
|
|
182
245
|
logoutMethod(JAuthAdapter::javaClassStatic(), static_ref_cast<JContext>(jContext));
|
|
183
246
|
}
|
|
184
247
|
|
|
185
|
-
extern "C" JNIEXPORT void JNICALL Java_com_auth_AuthAdapter_nativeInitialize(JNIEnv
|
|
186
|
-
AuthCache::setAndroidContext(
|
|
248
|
+
extern "C" JNIEXPORT void JNICALL Java_com_auth_AuthAdapter_nativeInitialize(JNIEnv*, jclass, jobject context) {
|
|
249
|
+
AuthCache::setAndroidContext(context);
|
|
187
250
|
}
|
|
188
251
|
|
|
189
252
|
extern "C" JNIEXPORT void JNICALL Java_com_auth_AuthAdapter_nativeOnLoginSuccess(
|
|
@@ -253,6 +316,7 @@ extern "C" JNIEXPORT void JNICALL Java_com_auth_AuthAdapter_nativeOnLoginSuccess
|
|
|
253
316
|
const char* s = env->GetStringUTFChars(jstr, nullptr);
|
|
254
317
|
scopeVec.push_back(std::string(s));
|
|
255
318
|
env->ReleaseStringUTFChars(jstr, s);
|
|
319
|
+
env->DeleteLocalRef(jstr);
|
|
256
320
|
}
|
|
257
321
|
user.scopes = scopeVec;
|
|
258
322
|
}
|
|
@@ -260,6 +324,7 @@ extern "C" JNIEXPORT void JNICALL Java_com_auth_AuthAdapter_nativeOnLoginSuccess
|
|
|
260
324
|
jclass longClass = env->FindClass("java/lang/Long");
|
|
261
325
|
jmethodID longValueMethod = env->GetMethodID(longClass, "longValue", "()J");
|
|
262
326
|
user.expirationTime = (double)env->CallLongMethod(expirationTime, longValueMethod);
|
|
327
|
+
env->DeleteLocalRef(longClass);
|
|
263
328
|
}
|
|
264
329
|
|
|
265
330
|
if (loginPromise) loginPromise->resolve(user);
|
|
@@ -286,19 +351,21 @@ extern "C" JNIEXPORT void JNICALL Java_com_auth_AuthAdapter_nativeOnLoginError(
|
|
|
286
351
|
const char* errorCStr = env->GetStringUTFChars(error, nullptr);
|
|
287
352
|
std::string errorStr(errorCStr);
|
|
288
353
|
env->ReleaseStringUTFChars(error, errorCStr);
|
|
289
|
-
|
|
290
|
-
|
|
354
|
+
|
|
355
|
+
// errorStr is the structured AuthErrorCode (e.g. "cancelled", "network_error").
|
|
356
|
+
// underlyingError is a raw platform message for debugging — it must not replace the code.
|
|
291
357
|
if (underlyingError) {
|
|
292
358
|
const char* uCStr = env->GetStringUTFChars(underlyingError, nullptr);
|
|
293
|
-
finalError = std::string(uCStr);
|
|
294
359
|
env->ReleaseStringUTFChars(underlyingError, uCStr);
|
|
360
|
+
// underlyingError is intentionally discarded here; the structured code is sufficient
|
|
361
|
+
// for consumers. If richer debugging is needed, add it to the AuthUser.underlyingError field.
|
|
295
362
|
}
|
|
296
363
|
|
|
297
|
-
if (loginPromise) loginPromise->reject(std::make_exception_ptr(std::runtime_error(
|
|
298
|
-
if (scopesPromise) scopesPromise->reject(std::make_exception_ptr(std::runtime_error(
|
|
364
|
+
if (loginPromise) loginPromise->reject(std::make_exception_ptr(std::runtime_error(errorStr)));
|
|
365
|
+
if (scopesPromise) scopesPromise->reject(std::make_exception_ptr(std::runtime_error(errorStr)));
|
|
299
366
|
if (silentPromise) {
|
|
300
367
|
if (errorStr == "No session") silentPromise->resolve(std::nullopt);
|
|
301
|
-
else silentPromise->reject(std::make_exception_ptr(std::runtime_error(
|
|
368
|
+
else silentPromise->reject(std::make_exception_ptr(std::runtime_error(errorStr)));
|
|
302
369
|
}
|
|
303
370
|
}
|
|
304
371
|
|
|
@@ -328,6 +395,7 @@ extern "C" JNIEXPORT void JNICALL Java_com_auth_AuthAdapter_nativeOnRefreshSucce
|
|
|
328
395
|
jclass longClass = env->FindClass("java/lang/Long");
|
|
329
396
|
jmethodID longValueMethod = env->GetMethodID(longClass, "longValue", "()J");
|
|
330
397
|
tokens.expirationTime = (double)env->CallLongMethod(expirationTime, longValueMethod);
|
|
398
|
+
env->DeleteLocalRef(longClass);
|
|
331
399
|
}
|
|
332
400
|
refreshPromise->resolve(tokens);
|
|
333
401
|
}
|
|
@@ -343,17 +411,15 @@ extern "C" JNIEXPORT void JNICALL Java_com_auth_AuthAdapter_nativeOnRefreshError
|
|
|
343
411
|
gRefreshPromise = nullptr;
|
|
344
412
|
}
|
|
345
413
|
if (refreshPromise) {
|
|
346
|
-
std::string finalError;
|
|
347
414
|
const char* errorCStr = env->GetStringUTFChars(error, nullptr);
|
|
348
|
-
|
|
415
|
+
std::string errorStr(errorCStr);
|
|
349
416
|
env->ReleaseStringUTFChars(error, errorCStr);
|
|
350
|
-
|
|
417
|
+
|
|
351
418
|
if (underlyingError) {
|
|
352
419
|
const char* uCStr = env->GetStringUTFChars(underlyingError, nullptr);
|
|
353
|
-
finalError = std::string(uCStr);
|
|
354
420
|
env->ReleaseStringUTFChars(underlyingError, uCStr);
|
|
355
421
|
}
|
|
356
|
-
refreshPromise->reject(std::make_exception_ptr(std::runtime_error(
|
|
422
|
+
refreshPromise->reject(std::make_exception_ptr(std::runtime_error(errorStr)));
|
|
357
423
|
}
|
|
358
424
|
}
|
|
359
425
|
|