Conversation
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ntract tests Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Add secureKeyStorageAvailable to getAvailability() and reject createKey() with secure_key_storage_unavailable when the device has no Secure Enclave, such as the iOS Simulator, instead of failing inside SecKeyCreateRandomKey. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Implement the Android side of the module against clerk-android's biometric credential storage contract v2, and add hashIdentifierHint() plus identifierHintSha256 on listed records on both platforms. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Report secureKeyStorageAvailable from getAvailability() on Android (false below API 28) and reject createKey() there with secure_key_storage_unavailable instead of biometry_not_available. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
getAvailability() and signIn() report biometric_authentication_unavailable before reading local records when @clerk/expo-biometrics reports no secure key storage, and enroll() maps its secure_key_storage_unavailable rejection to biometric_authentication_unavailable before contacting Clerk. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
🦋 Changeset detectedLatest commit: 76e4e5b The changes in this PR will be included in the next version bump. This PR includes changesets to release 24 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: trueComment |
This was referenced Sep 29, 2026
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Moves biometric credential enrollment, listing, revocation and sign-in out of Clerk's native iOS/Android SDKs and into JS, backed by a new thin native module,
@clerk/expo-biometrics. It builds on today's@clerk/expoand its current native client sync. It does not depend on the sync redesign or the@clerk/expo-native-componentssplit, which will rebase on top of this.This combines #9953, #9959, #9961 and #9960.
@clerk/shared/@clerk/clerk-js: experimental trusted device resources (additive, nothing on theClerkclass changes)trusted_devicesign-in strategy:signIn.create({ strategy: 'trusted_device', trustedDeviceId })andsignIn.attemptFirstFactor({ strategy: 'trusted_device', trustedDeviceId, clientData, signature, algorithm: 'ES256' }). The challenge is exposed onsignIn.firstFactorVerification.trustedDeviceChallenge(FAPI'sexpires_atthere is in seconds).AuthConfig.nativeSettings.BiometricCredentialresource, plusUser.__experimental_getBiometricCredentials(),__experimental_prepareBiometricCredential(),__experimental_attemptBiometricCredential()and__experimental_revokeBiometricCredential(id)for/v1/me/biometric_credentials.clerk.native.jsgoes from 79.94KB to 80.63KB gzip, so itsmaxSizegoes from 80KB to 82KB.@clerk/expo-biometrics: new experimental native module (iOS and Android)It handles only the device side: key creation, ES256 signing behind a biometric prompt, and on-device credential records. It makes no FAPI calls and doesn't depend on clerk-ios or clerk-android.
trustedDeviceCredentialskeychain item. The item and the reinstall marker follow the clerk-ios storage contract v1 (test: pin biometric credential storage format clerk-ios#584), so credentials created here and byClerkKitin the same app are interchangeable.getAvailability()reportssecureKeyStorageAvailable: false, because Secure Enclave keys fail there.secp256r1keys, signed throughBiometricPrompt.noBackupFilesDir/clerk/biometric_credentials.v2.json. Writes follow the clerk-android v2 storage contract (feat(api): isolate biometric credential storage clerk-android#966): file lock, atomic writes, unknown fields preserved.hashIdentifierHint()andidentifierHintSha256on records let hints match on both platforms.Why it's a separate package rather than part of
@clerk/expo: Expo autolinks every native module in an installed package. Putting this in@clerk/expowould link LocalAuthentication andandroidx.biometricinto every app, and those apps would have to declareNSFaceIDUsageDescriptionwhether or not they use biometrics. It follows the same pattern as@clerk/expo-passkeysand@clerk/expo-google-signin.@clerk/expo:useBiometricCredentials()runs in JS@clerk/expo-biometricsis an optional peer dependency, loaded with a guardedrequire. Without it, the hook's methods throw an error that explains how to install it and rebuild.BiometricCredentials.swift:nativeSettings.idand identifier hint. Records whose key is missing are pruned, and records are reconciled with the server list when a session is active.createKey→ prepare → sign → attempt →saveRecord, with the key and server credential cleaned up if a step fails.signIn.create→ sign the challenge →attemptFirstFactor. The local record is dropped when the server or keystore reports it gone.reverify()stays on Clerk's native SDK through the existingClerkExpomodule, and still uses today's sync coordinator (waitForPendingJsToNativeSync/synchronizeNativeClientToJs). FAPI only liststrusted_devicereverification factors from API version 2026-08-20, and clerk-js doesn't send that version yet.ClerkExpoare left in place, unused by the hook, and will be removed in a follow-up.Sign-in with Face ID completes in JS through
setActive. Apps that render native components receive the session through the existing sync, the same as any other JS sign-in.Checklist
pnpm testruns as expected.pnpm buildruns as expected.Type of change
🤖 Generated with Claude Code