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.
- package/README.md +21 -319
- package/android/generated/java/com/credentialsmanager/NativeCredentialsManagerSpec.java +3 -2
- package/android/generated/jni/RNCredentialsManagerSpec-generated.cpp +6 -6
- package/android/generated/jni/react/renderer/components/RNCredentialsManagerSpec/RNCredentialsManagerSpecJSI-generated.cpp +8 -7
- package/android/generated/jni/react/renderer/components/RNCredentialsManagerSpec/RNCredentialsManagerSpecJSI.h +65 -10
- package/android/src/main/java/com/credentialsmanager/handlers/CredentialHandler.kt +48 -5
- package/android/src/newarch/java/com/credentialsmanager/CredentialsManagerModule.kt +20 -15
- package/android/src/oldarch/java/com/credentialsmanager/CredentialsManagerModule.kt +29 -14
- package/ios/generated/RNCredentialsManagerSpec/RNCredentialsManagerSpec-generated.mm +17 -11
- package/ios/generated/RNCredentialsManagerSpec/RNCredentialsManagerSpec.h +38 -11
- package/ios/generated/RNCredentialsManagerSpecJSI-generated.cpp +8 -7
- package/ios/generated/RNCredentialsManagerSpecJSI.h +65 -10
- package/lib/commonjs/NativeCredentialsManager.js.map +1 -1
- package/lib/commonjs/index.js +13 -6
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/NativeCredentialsManager.js.map +1 -1
- package/lib/module/index.js +11 -4
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/commonjs/src/NativeCredentialsManager.d.ts +12 -7
- package/lib/typescript/commonjs/src/NativeCredentialsManager.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/index.d.ts +12 -7
- package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
- package/lib/typescript/module/src/NativeCredentialsManager.d.ts +12 -7
- package/lib/typescript/module/src/NativeCredentialsManager.d.ts.map +1 -1
- package/lib/typescript/module/src/index.d.ts +12 -7
- package/lib/typescript/module/src/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/NativeCredentialsManager.ts +20 -7
- package/src/index.tsx +29 -10
package/README.md
CHANGED
|
@@ -1,320 +1,22 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
<h1 align="center">
|
|
2
|
+
React Native Credentials Manager
|
|
3
|
+
</h1>
|
|
4
|
+
|
|
5
|
+

|
|
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
|
|
47
|
+
public abstract void signIn(ReadableArray options, ReadableMap params, Promise promise);
|
|
47
48
|
|
|
48
49
|
@ReactMethod
|
|
49
50
|
@DoNotStrip
|
|
50
|
-
public abstract void
|
|
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
|
|
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, "
|
|
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
|
|
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, "
|
|
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_["
|
|
45
|
-
methodMap_["
|
|
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
|
|
29
|
-
return static_cast<NativeCredentialsManagerCxxSpecJSI *>(&turboModule)->
|
|
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
|
|
35
|
-
return static_cast<NativeCredentialsManagerCxxSpecJSI *>(&turboModule)->
|
|
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_["
|
|
51
|
-
methodMap_["
|
|
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
|
|
173
|
-
virtual jsi::Value
|
|
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
|
|
276
|
+
jsi::Value signIn(jsi::Runtime &rt, jsi::Array options, jsi::Object params) override {
|
|
222
277
|
static_assert(
|
|
223
|
-
bridging::getParameterCount(&T::
|
|
224
|
-
"Expected
|
|
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::
|
|
282
|
+
rt, &T::signIn, jsInvoker_, instance_, std::move(options), std::move(params));
|
|
228
283
|
}
|
|
229
|
-
jsi::Value
|
|
284
|
+
jsi::Value signUpWithGoogle(jsi::Runtime &rt, jsi::Object params) override {
|
|
230
285
|
static_assert(
|
|
231
|
-
bridging::getParameterCount(&T::
|
|
232
|
-
"Expected
|
|
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::
|
|
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
|