react-native-credentials-manager 0.4.1 → 0.5.1

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 (29) hide show
  1. package/README.md +21 -319
  2. package/android/generated/java/com/credentialsmanager/NativeCredentialsManagerSpec.java +3 -2
  3. package/android/generated/jni/RNCredentialsManagerSpec-generated.cpp +6 -6
  4. package/android/generated/jni/react/renderer/components/RNCredentialsManagerSpec/RNCredentialsManagerSpecJSI-generated.cpp +8 -7
  5. package/android/generated/jni/react/renderer/components/RNCredentialsManagerSpec/RNCredentialsManagerSpecJSI.h +65 -10
  6. package/android/src/main/java/com/credentialsmanager/handlers/CredentialHandler.kt +48 -5
  7. package/android/src/newarch/java/com/credentialsmanager/CredentialsManagerModule.kt +20 -15
  8. package/android/src/oldarch/java/com/credentialsmanager/CredentialsManagerModule.kt +29 -14
  9. package/ios/generated/RNCredentialsManagerSpec/RNCredentialsManagerSpec-generated.mm +17 -11
  10. package/ios/generated/RNCredentialsManagerSpec/RNCredentialsManagerSpec.h +38 -11
  11. package/ios/generated/RNCredentialsManagerSpecJSI-generated.cpp +8 -7
  12. package/ios/generated/RNCredentialsManagerSpecJSI.h +65 -10
  13. package/lib/commonjs/NativeCredentialsManager.js.map +1 -1
  14. package/lib/commonjs/index.js +13 -6
  15. package/lib/commonjs/index.js.map +1 -1
  16. package/lib/module/NativeCredentialsManager.js.map +1 -1
  17. package/lib/module/index.js +11 -4
  18. package/lib/module/index.js.map +1 -1
  19. package/lib/typescript/commonjs/src/NativeCredentialsManager.d.ts +12 -7
  20. package/lib/typescript/commonjs/src/NativeCredentialsManager.d.ts.map +1 -1
  21. package/lib/typescript/commonjs/src/index.d.ts +12 -7
  22. package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
  23. package/lib/typescript/module/src/NativeCredentialsManager.d.ts +12 -7
  24. package/lib/typescript/module/src/NativeCredentialsManager.d.ts.map +1 -1
  25. package/lib/typescript/module/src/index.d.ts +12 -7
  26. package/lib/typescript/module/src/index.d.ts.map +1 -1
  27. package/package.json +1 -1
  28. package/src/NativeCredentialsManager.ts +20 -7
  29. package/src/index.tsx +29 -10
package/README.md CHANGED
@@ -1,320 +1,22 @@
1
- # react-native-credentials-manager
2
-
1
+ <h1 align="center">
2
+ React Native Credentials Manager
3
+ </h1>
4
+
5
+ ![App Screens](IMG/flow.png)
6
+
7
+ A React Native library that implements the [Credential Manager](https://developer.android.com/identity/sign-in/credential-manager) API for Android. This library allows you to manage passwords, passkeys and google signin in your React Native applications.
8
+
9
+ <p align="center">
10
+ <a href="https://www.npmjs.com/package/react-native-credentials-manager">
11
+ <img alt="npm version" src="https://badge.fury.io/js/react-native-credentials-manager.svg"/>
12
+ </a>
13
+ <a title='License' href="https://github.com/benjamineruvieru/react-native-credentials-manager/blob/master/LICENSE" height="18">
14
+ <img src='https://img.shields.io/badge/license-MIT-blue.svg' />
15
+ </a>
16
+ <a title='Tweet' href="https://twitter.com/intent/tweet?text=Check%20out%20this%20awesome%20React%20Native%20Credentials%20Manager%20Library&url=https://github.com/benjamineruvieru/react-native-credentials-manager&via=benjamin_eru&hashtags=react,reactnative,opensource,github,ux" height="18">
17
+ <img src='https://img.shields.io/twitter/url/http/shields.io.svg?style=social' />
18
+ </a>
19
+ </p>
20
+
21
+ > [!IMPORTANT]
3
22
  > 📚 **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
-
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.
6
-
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.
8
-
9
- ## Features
10
-
11
- - ✨ Passkey Authentication
12
- - 🔐 Password Credential Management
13
- - 📱 Google Signing
14
- - 🤖 [iOS Authentication Services](https://developer.apple.com/documentation/authenticationservices?language=objc) (coming soon)
15
-
16
- ## Installation
17
-
18
- ```bash
19
- npm install react-native-credentials-manager
20
-
21
- # or if you prefer yarn
22
-
23
- yarn add react-native-credentials-manager
24
- ```
25
-
26
- ## Requirements
27
-
28
- - React Native >= 0.71.0
29
- - New Architecture enabled
30
-
31
- ## Android Setup
32
-
33
- For complete setup instructions, see the [official Credential Manager documentation](https://developer.android.com/identity/sign-in/credential-manager#add-support-dal).
34
-
35
- 1. Add support for Digital Asset Links
36
-
37
- To enable passkey support, you need to associate your Android app with your website by creating and hosting a Digital Asset Links JSON file.
38
-
39
- Create a file named `assetlinks.json` with the following content:
40
-
41
- ```json
42
- [
43
- {
44
- "relation": [
45
- "delegate_permission/common.handle_all_urls",
46
- "delegate_permission/common.get_login_creds"
47
- ],
48
- "target": {
49
- "namespace": "android_app",
50
- "package_name": "your.package.name",
51
- "sha256_cert_fingerprints": [
52
- "YOUR_APP_SIGNING_CERTIFICATE_SHA256_FINGERPRINT"
53
- ]
54
- }
55
- }
56
- ]
57
- ```
58
-
59
- Host this file at:
60
-
61
- ```
62
- https://your-domain.com/.well-known/assetlinks.json
63
- ```
64
-
65
- Important requirements:
66
-
67
- - The MIME type must be `application/json`
68
- - If you have a `robots.txt`, ensure it allows access to `/.well-known/assetlinks.json`:
69
- ```
70
- User-agent: \*
71
- Allow: /.well-known/
72
- ```
73
- - The domain must be fully-qualified
74
- - Don't include trailing slashes or paths in the domain
75
- - Subdomains are not automatically included in the association
76
-
77
- ### ProGuard Rules
78
-
79
- If you're using ProGuard, add these rules to your `android/app/proguard-rules.pro`:
80
-
81
- ```pro
82
- -if class androidx.credentials.CredentialManager
83
- -keep class androidx.credentials.playservices.** {
84
- *;
85
- }
86
- ```
87
-
88
- ## Usage
89
-
90
- ### High-Level Authentication Flow
91
-
92
- The library provides three primary functions for managing user authentication:
93
-
94
- 1. **signUpWithPasskeys**: Registers a new user using passkeys.
95
- 2. **signUpWithPassword**: Registers a new user using a traditional username and password.
96
- 3. **signInWithSavedCredentials**: Authenticates a user using previously saved credentials.
97
-
98
- ### 1. Sign Up with Passkeys
99
-
100
- **Function**: `signUpWithPasskeys(requestJson)`
101
-
102
- **Description**: Registers a new user using passkeys, enhancing security and user experience.
103
-
104
- **Backend Requirements**:
105
-
106
- - **Challenge Generation**: Your backend must generate a unique, base64-encoded challenge to prevent replay attacks.
107
- - **User Information**: Provide user details such as a unique identifier, username, and display name.
108
-
109
- **When to Use**: Opt for passkey registration to offer users a passwordless and secure authentication method.
110
-
111
- **Example**:
112
-
113
- ```typescript
114
- import { signUpWithPasskeys } from 'react-native-credentials-manager';
115
-
116
- // From your backend
117
- const requestJson = {
118
- challenge: 'base64EncodedChallengeFromBackend',
119
- rp: {
120
- name: 'Your App Name',
121
- id: 'your-domain.com',
122
- },
123
- user: {
124
- id: 'base64EncodedUserIdFromBackend',
125
- name: 'username',
126
- displayName: 'User Display Name',
127
- },
128
- pubKeyCredParams: [
129
- {
130
- type: 'public-key',
131
- alg: -7, // ES256
132
- },
133
- ],
134
- authenticatorSelection: {
135
- authenticatorAttachment: 'platform',
136
- requireResidentKey: true,
137
- residentKey: 'required',
138
- userVerification: 'required',
139
- },
140
- };
141
-
142
- try {
143
- const response = await signUpWithPasskeys(requestJson);
144
- console.log('Passkey registration successful:', response);
145
- } catch (error) {
146
- console.error('Passkey registration failed:', error);
147
- }
148
- ```
149
-
150
- **Parameters**:
151
-
152
- | Parameter | Type | Description |
153
- | ------------------------------------------------ | --------- | ---------------------------------------------------------------------------------------------- |
154
- | `challenge` | `string` | A base64-encoded challenge provided by your server to prevent replay attacks. |
155
- | `rp` | `object` | Information about your app (Relying Party). |
156
- | `rp.name` | `string` | The name of your app. |
157
- | `rp.id` | `string` | The domain of your app. |
158
- | `user` | `object` | Information about the user registering. |
159
- | `user.id` | `string` | A base64-encoded unique identifier for the user. |
160
- | `user.name` | `string` | The username of the user. |
161
- | `user.displayName` | `string` | The display name of the user. |
162
- | `pubKeyCredParams` | `array` | An array of objects indicating acceptable public key algorithms. |
163
- | `authenticatorSelection` | `object` | Criteria for selecting the appropriate authenticator. |
164
- | `authenticatorSelection.authenticatorAttachment` | `string` | Indicates the desired authenticator attachment modality (`"platform"` or `"cross-platform"`). |
165
- | `authenticatorSelection.requireResidentKey` | `boolean` | Indicates whether resident keys are required. |
166
- | `authenticatorSelection.residentKey` | `string` | Specifies the resident key requirement (`"required"`, `"preferred"`, or `"discouraged"`). |
167
- | `authenticatorSelection.userVerification` | `string` | Specifies the user verification requirement (`"required"`, `"preferred"`, or `"discouraged"`). |
168
-
169
- **Note**: Parameters such as `challenge`, `user.id`, and other user-specific information should be securely generated and provided by your backend server.
170
-
171
- ### 2. Sign Up with Password
172
-
173
- **Function**: `signUpWithPassword(credentials)`
174
-
175
- **Description**: Registers a new user using a traditional username and password combination.
176
-
177
- **Backend Requirements**:
178
-
179
- - **User Registration**: Your backend should handle the storage and management of user credentials securely.
180
-
181
- **When to Use**: Use this method when you want to support traditional password-based authentication.
182
-
183
- **Example**:
184
-
185
- ```typescript
186
- import { signUpWithPassword } from 'react-native-credentials-manager';
187
-
188
- const credentials = {
189
- username: 'user@example.com',
190
- password: 'securePassword123!',
191
- };
192
-
193
- try {
194
- await signUpWithPassword(credentials);
195
- console.log('User registered successfully with password.');
196
- } catch (error) {
197
- console.error('Password registration failed:', error);
198
- }
199
- ```
200
-
201
- ### Sign In with Saved Credentials
202
-
203
- ```typescript
204
- import { signInWithSavedCredentials } from 'react-native-credentials-manager';
205
-
206
- // From your backend
207
- const signinRequestJson = {
208
- challenge: 'base64EncodedChallenge',
209
- timeout: 1800000,
210
- userVerification: 'required',
211
- rpId: 'your-domain.com',
212
- };
213
-
214
- try {
215
- const credential = await signInWithSavedCredentials(signinRequestJson);
216
-
217
- if (credential.type === 'passkey') {
218
- console.log('Passkey:', credential.authenticationResponseJson);
219
- } else if (credential.type === 'password') {
220
- console.log('Password credentials:', {
221
- username: credential.username,
222
- password: credential.password,
223
- });
224
- }
225
- } catch (error) {
226
- console.error('Sign in failed:', error);
227
- }
228
- ```
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
-
290
- ## Documentation
291
-
292
- For more detailed information about the underlying APIs, refer to:
293
-
294
- - [Android Credential Manager Overview](https://developer.android.com/identity/sign-in/credential-manager)
295
- - [Android Credential Manager API Reference](https://developer.android.com/reference/androidx/credentials/package-summary)
296
- - [WebAuthn Developer Guide](https://webauthn.guide)
297
- - [Passkeys Overview](https://developers.google.com/identity/passkeys)
298
-
299
- ## Roadmap
300
-
301
- - ~~Old Architecture Support~~ ✅
302
- - iOS Support using [Authentication Services](https://developer.apple.com/documentation/authenticationservices?language=objc)
303
- - Additional Authentication Methods
304
- - Comprehensive Documentation
305
-
306
- ## Contributing
307
-
308
- See the [contributing guide](CONTRIBUTING.md) to learn how to contribute to the repository and the development workflow.
309
-
310
- ## License
311
-
312
- MIT
313
-
314
- ---
315
-
316
- Made with [create-react-native-library](https://github.com/callstack/react-native-builder-bob)
317
-
318
- ```
319
-
320
- ```
@@ -17,6 +17,7 @@ import com.facebook.react.bridge.Promise;
17
17
  import com.facebook.react.bridge.ReactApplicationContext;
18
18
  import com.facebook.react.bridge.ReactContextBaseJavaModule;
19
19
  import com.facebook.react.bridge.ReactMethod;
20
+ import com.facebook.react.bridge.ReadableArray;
20
21
  import com.facebook.react.bridge.ReadableMap;
21
22
  import com.facebook.react.turbomodule.core.interfaces.TurboModule;
22
23
  import javax.annotation.Nonnull;
@@ -43,11 +44,11 @@ public abstract class NativeCredentialsManagerSpec extends ReactContextBaseJavaM
43
44
 
44
45
  @ReactMethod
45
46
  @DoNotStrip
46
- public abstract void signInWithSavedCredentials(ReadableMap requestJson, Promise promise);
47
+ public abstract void signIn(ReadableArray options, ReadableMap params, Promise promise);
47
48
 
48
49
  @ReactMethod
49
50
  @DoNotStrip
50
- public abstract void signInWithGoogle(ReadableMap params, Promise promise);
51
+ public abstract void signUpWithGoogle(ReadableMap params, Promise promise);
51
52
 
52
53
  @ReactMethod
53
54
  @DoNotStrip
@@ -22,14 +22,14 @@ static facebook::jsi::Value __hostFunction_NativeCredentialsManagerSpecJSI_signU
22
22
  return static_cast<JavaTurboModule &>(turboModule).invokeJavaMethod(rt, VoidKind, "signUpWithPassword", "(Lcom/facebook/react/bridge/ReadableMap;)V", args, count, cachedMethodId);
23
23
  }
24
24
 
25
- static facebook::jsi::Value __hostFunction_NativeCredentialsManagerSpecJSI_signInWithSavedCredentials(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
25
+ static facebook::jsi::Value __hostFunction_NativeCredentialsManagerSpecJSI_signIn(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
26
26
  static jmethodID cachedMethodId = nullptr;
27
- return static_cast<JavaTurboModule &>(turboModule).invokeJavaMethod(rt, PromiseKind, "signInWithSavedCredentials", "(Lcom/facebook/react/bridge/ReadableMap;Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId);
27
+ return static_cast<JavaTurboModule &>(turboModule).invokeJavaMethod(rt, PromiseKind, "signIn", "(Lcom/facebook/react/bridge/ReadableArray;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) {
30
+ static facebook::jsi::Value __hostFunction_NativeCredentialsManagerSpecJSI_signUpWithGoogle(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
31
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);
32
+ return static_cast<JavaTurboModule &>(turboModule).invokeJavaMethod(rt, PromiseKind, "signUpWithGoogle", "(Lcom/facebook/react/bridge/ReadableMap;Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId);
33
33
  }
34
34
 
35
35
  static facebook::jsi::Value __hostFunction_NativeCredentialsManagerSpecJSI_signOut(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
@@ -41,8 +41,8 @@ NativeCredentialsManagerSpecJSI::NativeCredentialsManagerSpecJSI(const JavaTurbo
41
41
  : JavaTurboModule(params) {
42
42
  methodMap_["signUpWithPasskeys"] = MethodMetadata {2, __hostFunction_NativeCredentialsManagerSpecJSI_signUpWithPasskeys};
43
43
  methodMap_["signUpWithPassword"] = MethodMetadata {1, __hostFunction_NativeCredentialsManagerSpecJSI_signUpWithPassword};
44
- methodMap_["signInWithSavedCredentials"] = MethodMetadata {1, __hostFunction_NativeCredentialsManagerSpecJSI_signInWithSavedCredentials};
45
- methodMap_["signInWithGoogle"] = MethodMetadata {1, __hostFunction_NativeCredentialsManagerSpecJSI_signInWithGoogle};
44
+ methodMap_["signIn"] = MethodMetadata {2, __hostFunction_NativeCredentialsManagerSpecJSI_signIn};
45
+ methodMap_["signUpWithGoogle"] = MethodMetadata {1, __hostFunction_NativeCredentialsManagerSpecJSI_signUpWithGoogle};
46
46
  methodMap_["signOut"] = MethodMetadata {0, __hostFunction_NativeCredentialsManagerSpecJSI_signOut};
47
47
  }
48
48
 
@@ -25,14 +25,15 @@ static jsi::Value __hostFunction_NativeCredentialsManagerCxxSpecJSI_signUpWithPa
25
25
  );
26
26
  return jsi::Value::undefined();
27
27
  }
28
- static jsi::Value __hostFunction_NativeCredentialsManagerCxxSpecJSI_signInWithSavedCredentials(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
29
- return static_cast<NativeCredentialsManagerCxxSpecJSI *>(&turboModule)->signInWithSavedCredentials(
28
+ static jsi::Value __hostFunction_NativeCredentialsManagerCxxSpecJSI_signIn(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
29
+ return static_cast<NativeCredentialsManagerCxxSpecJSI *>(&turboModule)->signIn(
30
30
  rt,
31
- count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asObject(rt)
31
+ count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asObject(rt).asArray(rt),
32
+ count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asObject(rt)
32
33
  );
33
34
  }
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(
35
+ static jsi::Value __hostFunction_NativeCredentialsManagerCxxSpecJSI_signUpWithGoogle(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
36
+ return static_cast<NativeCredentialsManagerCxxSpecJSI *>(&turboModule)->signUpWithGoogle(
36
37
  rt,
37
38
  count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asObject(rt)
38
39
  );
@@ -47,8 +48,8 @@ NativeCredentialsManagerCxxSpecJSI::NativeCredentialsManagerCxxSpecJSI(std::shar
47
48
  : TurboModule("CredentialsManager", jsInvoker) {
48
49
  methodMap_["signUpWithPasskeys"] = MethodMetadata {2, __hostFunction_NativeCredentialsManagerCxxSpecJSI_signUpWithPasskeys};
49
50
  methodMap_["signUpWithPassword"] = MethodMetadata {1, __hostFunction_NativeCredentialsManagerCxxSpecJSI_signUpWithPassword};
50
- methodMap_["signInWithSavedCredentials"] = MethodMetadata {1, __hostFunction_NativeCredentialsManagerCxxSpecJSI_signInWithSavedCredentials};
51
- methodMap_["signInWithGoogle"] = MethodMetadata {1, __hostFunction_NativeCredentialsManagerCxxSpecJSI_signInWithGoogle};
51
+ methodMap_["signIn"] = MethodMetadata {2, __hostFunction_NativeCredentialsManagerCxxSpecJSI_signIn};
52
+ methodMap_["signUpWithGoogle"] = MethodMetadata {1, __hostFunction_NativeCredentialsManagerCxxSpecJSI_signUpWithGoogle};
52
53
  methodMap_["signOut"] = MethodMetadata {0, __hostFunction_NativeCredentialsManagerCxxSpecJSI_signOut};
53
54
  }
54
55
 
@@ -162,6 +162,61 @@ struct NativeCredentialsManagerGoogleCredentialBridging {
162
162
  }
163
163
  };
164
164
 
165
+
166
+
167
+ #pragma mark - NativeCredentialsManagerGoogleSignInParams
168
+
169
+ template <typename P0, typename P1, typename P2>
170
+ struct NativeCredentialsManagerGoogleSignInParams {
171
+ P0 nonce;
172
+ P1 serverClientId;
173
+ P2 autoSelectEnabled;
174
+ bool operator==(const NativeCredentialsManagerGoogleSignInParams &other) const {
175
+ return nonce == other.nonce && serverClientId == other.serverClientId && autoSelectEnabled == other.autoSelectEnabled;
176
+ }
177
+ };
178
+
179
+ template <typename T>
180
+ struct NativeCredentialsManagerGoogleSignInParamsBridging {
181
+ static T types;
182
+
183
+ static T fromJs(
184
+ jsi::Runtime &rt,
185
+ const jsi::Object &value,
186
+ const std::shared_ptr<CallInvoker> &jsInvoker) {
187
+ T result{
188
+ bridging::fromJs<decltype(types.nonce)>(rt, value.getProperty(rt, "nonce"), jsInvoker),
189
+ bridging::fromJs<decltype(types.serverClientId)>(rt, value.getProperty(rt, "serverClientId"), jsInvoker),
190
+ bridging::fromJs<decltype(types.autoSelectEnabled)>(rt, value.getProperty(rt, "autoSelectEnabled"), jsInvoker)};
191
+ return result;
192
+ }
193
+
194
+ #ifdef DEBUG
195
+ static jsi::String nonceToJs(jsi::Runtime &rt, decltype(types.nonce) value) {
196
+ return bridging::toJs(rt, value);
197
+ }
198
+
199
+ static jsi::String serverClientIdToJs(jsi::Runtime &rt, decltype(types.serverClientId) value) {
200
+ return bridging::toJs(rt, value);
201
+ }
202
+
203
+ static bool autoSelectEnabledToJs(jsi::Runtime &rt, decltype(types.autoSelectEnabled) value) {
204
+ return bridging::toJs(rt, value);
205
+ }
206
+ #endif
207
+
208
+ static jsi::Object toJs(
209
+ jsi::Runtime &rt,
210
+ const T &value,
211
+ const std::shared_ptr<CallInvoker> &jsInvoker) {
212
+ auto result = facebook::jsi::Object(rt);
213
+ result.setProperty(rt, "nonce", bridging::toJs(rt, value.nonce, jsInvoker));
214
+ result.setProperty(rt, "serverClientId", bridging::toJs(rt, value.serverClientId, jsInvoker));
215
+ result.setProperty(rt, "autoSelectEnabled", bridging::toJs(rt, value.autoSelectEnabled, jsInvoker));
216
+ return result;
217
+ }
218
+ };
219
+
165
220
  class JSI_EXPORT NativeCredentialsManagerCxxSpecJSI : public TurboModule {
166
221
  protected:
167
222
  NativeCredentialsManagerCxxSpecJSI(std::shared_ptr<CallInvoker> jsInvoker);
@@ -169,8 +224,8 @@ protected:
169
224
  public:
170
225
  virtual jsi::Value signUpWithPasskeys(jsi::Runtime &rt, jsi::Object requestJson, bool preferImmediatelyAvailableCredentials) = 0;
171
226
  virtual void signUpWithPassword(jsi::Runtime &rt, jsi::Object credObject) = 0;
172
- virtual jsi::Value signInWithSavedCredentials(jsi::Runtime &rt, jsi::Object requestJson) = 0;
173
- virtual jsi::Value signInWithGoogle(jsi::Runtime &rt, jsi::Object params) = 0;
227
+ virtual jsi::Value signIn(jsi::Runtime &rt, jsi::Array options, jsi::Object params) = 0;
228
+ virtual jsi::Value signUpWithGoogle(jsi::Runtime &rt, jsi::Object params) = 0;
174
229
  virtual jsi::Value signOut(jsi::Runtime &rt) = 0;
175
230
 
176
231
  };
@@ -218,21 +273,21 @@ private:
218
273
  return bridging::callFromJs<void>(
219
274
  rt, &T::signUpWithPassword, jsInvoker_, instance_, std::move(credObject));
220
275
  }
221
- jsi::Value signInWithSavedCredentials(jsi::Runtime &rt, jsi::Object requestJson) override {
276
+ jsi::Value signIn(jsi::Runtime &rt, jsi::Array options, jsi::Object params) override {
222
277
  static_assert(
223
- bridging::getParameterCount(&T::signInWithSavedCredentials) == 2,
224
- "Expected signInWithSavedCredentials(...) to have 2 parameters");
278
+ bridging::getParameterCount(&T::signIn) == 3,
279
+ "Expected signIn(...) to have 3 parameters");
225
280
 
226
281
  return bridging::callFromJs<jsi::Value>(
227
- rt, &T::signInWithSavedCredentials, jsInvoker_, instance_, std::move(requestJson));
282
+ rt, &T::signIn, jsInvoker_, instance_, std::move(options), std::move(params));
228
283
  }
229
- jsi::Value signInWithGoogle(jsi::Runtime &rt, jsi::Object params) override {
284
+ jsi::Value signUpWithGoogle(jsi::Runtime &rt, jsi::Object params) override {
230
285
  static_assert(
231
- bridging::getParameterCount(&T::signInWithGoogle) == 2,
232
- "Expected signInWithGoogle(...) to have 2 parameters");
286
+ bridging::getParameterCount(&T::signUpWithGoogle) == 2,
287
+ "Expected signUpWithGoogle(...) to have 2 parameters");
233
288
 
234
289
  return bridging::callFromJs<jsi::Value>(
235
- rt, &T::signInWithGoogle, jsInvoker_, instance_, std::move(params));
290
+ rt, &T::signUpWithGoogle, jsInvoker_, instance_, std::move(params));
236
291
  }
237
292
  jsi::Value signOut(jsi::Runtime &rt) override {
238
293
  static_assert(
@@ -2,10 +2,12 @@ package com.credentialsmanager.handlers
2
2
 
3
3
  import android.content.Context
4
4
  import android.util.Log
5
+ import androidx.credentials.ClearCredentialStateRequest
5
6
  import androidx.credentials.CreatePasswordRequest
6
7
  import androidx.credentials.CreatePublicKeyCredentialRequest
7
8
  import androidx.credentials.CreatePublicKeyCredentialResponse
8
9
  import androidx.credentials.CredentialManager
10
+ import androidx.credentials.CredentialOption
9
11
  import androidx.credentials.CustomCredential
10
12
  import androidx.credentials.GetCredentialRequest
11
13
  import androidx.credentials.GetCredentialResponse
@@ -14,23 +16,22 @@ import androidx.credentials.GetPublicKeyCredentialOption
14
16
  import androidx.credentials.PasswordCredential
15
17
  import androidx.credentials.PublicKeyCredential
16
18
  import com.facebook.react.bridge.Arguments
19
+ import com.facebook.react.bridge.ReadableArray
17
20
  import com.facebook.react.bridge.ReadableMap
18
21
  import com.google.android.libraries.identity.googleid.GetGoogleIdOption
19
22
  import com.google.android.libraries.identity.googleid.GoogleIdTokenCredential
20
23
  import com.google.android.libraries.identity.googleid.GoogleIdTokenParsingException
21
24
  import org.json.JSONObject
22
- import androidx.credentials.ClearCredentialStateRequest
23
25
 
24
26
  class CredentialHandler(
25
27
  private val context: Context,
26
28
  ) {
27
29
  private val credentialManager = CredentialManager.create(context)
28
30
 
29
- suspend fun signOut(){
30
-
31
+ suspend fun signOut() {
31
32
  credentialManager.clearCredentialState(ClearCredentialStateRequest())
32
-
33
33
  }
34
+
34
35
  suspend fun createPasskey(
35
36
  jsonString: String,
36
37
  preferImmediatelyAvailableCredentials: Boolean,
@@ -66,6 +67,49 @@ class CredentialHandler(
66
67
  credentialManager.createCredential(context, createPasswordRequest)
67
68
  }
68
69
 
70
+ suspend fun signIn(
71
+ options: ReadableArray,
72
+ params: ReadableMap,
73
+ ): ReadableMap? {
74
+ val credentialOptions = mutableListOf<CredentialOption>()
75
+ for (i in 0 until options.size()) {
76
+ when (options.getString(i)) {
77
+ "passkeys" -> {
78
+ if (params.hasKey("passkeys")) {
79
+ val jsonString = params.getMap("passkeys")?.toString()
80
+ jsonString?.let {
81
+ credentialOptions.add(GetPublicKeyCredentialOption(it, null))
82
+ }
83
+ }
84
+ }
85
+ "password" -> {
86
+ credentialOptions.add(GetPasswordOption())
87
+ }
88
+ "google-signin" -> {
89
+ if (params.hasKey("googleSignIn")) {
90
+ val googleParams = params.getMap("googleSignIn")
91
+ val nonce = googleParams?.getString("nonce") ?: ""
92
+ val serverClientId = googleParams?.getString("serverClientId") ?: ""
93
+ val autoSelectEnabled = googleParams?.getBoolean("autoSelectEnabled") ?: false
94
+
95
+ credentialOptions.add(
96
+ getGoogleId(
97
+ true,
98
+ nonce,
99
+ serverClientId,
100
+ autoSelectEnabled,
101
+ ),
102
+ )
103
+ }
104
+ }
105
+ }
106
+ }
107
+
108
+ val request = GetCredentialRequest(credentialOptions)
109
+ val result = credentialManager.getCredential(context, request)
110
+ return handleSignInResult(result)
111
+ }
112
+
69
113
  suspend fun getSavedCredentials(jsonString: String): ReadableMap? {
70
114
  val getPublicKeyCredentialOption = GetPublicKeyCredentialOption(jsonString, null)
71
115
  val getPasswordOption = GetPasswordOption()
@@ -159,7 +203,6 @@ class CredentialHandler(
159
203
  .build()
160
204
  }
161
205
 
162
-
163
206
  suspend fun googleSignInRequest(googleIdOption: GetGoogleIdOption): GetCredentialResponse {
164
207
  val request: GetCredentialRequest =
165
208
  GetCredentialRequest