Skip to content

Commit b9871f8

Browse files
refactor: remove passkey registration and assertion methods from native and web platforms
1 parent cf94555 commit b9871f8

18 files changed

Lines changed: 77 additions & 1055 deletions

File tree

EXAMPLES.md

Lines changed: 36 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1026,12 +1026,12 @@ For detailed examples of validating different token types in Actions, see:
10261026

10271027
### Overview
10281028

1029-
Passkeys provide a passwordless authentication experience using platform biometrics (Face ID, Touch ID, fingerprint) backed by public-key cryptography. The SDK handles the full passkey flow — challenge, platform credential manager interaction, and token exchange — so you can implement passkeys without writing any custom native code.
1029+
Passkeys provide a passwordless authentication experience using platform biometrics (Face ID, Touch ID, fingerprint) backed by public-key cryptography. The SDK provides the Auth0 challenge and token exchange steps, while you handle the platform credential manager interaction using native modules or libraries like `react-native-passkey`.
10301030

10311031
The passkey flow has three steps:
10321032

10331033
1. **Challenge** — Request a WebAuthn challenge from Auth0 (`passkeySignupChallenge` or `passkeyLoginChallenge`)
1034-
2. **Credential Manager** — Present the OS credential manager UI to create or assert a passkey (`passkeyRegistration` or `passkeyAssertion`)
1034+
2. **Credential Manager** — Present the OS credential manager UI to create or assert a passkey (using your own native module or a library)
10351035
3. **Exchange** — Send the credential response back to Auth0 to get tokens (`passkeyExchange`)
10361036

10371037
> **Platform Support:** Native only (iOS 16.6+ / Android). Not supported on Web.
@@ -1051,14 +1051,13 @@ Before using passkeys:
10511051
10521052
### Signup with Passkey
10531053
1054-
The signup flow requests a registration challenge, presents the OS credential manager UI to create a new passkey, then exchanges the result for Auth0 tokens. The SDK handles the platform credential manager interaction for you.
1054+
The signup flow requests a registration challenge from Auth0, then you use the platform credential manager (via a native module or library like `react-native-passkey`) to create a new passkey, and finally exchange the credential for Auth0 tokens.
10551055
10561056
```tsx
10571057
import { useAuth0, PasskeyError } from 'react-native-auth0';
10581058
10591059
function PasskeySignupScreen() {
1060-
const { passkeySignupChallenge, passkeyRegistration, passkeyExchange } =
1061-
useAuth0();
1060+
const { passkeySignupChallenge, passkeyExchange } = useAuth0();
10621061
10631062
const handleSignup = async () => {
10641063
try {
@@ -1069,11 +1068,12 @@ function PasskeySignupScreen() {
10691068
realm: 'Username-Password-Authentication',
10701069
});
10711070
1072-
// Step 2: Present the OS credential manager UI to create a passkey
1073-
// This invokes CredentialManager on Android / ASAuthorizationController on iOS
1074-
const credentialJson = await passkeyRegistration({
1075-
challengeJson: JSON.stringify(challenge.authParamsPublicKey),
1076-
});
1071+
// Step 2: Use the platform credential manager to create a passkey
1072+
// challenge.authParamsPublicKey contains the WebAuthn PublicKeyCredentialCreationOptions
1073+
// Use your preferred library (e.g., react-native-passkey) or native module
1074+
const credentialJson = await yourCredentialManagerCreate(
1075+
challenge.authParamsPublicKey
1076+
);
10771077
10781078
// Step 3: Exchange the credential response for Auth0 tokens
10791079
const credentials = await passkeyExchange({
@@ -1098,14 +1098,13 @@ function PasskeySignupScreen() {
10981098
10991099
### Signin with Passkey
11001100
1101-
The login flow requests an assertion challenge, presents the OS credential manager UI to assert an existing passkey, then exchanges the result for Auth0 tokens.
1101+
The login flow requests an assertion challenge from Auth0, then you use the platform credential manager to assert an existing passkey, and finally exchange the credential for Auth0 tokens.
11021102
11031103
```tsx
11041104
import { useAuth0, PasskeyError } from 'react-native-auth0';
11051105

11061106
function PasskeySigninScreen() {
1107-
const { passkeyLoginChallenge, passkeyAssertion, passkeyExchange } =
1108-
useAuth0();
1107+
const { passkeyLoginChallenge, passkeyExchange } = useAuth0();
11091108

11101109
const handleSignin = async () => {
11111110
try {
@@ -1114,11 +1113,12 @@ function PasskeySigninScreen() {
11141113
realm: 'Username-Password-Authentication',
11151114
});
11161115

1117-
// Step 2: Present the OS credential manager UI to assert an existing passkey
1118-
// This invokes CredentialManager on Android / ASAuthorizationController on iOS
1119-
const credentialJson = await passkeyAssertion({
1120-
challengeJson: JSON.stringify(challenge.authParamsPublicKey),
1121-
});
1116+
// Step 2: Use the platform credential manager to assert an existing passkey
1117+
// challenge.authParamsPublicKey contains the WebAuthn PublicKeyCredentialRequestOptions
1118+
// Use your preferred library (e.g., react-native-passkey) or native module
1119+
const credentialJson = await yourCredentialManagerGet(
1120+
challenge.authParamsPublicKey
1121+
);
11221122

11231123
// Step 3: Exchange the credential response for Auth0 tokens
11241124
const credentials = await passkeyExchange({
@@ -1141,33 +1141,6 @@ function PasskeySigninScreen() {
11411141
}
11421142
```
11431143
1144-
### Advanced: Manual Credential Manager Handling
1145-
1146-
If you need full control over the platform credential manager interaction (e.g., custom UI, conditional mediation, or hybrid security key support), you can skip `passkeyRegistration`/`passkeyAssertion` and handle it yourself. The challenge and exchange methods give you the raw WebAuthn data:
1147-
1148-
```tsx
1149-
// Step 1: Get challenge (same as above)
1150-
const challenge = await passkeySignupChallenge({
1151-
email: 'user@example.com',
1152-
realm: '...',
1153-
});
1154-
1155-
// Step 2: Use your own native module or library to interact with the credential manager
1156-
// challenge.authParamsPublicKey contains the raw WebAuthn PublicKeyCredentialCreationOptions
1157-
// You must serialize the resulting PublicKeyCredential as JSON
1158-
1159-
const authResponse = await yourCustomCredentialManagerCall(
1160-
challenge.authParamsPublicKey
1161-
);
1162-
1163-
// Step 3: Exchange (same as above)
1164-
const credentials = await passkeyExchange({
1165-
authSession: challenge.authSession,
1166-
authResponse: JSON.stringify(authResponse),
1167-
realm: '...',
1168-
});
1169-
```
1170-
11711144
### Auth Response Format
11721145
11731146
The `authResponse` parameter passed to `passkeyExchange` must be a JSON string representing the [PublicKeyCredential](https://www.w3.org/TR/webauthn-2/#publickeycredential) response from the platform credential manager.
@@ -1221,9 +1194,11 @@ const signupChallenge = await auth0.passkeySignupChallenge({
12211194
realm: 'Username-Password-Authentication',
12221195
});
12231196

1224-
const registrationJson = await auth0.passkeyRegistration({
1225-
challengeJson: JSON.stringify(signupChallenge.authParamsPublicKey),
1226-
});
1197+
// Use your credential manager library to create the passkey
1198+
// signupChallenge.authParamsPublicKey has the WebAuthn creation options
1199+
const registrationJson = await yourCredentialManagerCreate(
1200+
signupChallenge.authParamsPublicKey
1201+
);
12271202

12281203
const signupCredentials = await auth0.passkeyExchange({
12291204
authSession: signupChallenge.authSession,
@@ -1236,9 +1211,11 @@ const loginChallenge = await auth0.passkeyLoginChallenge({
12361211
realm: 'Username-Password-Authentication',
12371212
});
12381213

1239-
const assertionJson = await auth0.passkeyAssertion({
1240-
challengeJson: JSON.stringify(loginChallenge.authParamsPublicKey),
1241-
});
1214+
// Use your credential manager library to assert the passkey
1215+
// loginChallenge.authParamsPublicKey has the WebAuthn request options
1216+
const assertionJson = await yourCredentialManagerGet(
1217+
loginChallenge.authParamsPublicKey
1218+
);
12421219

12431220
const loginCredentials = await auth0.passkeyExchange({
12441221
authSession: loginChallenge.authSession,
@@ -1271,16 +1248,14 @@ The `passkeySignupChallenge` method accepts the following parameters to create a
12711248
12721249
Passkey operations throw `PasskeyError` (extends `AuthError`) with a normalized `type` property. Use `PasskeyErrorCodes` for type-safe error handling:
12731250
1274-
| Error Code | Description |
1275-
| ------------------------------ | ---------------------------------------------------------------- |
1276-
| `PASSKEY_CHALLENGE_FAILED` | Auth0 challenge request failed |
1277-
| `PASSKEY_EXCHANGE_FAILED` | Token exchange with credential response failed |
1278-
| `PASSKEY_REGISTRATION_FAILED` | Platform credential manager failed to create a new passkey |
1279-
| `PASSKEY_ASSERTION_FAILED` | Platform credential manager failed to assert an existing passkey |
1280-
| `PASSKEY_USER_CANCELLED` | User cancelled the passkey OS prompt |
1281-
| `PASSKEY_NOT_AVAILABLE` | Passkeys not available on this device or OS version |
1282-
| `PASSKEY_UNSUPPORTED_PLATFORM` | Passkeys not supported on this platform (Web) |
1283-
| `PASSKEY_UNKNOWN_ERROR` | Unknown or uncategorized passkey error |
1251+
| Error Code | Description |
1252+
| ------------------------------ | --------------------------------------------------- |
1253+
| `PASSKEY_CHALLENGE_FAILED` | Auth0 challenge request failed |
1254+
| `PASSKEY_EXCHANGE_FAILED` | Token exchange with credential response failed |
1255+
| `PASSKEY_USER_CANCELLED` | User cancelled the passkey OS prompt |
1256+
| `PASSKEY_NOT_AVAILABLE` | Passkeys not available on this device or OS version |
1257+
| `PASSKEY_UNSUPPORTED_PLATFORM` | Passkeys not supported on this platform (Web) |
1258+
| `PASSKEY_UNKNOWN_ERROR` | Unknown or uncategorized passkey error |
12841259
12851260
```typescript
12861261
import { PasskeyError, PasskeyErrorCodes } from 'react-native-auth0';

android/src/main/java/com/auth0/react/A0Auth0Module.kt

Lines changed: 0 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,6 @@ import com.auth0.android.result.APICredentials
2121
import com.auth0.android.result.Credentials
2222
import com.auth0.android.result.PasskeyChallenge
2323
import com.auth0.android.result.PasskeyRegistrationChallenge
24-
import androidx.credentials.CreatePublicKeyCredentialRequest
25-
import androidx.credentials.CreatePublicKeyCredentialResponse
26-
import androidx.credentials.CredentialManager
27-
import androidx.credentials.GetCredentialRequest
28-
import androidx.credentials.GetPublicKeyCredentialOption
29-
import androidx.credentials.PublicKeyCredential
30-
import androidx.credentials.exceptions.CreateCredentialCancellationException
31-
import androidx.credentials.exceptions.CreateCredentialException
32-
import androidx.credentials.exceptions.GetCredentialCancellationException
33-
import androidx.credentials.exceptions.GetCredentialException
34-
import androidx.credentials.exceptions.NoCredentialException
3524
import com.facebook.react.bridge.ActivityEventListener
3625
import com.facebook.react.bridge.Promise
3726
import com.facebook.react.bridge.ReactApplicationContext
@@ -41,9 +30,6 @@ import com.facebook.react.bridge.ReadableMap
4130
import com.facebook.react.bridge.UiThreadUtil
4231
import com.facebook.react.bridge.WritableNativeMap
4332
import com.google.gson.Gson
44-
import kotlinx.coroutines.CoroutineScope
45-
import kotlinx.coroutines.Dispatchers
46-
import kotlinx.coroutines.launch
4733
import java.net.MalformedURLException
4834
import java.net.URL
4935

@@ -690,64 +676,6 @@ class A0Auth0Module(private val reactContext: ReactApplicationContext) : A0Auth0
690676
})
691677
}
692678

693-
@ReactMethod
694-
override fun passkeyRegistration(challengeJson: String, promise: Promise) {
695-
val activity = reactContext.currentActivity
696-
if (activity == null) {
697-
promise.reject("PASSKEY_REGISTRATION_FAILED", "No current activity available")
698-
return
699-
}
700-
701-
val credentialManager = CredentialManager.create(activity)
702-
val request = CreatePublicKeyCredentialRequest(challengeJson)
703-
704-
CoroutineScope(Dispatchers.Main).launch {
705-
try {
706-
val result = credentialManager.createCredential(activity, request)
707-
val response = result as CreatePublicKeyCredentialResponse
708-
promise.resolve(response.registrationResponseJson)
709-
} catch (e: CreateCredentialCancellationException) {
710-
promise.reject("PASSKEY_USER_CANCELLED", "User cancelled passkey registration", e)
711-
} catch (e: CreateCredentialException) {
712-
promise.reject("PASSKEY_REGISTRATION_FAILED", e.message ?: "Passkey registration failed", e)
713-
} catch (e: Exception) {
714-
promise.reject("PASSKEY_REGISTRATION_FAILED", e.message ?: "Unexpected error during passkey registration", e)
715-
}
716-
}
717-
}
718-
719-
@ReactMethod
720-
override fun passkeyAssertion(challengeJson: String, promise: Promise) {
721-
val activity = reactContext.currentActivity
722-
if (activity == null) {
723-
promise.reject("PASSKEY_ASSERTION_FAILED", "No current activity available")
724-
return
725-
}
726-
727-
val credentialManager = CredentialManager.create(activity)
728-
val option = GetPublicKeyCredentialOption(challengeJson)
729-
val request = GetCredentialRequest(listOf(option))
730-
731-
CoroutineScope(Dispatchers.Main).launch {
732-
try {
733-
val result = credentialManager.getCredential(activity, request)
734-
val credential = result.credential
735-
if (credential is PublicKeyCredential) {
736-
promise.resolve(credential.authenticationResponseJson)
737-
} else {
738-
promise.reject("PASSKEY_ASSERTION_FAILED", "Received unexpected credential type: ${credential.type}")
739-
}
740-
} catch (e: GetCredentialCancellationException) {
741-
promise.reject("PASSKEY_USER_CANCELLED", "User cancelled passkey assertion", e)
742-
} catch (e: NoCredentialException) {
743-
promise.reject("PASSKEY_NOT_AVAILABLE", "No passkey credential available for this user", e)
744-
} catch (e: GetCredentialException) {
745-
promise.reject("PASSKEY_ASSERTION_FAILED", e.message ?: "Passkey assertion failed", e)
746-
} catch (e: Exception) {
747-
promise.reject("PASSKEY_ASSERTION_FAILED", e.message ?: "Unexpected error during passkey assertion", e)
748-
}
749-
}
750-
}
751679

752680
override fun onActivityResult(activity: Activity, requestCode: Int, resultCode: Int, data: Intent?) {
753681
// No-op

android/src/main/oldarch/com/auth0/react/A0Auth0Spec.kt

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -160,11 +160,4 @@ abstract class A0Auth0Spec(context: ReactApplicationContext) : ReactContextBaseJ
160160
promise: Promise
161161
)
162162

163-
@ReactMethod
164-
@DoNotStrip
165-
abstract fun passkeyRegistration(challengeJson: String, promise: Promise)
166-
167-
@ReactMethod
168-
@DoNotStrip
169-
abstract fun passkeyAssertion(challengeJson: String, promise: Promise)
170163
}

0 commit comments

Comments
 (0)