Skip to content

signin: add cross-platform biometric auth flow#715

Closed
softartdev wants to merge 1 commit intodevfrom
codex/add-biometric-authentication-support
Closed

signin: add cross-platform biometric auth flow#715
softartdev wants to merge 1 commit intodevfrom
codex/add-biometric-authentication-support

Conversation

@softartdev
Copy link
Copy Markdown
Owner

Motivation

  • Provide a platform-agnostic biometric sign-in flow so users can authenticate with device biometrics where available while preserving the existing password fallback and navigation behavior.
  • Surface a simple shared contract so platform teams can implement secure native prompts and the app can react uniformly in the presentation layer.

Description

  • Add a shared contract BiometricAuthService and result sealed type BiometricAuthResult in core/presentation and implement platform-specific providers for Android (AndroidBiometricAuthService), iOS (IosBiometricAuthService), JVM (JvmBiometricAuthService), and Wasm (WasmJsBiometricAuthService).
  • Wire biometric service into DI via a new singleOfBiometricAuthService() expect/actual hook and register actual implementations in each platform module, and add androidx.biometric to dependencies for the Android target.
  • Inject BiometricAuthService into SignInViewModel, add OnBiometricClick action and new SignInResult states (available, in-progress, success, failed, fallback-to-password), and implement availability check and biometric authentication flow that navigates to AppNavGraph.Main on success.
  • Update SignInScreen to show a biometric button only when biometric auth is available, add UI strings and a test tag (SIGN_IN_BIOMETRIC_BUTTON_TAG), and route biometric failures to the existing password path.

Testing

  • Attempted the AI agent verification sequence: ran ./gradle/build_quick.sh, ./gradlew :app:android:connectedCheck, and ./gradlew build, but all three failed in this environment before project tasks could execute due to plugin resolution errors (plugin org.gradle.kotlin.kotlin-dsl:6.5.2 could not be resolved).
  • Unit/host tests were not executed because the build failed early; SignInViewModelTest was updated to mock BiometricAuthService and exercise existing password flows locally during development.

Codex Task

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ed3908fafe

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

factoryOf<AppVersionUseCase, Context>(constructor = ::AppVersionUseCase)

actual fun Module.singleOfBiometricAuthService(): KoinDefinition<BiometricAuthService> =
factoryOf<BiometricAuthService, Context>(constructor = ::AndroidBiometricAuthService)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Inject an Activity context for biometric auth

This binding creates AndroidBiometricAuthService from Koin's generic Context, but Android Koin is initialized with the application context (androidContext(this@MainApplication)), not an Activity. As a result, authenticate() cannot obtain a FragmentActivity and immediately returns FallbackToPassword, so Android users will never see a biometric prompt even when isBiometricAvailable() is true.

Useful? React with 👍 / 👎.

Comment on lines +40 to +43
override fun onAuthenticationFailed() {
if (continuation.isActive) {
continuation.resume(BiometricAuthResult.Failed)
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Do not finish auth flow on non-terminal biometric failure

onAuthenticationFailed() is a non-terminal callback (e.g., one bad fingerprint while the prompt remains open), but this code resumes the coroutine as Failed immediately. That ends the sign-in flow on the first mismatch and can ignore a later successful scan from the same prompt session, producing incorrect login failures.

Useful? React with 👍 / 👎.

Comment on lines +66 to +70
showBiometricButton = signInResultState.value in setOf(
SignInResult.ShowBiometricAvailable,
SignInResult.ShowBiometricInProgress,
SignInResult.ShowBiometricSuccess,
SignInResult.ShowBiometricFailed,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve biometric button visibility across password errors

The biometric button is shown only for a subset of biometric-specific SignInResult values; after any password attempt, SignInViewModel switches state to ShowEmptyPassError, ShowIncorrectPassError, or ShowSignInForm, which hides the button even on devices where biometrics are available. This traps users in password-only mode unless the screen is recreated.

Useful? React with 👍 / 👎.

@softartdev softartdev closed this Apr 27, 2026
@softartdev softartdev deleted the codex/add-biometric-authentication-support branch April 27, 2026 21:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant