react-native-credentials-manager 0.2.1 → 0.4.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.
Files changed (34) hide show
  1. package/README.md +65 -3
  2. package/android/build.gradle +9 -9
  3. package/android/generated/java/com/credentialsmanager/NativeCredentialsManagerSpec.java +8 -0
  4. package/android/generated/jni/RNCredentialsManagerSpec-generated.cpp +12 -0
  5. package/android/generated/jni/react/renderer/components/RNCredentialsManagerSpec/RNCredentialsManagerSpecJSI-generated.cpp +13 -0
  6. package/android/generated/jni/react/renderer/components/RNCredentialsManagerSpec/RNCredentialsManagerSpecJSI.h +118 -0
  7. package/android/src/main/java/com/credentialsmanager/CredentialsManagerModuleImpl.kt +7 -0
  8. package/android/src/main/java/com/credentialsmanager/CredentialsManagerPackage.kt +6 -5
  9. package/android/src/main/java/com/credentialsmanager/handlers/CredentialHandler.kt +178 -0
  10. package/android/src/main/java/com/credentialsmanager/handlers/ErrorHandler.kt +56 -0
  11. package/android/src/newarch/java/com/credentialsmanager/CredentialsManagerModule.kt +138 -0
  12. package/android/src/oldarch/java/com/credentialsmanager/CredentialsManagerModule.kt +127 -0
  13. package/ios/generated/RNCredentialsManagerSpec/RNCredentialsManagerSpec-generated.mm +20 -0
  14. package/ios/generated/RNCredentialsManagerSpec/RNCredentialsManagerSpec.h +37 -0
  15. package/ios/generated/RNCredentialsManagerSpecJSI-generated.cpp +13 -0
  16. package/ios/generated/RNCredentialsManagerSpecJSI.h +118 -0
  17. package/lib/commonjs/NativeCredentialsManager.js.map +1 -1
  18. package/lib/commonjs/index.js +12 -0
  19. package/lib/commonjs/index.js.map +1 -1
  20. package/lib/module/NativeCredentialsManager.js.map +1 -1
  21. package/lib/module/index.js +10 -0
  22. package/lib/module/index.js.map +1 -1
  23. package/lib/typescript/commonjs/src/NativeCredentialsManager.d.ts +16 -0
  24. package/lib/typescript/commonjs/src/NativeCredentialsManager.d.ts.map +1 -1
  25. package/lib/typescript/commonjs/src/index.d.ts +7 -1
  26. package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
  27. package/lib/typescript/module/src/NativeCredentialsManager.d.ts +16 -0
  28. package/lib/typescript/module/src/NativeCredentialsManager.d.ts.map +1 -1
  29. package/lib/typescript/module/src/index.d.ts +7 -1
  30. package/lib/typescript/module/src/index.d.ts.map +1 -1
  31. package/package.json +15 -3
  32. package/src/NativeCredentialsManager.ts +17 -0
  33. package/src/index.tsx +17 -1
  34. package/android/src/main/java/com/credentialsmanager/CredentialsManagerModule.kt +0 -212
package/README.md CHANGED
@@ -1,14 +1,16 @@
1
1
  # react-native-credentials-manager
2
2
 
3
+ > 📚 **Documentation has moved!** The complete documentation is now available at [https://docs.benjamineruvieru.com/docs/react-native-credentials-manager/](https://docs.benjamineruvieru.com/docs/react-native-credentials-manager/)
4
+
3
5
  A React Native library that implements the [Credential Manager API](https://developer.android.com/identity/sign-in/credential-manager) for Android. This library allows you to manage passwords and passkeys in your React Native applications.
4
6
 
5
- > ⚠️ **Note**: This library is actively under development. iOS support using Authentication Services is coming soon. Support for the old React Native architecture is also in progress. Google Sign-In integration with Credential Manager will be added shortly.
7
+ > ⚠️ **Note**: This library is actively under development. iOS support using Authentication Services is coming soon. ~~Support for the old React Native architecture is also in progress.~~ Supports old architecture now. ~~Google Sign-In integration with Credential Manager will be added shortly.~~ Google Sign-In is now supported.
6
8
 
7
9
  ## Features
8
10
 
9
11
  - ✨ Passkey Authentication
10
12
  - 🔐 Password Credential Management
11
- - 📱 Google Signing (coming soon)
13
+ - 📱 Google Signing
12
14
  - 🤖 [iOS Authentication Services](https://developer.apple.com/documentation/authenticationservices?language=objc) (coming soon)
13
15
 
14
16
  ## Installation
@@ -225,6 +227,66 @@ try {
225
227
  }
226
228
  ```
227
229
 
230
+ ### [Google Sign-In](https://developer.android.com/identity/sign-in/credential-manager-siwg#instantiate-google)
231
+
232
+ **Function**: `signInWithGoogle(params)`
233
+
234
+ **Description**: Authenticates users using Google Sign-In through the Credential Manager.
235
+
236
+ **Parameters**:
237
+
238
+ | Parameter | Type | Description |
239
+ | ------------------- | --------- | --------------------------------------------------------------------------- |
240
+ | `serverClientId` | `string` | Your application's web client ID from the Google Cloud Console |
241
+ | `nonce` | `string?` | Optional nonce for additional security |
242
+ | `autoSelectEnabled` | `boolean` | Whether to automatically select the Google account if only one is available |
243
+
244
+ **Example**:
245
+
246
+ ```typescript
247
+ import { signInWithGoogle } from 'react-native-credentials-manager';
248
+
249
+ try {
250
+ const credential = await signInWithGoogle({
251
+ serverClientId: 'YOUR_WEB_CLIENT_ID',
252
+ autoSelectEnabled: true,
253
+ });
254
+
255
+ if (credential.type === 'google-signin') {
256
+ console.log('Google credentials:', {
257
+ id: credential.id,
258
+ idToken: credential.idToken,
259
+ displayName: credential.displayName,
260
+ familyName: credential.familyName,
261
+ givenName: credential.givenName,
262
+ profilePicture: credential.profilePicture,
263
+ phoneNumber: credential.phoneNumber,
264
+ });
265
+ }
266
+ } catch (error) {
267
+ console.error('Google Sign-In failed:', error);
268
+ }
269
+ ```
270
+
271
+ ### Sign Out
272
+
273
+ Function : signOut()
274
+
275
+ Description : Signs out the current user and clears credentials.
276
+
277
+ Example :
278
+
279
+ ```typescript
280
+ import { signOut } from 'react-native-credentials-manager';
281
+
282
+ try {
283
+ await signOut();
284
+ console.log('Successfully signed out');
285
+ } catch (error) {
286
+ console.error('Sign out failed:', error);
287
+ }
288
+ ```
289
+
228
290
  ## Documentation
229
291
 
230
292
  For more detailed information about the underlying APIs, refer to:
@@ -236,7 +298,7 @@ For more detailed information about the underlying APIs, refer to:
236
298
 
237
299
  ## Roadmap
238
300
 
239
- - Old Architecture Support
301
+ - ~~Old Architecture Support~~ ✅
240
302
  - iOS Support using [Authentication Services](https://developer.apple.com/documentation/authenticationservices?language=objc)
241
303
  - Additional Authentication Methods
242
304
  - Comprehensive Documentation
@@ -79,16 +79,15 @@ android {
79
79
  targetCompatibility JavaVersion.VERSION_1_8
80
80
  }
81
81
 
82
- sourceSets {
83
- main {
84
- if (isNewArchitectureEnabled()) {
85
- java.srcDirs += [
86
- "generated/java",
87
- "generated/jni"
88
- ]
89
- }
82
+ sourceSets {
83
+ main {
84
+ if (isNewArchitectureEnabled()) {
85
+ java.srcDirs += ['src/newarch',"generated/java",]
86
+ } else {
87
+ java.srcDirs += ['src/oldarch']
88
+ }
89
+ }
90
90
  }
91
- }
92
91
  }
93
92
 
94
93
  repositories {
@@ -105,6 +104,7 @@ dependencies {
105
104
  implementation "androidx.credentials:credentials-play-services-auth:1.5.0-rc01"
106
105
  implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4"
107
106
  implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4"
107
+ implementation "com.google.android.libraries.identity.googleid:googleid:1.1.1"
108
108
  }
109
109
 
110
110
  if (isNewArchitectureEnabled()) {
@@ -44,4 +44,12 @@ public abstract class NativeCredentialsManagerSpec extends ReactContextBaseJavaM
44
44
  @ReactMethod
45
45
  @DoNotStrip
46
46
  public abstract void signInWithSavedCredentials(ReadableMap requestJson, Promise promise);
47
+
48
+ @ReactMethod
49
+ @DoNotStrip
50
+ public abstract void signInWithGoogle(ReadableMap params, Promise promise);
51
+
52
+ @ReactMethod
53
+ @DoNotStrip
54
+ public abstract void signOut(Promise promise);
47
55
  }
@@ -27,11 +27,23 @@ static facebook::jsi::Value __hostFunction_NativeCredentialsManagerSpecJSI_signI
27
27
  return static_cast<JavaTurboModule &>(turboModule).invokeJavaMethod(rt, PromiseKind, "signInWithSavedCredentials", "(Lcom/facebook/react/bridge/ReadableMap;Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId);
28
28
  }
29
29
 
30
+ static facebook::jsi::Value __hostFunction_NativeCredentialsManagerSpecJSI_signInWithGoogle(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
31
+ static jmethodID cachedMethodId = nullptr;
32
+ return static_cast<JavaTurboModule &>(turboModule).invokeJavaMethod(rt, PromiseKind, "signInWithGoogle", "(Lcom/facebook/react/bridge/ReadableMap;Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId);
33
+ }
34
+
35
+ static facebook::jsi::Value __hostFunction_NativeCredentialsManagerSpecJSI_signOut(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
36
+ static jmethodID cachedMethodId = nullptr;
37
+ return static_cast<JavaTurboModule &>(turboModule).invokeJavaMethod(rt, PromiseKind, "signOut", "(Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId);
38
+ }
39
+
30
40
  NativeCredentialsManagerSpecJSI::NativeCredentialsManagerSpecJSI(const JavaTurboModule::InitParams &params)
31
41
  : JavaTurboModule(params) {
32
42
  methodMap_["signUpWithPasskeys"] = MethodMetadata {2, __hostFunction_NativeCredentialsManagerSpecJSI_signUpWithPasskeys};
33
43
  methodMap_["signUpWithPassword"] = MethodMetadata {1, __hostFunction_NativeCredentialsManagerSpecJSI_signUpWithPassword};
34
44
  methodMap_["signInWithSavedCredentials"] = MethodMetadata {1, __hostFunction_NativeCredentialsManagerSpecJSI_signInWithSavedCredentials};
45
+ methodMap_["signInWithGoogle"] = MethodMetadata {1, __hostFunction_NativeCredentialsManagerSpecJSI_signInWithGoogle};
46
+ methodMap_["signOut"] = MethodMetadata {0, __hostFunction_NativeCredentialsManagerSpecJSI_signOut};
35
47
  }
36
48
 
37
49
  std::shared_ptr<TurboModule> RNCredentialsManagerSpec_ModuleProvider(const std::string &moduleName, const JavaTurboModule::InitParams &params) {
@@ -31,12 +31,25 @@ static jsi::Value __hostFunction_NativeCredentialsManagerCxxSpecJSI_signInWithSa
31
31
  count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asObject(rt)
32
32
  );
33
33
  }
34
+ static jsi::Value __hostFunction_NativeCredentialsManagerCxxSpecJSI_signInWithGoogle(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
35
+ return static_cast<NativeCredentialsManagerCxxSpecJSI *>(&turboModule)->signInWithGoogle(
36
+ rt,
37
+ count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asObject(rt)
38
+ );
39
+ }
40
+ static jsi::Value __hostFunction_NativeCredentialsManagerCxxSpecJSI_signOut(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
41
+ return static_cast<NativeCredentialsManagerCxxSpecJSI *>(&turboModule)->signOut(
42
+ rt
43
+ );
44
+ }
34
45
 
35
46
  NativeCredentialsManagerCxxSpecJSI::NativeCredentialsManagerCxxSpecJSI(std::shared_ptr<CallInvoker> jsInvoker)
36
47
  : TurboModule("CredentialsManager", jsInvoker) {
37
48
  methodMap_["signUpWithPasskeys"] = MethodMetadata {2, __hostFunction_NativeCredentialsManagerCxxSpecJSI_signUpWithPasskeys};
38
49
  methodMap_["signUpWithPassword"] = MethodMetadata {1, __hostFunction_NativeCredentialsManagerCxxSpecJSI_signUpWithPassword};
39
50
  methodMap_["signInWithSavedCredentials"] = MethodMetadata {1, __hostFunction_NativeCredentialsManagerCxxSpecJSI_signInWithSavedCredentials};
51
+ methodMap_["signInWithGoogle"] = MethodMetadata {1, __hostFunction_NativeCredentialsManagerCxxSpecJSI_signInWithGoogle};
52
+ methodMap_["signOut"] = MethodMetadata {0, __hostFunction_NativeCredentialsManagerCxxSpecJSI_signOut};
40
53
  }
41
54
 
42
55
 
@@ -62,6 +62,106 @@ struct NativeCredentialsManagerCredObjectBridging {
62
62
  }
63
63
  };
64
64
 
65
+
66
+
67
+ #pragma mark - NativeCredentialsManagerGoogleCredential
68
+
69
+ template <typename P0, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7>
70
+ struct NativeCredentialsManagerGoogleCredential {
71
+ P0 type;
72
+ P1 id;
73
+ P2 idToken;
74
+ P3 displayName;
75
+ P4 familyName;
76
+ P5 givenName;
77
+ P6 profilePicture;
78
+ P7 phoneNumber;
79
+ bool operator==(const NativeCredentialsManagerGoogleCredential &other) const {
80
+ return type == other.type && id == other.id && idToken == other.idToken && displayName == other.displayName && familyName == other.familyName && givenName == other.givenName && profilePicture == other.profilePicture && phoneNumber == other.phoneNumber;
81
+ }
82
+ };
83
+
84
+ template <typename T>
85
+ struct NativeCredentialsManagerGoogleCredentialBridging {
86
+ static T types;
87
+
88
+ static T fromJs(
89
+ jsi::Runtime &rt,
90
+ const jsi::Object &value,
91
+ const std::shared_ptr<CallInvoker> &jsInvoker) {
92
+ T result{
93
+ bridging::fromJs<decltype(types.type)>(rt, value.getProperty(rt, "type"), jsInvoker),
94
+ bridging::fromJs<decltype(types.id)>(rt, value.getProperty(rt, "id"), jsInvoker),
95
+ bridging::fromJs<decltype(types.idToken)>(rt, value.getProperty(rt, "idToken"), jsInvoker),
96
+ bridging::fromJs<decltype(types.displayName)>(rt, value.getProperty(rt, "displayName"), jsInvoker),
97
+ bridging::fromJs<decltype(types.familyName)>(rt, value.getProperty(rt, "familyName"), jsInvoker),
98
+ bridging::fromJs<decltype(types.givenName)>(rt, value.getProperty(rt, "givenName"), jsInvoker),
99
+ bridging::fromJs<decltype(types.profilePicture)>(rt, value.getProperty(rt, "profilePicture"), jsInvoker),
100
+ bridging::fromJs<decltype(types.phoneNumber)>(rt, value.getProperty(rt, "phoneNumber"), jsInvoker)};
101
+ return result;
102
+ }
103
+
104
+ #ifdef DEBUG
105
+ static jsi::String typeToJs(jsi::Runtime &rt, decltype(types.type) value) {
106
+ return bridging::toJs(rt, value);
107
+ }
108
+
109
+ static jsi::String idToJs(jsi::Runtime &rt, decltype(types.id) value) {
110
+ return bridging::toJs(rt, value);
111
+ }
112
+
113
+ static jsi::String idTokenToJs(jsi::Runtime &rt, decltype(types.idToken) value) {
114
+ return bridging::toJs(rt, value);
115
+ }
116
+
117
+ static jsi::String displayNameToJs(jsi::Runtime &rt, decltype(types.displayName) value) {
118
+ return bridging::toJs(rt, value);
119
+ }
120
+
121
+ static jsi::String familyNameToJs(jsi::Runtime &rt, decltype(types.familyName) value) {
122
+ return bridging::toJs(rt, value);
123
+ }
124
+
125
+ static jsi::String givenNameToJs(jsi::Runtime &rt, decltype(types.givenName) value) {
126
+ return bridging::toJs(rt, value);
127
+ }
128
+
129
+ static jsi::String profilePictureToJs(jsi::Runtime &rt, decltype(types.profilePicture) value) {
130
+ return bridging::toJs(rt, value);
131
+ }
132
+
133
+ static jsi::String phoneNumberToJs(jsi::Runtime &rt, decltype(types.phoneNumber) value) {
134
+ return bridging::toJs(rt, value);
135
+ }
136
+ #endif
137
+
138
+ static jsi::Object toJs(
139
+ jsi::Runtime &rt,
140
+ const T &value,
141
+ const std::shared_ptr<CallInvoker> &jsInvoker) {
142
+ auto result = facebook::jsi::Object(rt);
143
+ result.setProperty(rt, "type", bridging::toJs(rt, value.type, jsInvoker));
144
+ result.setProperty(rt, "id", bridging::toJs(rt, value.id, jsInvoker));
145
+ result.setProperty(rt, "idToken", bridging::toJs(rt, value.idToken, jsInvoker));
146
+ if (value.displayName) {
147
+ result.setProperty(rt, "displayName", bridging::toJs(rt, value.displayName.value(), jsInvoker));
148
+ }
149
+ if (value.familyName) {
150
+ result.setProperty(rt, "familyName", bridging::toJs(rt, value.familyName.value(), jsInvoker));
151
+ }
152
+ if (value.givenName) {
153
+ result.setProperty(rt, "givenName", bridging::toJs(rt, value.givenName.value(), jsInvoker));
154
+ }
155
+ if (value.profilePicture) {
156
+ result.setProperty(rt, "profilePicture", bridging::toJs(rt, value.profilePicture.value(), jsInvoker));
157
+ }
158
+ if (value.phoneNumber) {
159
+ result.setProperty(rt, "phoneNumber", bridging::toJs(rt, value.phoneNumber.value(), jsInvoker));
160
+ }
161
+ return result;
162
+ }
163
+ };
164
+
65
165
  class JSI_EXPORT NativeCredentialsManagerCxxSpecJSI : public TurboModule {
66
166
  protected:
67
167
  NativeCredentialsManagerCxxSpecJSI(std::shared_ptr<CallInvoker> jsInvoker);
@@ -70,6 +170,8 @@ public:
70
170
  virtual jsi::Value signUpWithPasskeys(jsi::Runtime &rt, jsi::Object requestJson, bool preferImmediatelyAvailableCredentials) = 0;
71
171
  virtual void signUpWithPassword(jsi::Runtime &rt, jsi::Object credObject) = 0;
72
172
  virtual jsi::Value signInWithSavedCredentials(jsi::Runtime &rt, jsi::Object requestJson) = 0;
173
+ virtual jsi::Value signInWithGoogle(jsi::Runtime &rt, jsi::Object params) = 0;
174
+ virtual jsi::Value signOut(jsi::Runtime &rt) = 0;
73
175
 
74
176
  };
75
177
 
@@ -124,6 +226,22 @@ private:
124
226
  return bridging::callFromJs<jsi::Value>(
125
227
  rt, &T::signInWithSavedCredentials, jsInvoker_, instance_, std::move(requestJson));
126
228
  }
229
+ jsi::Value signInWithGoogle(jsi::Runtime &rt, jsi::Object params) override {
230
+ static_assert(
231
+ bridging::getParameterCount(&T::signInWithGoogle) == 2,
232
+ "Expected signInWithGoogle(...) to have 2 parameters");
233
+
234
+ return bridging::callFromJs<jsi::Value>(
235
+ rt, &T::signInWithGoogle, jsInvoker_, instance_, std::move(params));
236
+ }
237
+ jsi::Value signOut(jsi::Runtime &rt) override {
238
+ static_assert(
239
+ bridging::getParameterCount(&T::signOut) == 1,
240
+ "Expected signOut(...) to have 1 parameters");
241
+
242
+ return bridging::callFromJs<jsi::Value>(
243
+ rt, &T::signOut, jsInvoker_, instance_);
244
+ }
127
245
 
128
246
  private:
129
247
  friend class NativeCredentialsManagerCxxSpec;
@@ -0,0 +1,7 @@
1
+ package com.credentialsmanager
2
+
3
+ class CredentialsManagerModuleImpl {
4
+ companion object {
5
+ const val NAME = "CredentialsManager"
6
+ }
7
+ }
@@ -12,7 +12,7 @@ class CredentialsManagerPackage : BaseReactPackage() {
12
12
  name: String,
13
13
  reactContext: ReactApplicationContext,
14
14
  ): NativeModule? =
15
- if (name == CredentialsManagerModule.NAME) {
15
+ if (name == CredentialsManagerModuleImpl.NAME) {
16
16
  CredentialsManagerModule(reactContext)
17
17
  } else {
18
18
  null
@@ -21,14 +21,15 @@ class CredentialsManagerPackage : BaseReactPackage() {
21
21
  override fun getReactModuleInfoProvider(): ReactModuleInfoProvider =
22
22
  ReactModuleInfoProvider {
23
23
  val moduleInfos: MutableMap<String, ReactModuleInfo> = HashMap()
24
- moduleInfos[CredentialsManagerModule.NAME] =
24
+ val isTurboModule = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
25
+ moduleInfos[CredentialsManagerModuleImpl.NAME] =
25
26
  ReactModuleInfo(
26
- CredentialsManagerModule.NAME,
27
- CredentialsManagerModule.NAME,
27
+ CredentialsManagerModuleImpl.NAME,
28
+ CredentialsManagerModuleImpl.NAME,
28
29
  false, // canOverrideExistingModule
29
30
  false, // needsEagerInit
30
31
  false, // isCxxModule
31
- true, // isTurboModule
32
+ isTurboModule, // isTurboModule
32
33
  )
33
34
  moduleInfos
34
35
  }
@@ -0,0 +1,178 @@
1
+ package com.credentialsmanager.handlers
2
+
3
+ import android.content.Context
4
+ import android.util.Log
5
+ import androidx.credentials.CreatePasswordRequest
6
+ import androidx.credentials.CreatePublicKeyCredentialRequest
7
+ import androidx.credentials.CreatePublicKeyCredentialResponse
8
+ import androidx.credentials.CredentialManager
9
+ import androidx.credentials.CustomCredential
10
+ import androidx.credentials.GetCredentialRequest
11
+ import androidx.credentials.GetCredentialResponse
12
+ import androidx.credentials.GetPasswordOption
13
+ import androidx.credentials.GetPublicKeyCredentialOption
14
+ import androidx.credentials.PasswordCredential
15
+ import androidx.credentials.PublicKeyCredential
16
+ import com.facebook.react.bridge.Arguments
17
+ import com.facebook.react.bridge.ReadableMap
18
+ import com.google.android.libraries.identity.googleid.GetGoogleIdOption
19
+ import com.google.android.libraries.identity.googleid.GoogleIdTokenCredential
20
+ import com.google.android.libraries.identity.googleid.GoogleIdTokenParsingException
21
+ import org.json.JSONObject
22
+ import androidx.credentials.ClearCredentialStateRequest
23
+
24
+ class CredentialHandler(
25
+ private val context: Context,
26
+ ) {
27
+ private val credentialManager = CredentialManager.create(context)
28
+
29
+ suspend fun signOut(){
30
+
31
+ credentialManager.clearCredentialState(ClearCredentialStateRequest())
32
+
33
+ }
34
+ suspend fun createPasskey(
35
+ jsonString: String,
36
+ preferImmediatelyAvailableCredentials: Boolean,
37
+ ): ReadableMap? {
38
+ val request =
39
+ CreatePublicKeyCredentialRequest(
40
+ requestJson = jsonString,
41
+ preferImmediatelyAvailableCredentials = preferImmediatelyAvailableCredentials,
42
+ )
43
+
44
+ val response =
45
+ credentialManager.createCredential(
46
+ context,
47
+ request,
48
+ ) as CreatePublicKeyCredentialResponse
49
+
50
+ return response.data.getString("androidx.credentials.BUNDLE_KEY_REGISTRATION_RESPONSE_JSON")?.let { json ->
51
+ val jsonObject = Arguments.createMap()
52
+ val parsedObject = JSONObject(json)
53
+
54
+ parsedObject.keys().forEach { key ->
55
+ jsonObject.putString(key, parsedObject.getString(key))
56
+ }
57
+ jsonObject
58
+ }
59
+ }
60
+
61
+ suspend fun createPassword(
62
+ username: String,
63
+ password: String,
64
+ ) {
65
+ val createPasswordRequest = CreatePasswordRequest(id = username, password = password)
66
+ credentialManager.createCredential(context, createPasswordRequest)
67
+ }
68
+
69
+ suspend fun getSavedCredentials(jsonString: String): ReadableMap? {
70
+ val getPublicKeyCredentialOption = GetPublicKeyCredentialOption(jsonString, null)
71
+ val getPasswordOption = GetPasswordOption()
72
+
73
+ val result =
74
+ credentialManager.getCredential(
75
+ context,
76
+ GetCredentialRequest(
77
+ listOf(
78
+ getPublicKeyCredentialOption,
79
+ getPasswordOption,
80
+ ),
81
+ ),
82
+ )
83
+
84
+ return handleSignInResult(result)
85
+ }
86
+
87
+ fun handleSignInResult(result: GetCredentialResponse): ReadableMap? {
88
+ // Handle the successfully returned credential.
89
+ val credential = result.credential
90
+ Log.d("CredentialManager", "Handle results called")
91
+
92
+ return when (credential) {
93
+ is PublicKeyCredential -> {
94
+ val cred = result.credential as PublicKeyCredential
95
+ Arguments.createMap().apply {
96
+ putString("type", "passkey")
97
+ putString("authenticationResponseJson", cred.authenticationResponseJson)
98
+ }
99
+ }
100
+ is PasswordCredential -> {
101
+ val cred = result.credential as PasswordCredential
102
+ Arguments.createMap().apply {
103
+ putString("type", "password")
104
+ putString("username", cred.id)
105
+ putString("password", cred.password)
106
+ }
107
+ }
108
+ // GoogleIdToken credential
109
+ is CustomCredential -> {
110
+ if (credential.type == GoogleIdTokenCredential.TYPE_GOOGLE_ID_TOKEN_CREDENTIAL) {
111
+ try {
112
+ val googleIdTokenCredential =
113
+ GoogleIdTokenCredential
114
+ .createFrom(credential.data)
115
+ Log.d("CredentialManager", "Google ID Token Credential ID: ${googleIdTokenCredential.id}")
116
+
117
+ return Arguments.createMap().apply {
118
+ putString("type", "google-signin")
119
+ putString("id", googleIdTokenCredential.id)
120
+ putString("idToken", googleIdTokenCredential.idToken)
121
+ googleIdTokenCredential.displayName?.let { putString("displayName", it) }
122
+ googleIdTokenCredential.familyName?.let { putString("familyName", it) }
123
+ googleIdTokenCredential.givenName?.let { putString("givenName", it) }
124
+ googleIdTokenCredential.profilePictureUri?.let { putString("profilePicture", it.toString()) }
125
+ googleIdTokenCredential.phoneNumber?.let { putString("phoneNumber", it) }
126
+ }
127
+ } catch (e: GoogleIdTokenParsingException) {
128
+ Log.e("CredentialManager", "Received an invalid google id token response", e)
129
+ return null
130
+ }
131
+ } else {
132
+ Log.e("CredentialManager", "Received an unexpected credential type")
133
+ return null
134
+ }
135
+ }
136
+
137
+ else -> {
138
+ // Catch any unrecognized credential type here.
139
+ Log.e("CredentialManager", "Unexpected type of credential")
140
+ return null
141
+ }
142
+ }
143
+ }
144
+
145
+ fun getGoogleId(
146
+ setFilterByAuthorizedAccounts: Boolean,
147
+ nonce: String,
148
+ serverClientId: String,
149
+ autoSelectEnabled: Boolean,
150
+ ): GetGoogleIdOption {
151
+ Log.d("CredentialManager", "getGoogleId - setFilterByAuthorizedAccounts: $setFilterByAuthorizedAccounts")
152
+
153
+ return GetGoogleIdOption
154
+ .Builder()
155
+ .setFilterByAuthorizedAccounts(setFilterByAuthorizedAccounts)
156
+ .setServerClientId(serverClientId)
157
+ .setAutoSelectEnabled(autoSelectEnabled)
158
+ .setNonce(nonce)
159
+ .build()
160
+ }
161
+
162
+
163
+ suspend fun googleSignInRequest(googleIdOption: GetGoogleIdOption): GetCredentialResponse {
164
+ val request: GetCredentialRequest =
165
+ GetCredentialRequest
166
+ .Builder()
167
+ .addCredentialOption(googleIdOption)
168
+ .build()
169
+
170
+ val result =
171
+ credentialManager.getCredential(
172
+ request = request,
173
+ context = context,
174
+ )
175
+
176
+ return result
177
+ }
178
+ }
@@ -0,0 +1,56 @@
1
+ package com.credentialsmanager.handlers
2
+
3
+ import android.util.Log
4
+ import androidx.credentials.exceptions.CreateCredentialCancellationException
5
+ import androidx.credentials.exceptions.CreateCredentialCustomException
6
+ import androidx.credentials.exceptions.CreateCredentialException
7
+ import androidx.credentials.exceptions.CreateCredentialInterruptedException
8
+ import androidx.credentials.exceptions.CreateCredentialProviderConfigurationException
9
+ import androidx.credentials.exceptions.CreateCredentialUnknownException
10
+ import androidx.credentials.exceptions.GetCredentialCancellationException
11
+ import androidx.credentials.exceptions.GetCredentialException
12
+ import androidx.credentials.exceptions.GetCredentialInterruptedException
13
+ import androidx.credentials.exceptions.GetCredentialUnknownException
14
+ import androidx.credentials.exceptions.publickeycredential.CreatePublicKeyCredentialDomException
15
+
16
+ object ErrorHandler {
17
+ fun handleCredentialError(e: CreateCredentialException) {
18
+ when (e) {
19
+ is CreatePublicKeyCredentialDomException -> {
20
+ Log.d("CredentialManager", "passkey DOM errors")
21
+ }
22
+ is CreateCredentialCancellationException -> {
23
+ Log.d("CredentialManager", "User cancelled")
24
+ }
25
+ is CreateCredentialInterruptedException -> {
26
+ Log.d("CredentialManager", "Retry process")
27
+ }
28
+ is CreateCredentialProviderConfigurationException -> {
29
+ Log.d("CredentialManager", "Missing provider configuration")
30
+ }
31
+ is CreateCredentialUnknownException -> {
32
+ Log.d("CredentialManager", "Unknown error")
33
+ }
34
+ is CreateCredentialCustomException -> {
35
+ Log.d("CredentialManager", "Custom credential error")
36
+ }
37
+ else -> Log.w("CredentialManager", "Unexpected exception type ${e::class.java.name}")
38
+ }
39
+ }
40
+
41
+ fun handleGetCredentialError(e: GetCredentialException) {
42
+ when (e) {
43
+ is GetCredentialCancellationException -> {
44
+ Log.d("CredentialManager", "GetCredentialCancellationException")
45
+ }
46
+ is GetCredentialInterruptedException -> {
47
+ Log.d("CredentialManager", "User interputted")
48
+ }
49
+ is GetCredentialUnknownException -> {
50
+ Log.d("CredentialManager", "Unknown error")
51
+ }
52
+
53
+ else -> Log.w("CredentialManager", "Unexpected exception type ${e::class.java.name}")
54
+ }
55
+ }
56
+ }