Android SharedPreferences Tutorial and Example

Implementing biometric authentication with fingerprint

A fingerprint sensor lets Android users approve sensitive actions quickly without typing a password. The sensor performs a local match against an enrolled biometric, and the app receives an authentication result rather than the fingerprint image. Keeping that distinction clear is essential for privacy, storage, and consent.

Modern apps should use AndroidX BiometricPrompt rather than a sensor-specific workflow. It provides a consistent system prompt across supported Android versions and can bind a successful check to a cryptographic operation. This makes the pattern suitable for unlocking records, approving payments, or protecting high-value settings.

This Kotlin guide covers setup, capability checks, Keystore-backed encryption, callbacks, fallbacks, testing, and release. It reflects Australian conditions: Android is a major part of the local handset market, people expect strong security in banking and everyday apps, and biometric templates must stay under device and app controls.

Define the security boundary

Start by defining what the check protects. Authentication confirms that an enrolled user is present; authorisation decides whether that person may view or change the resource. Keep the protected action narrow, use a clear prompt title, and never treat biometric success as proof that a server session is still valid.

Australian privacy expectations reinforce this boundary. The Privacy Act 1988 and the Notifiable Data Breaches scheme apply to many Australian organisations, while the Australian Signals Directorate recommends locked screens and current software. Keep templates in Android's protected subsystem, collect no raw scans, and avoid logging biometric events with user identifiers.

Prepare the Android project

Add AndroidX Biometric to the app module and declare the normal biometric permission in the manifest. No runtime permission dialog is needed, but the device must have a secure screen lock and an enrolled biometric. Support a sensible minimum SDK and test older hardware, because Australia’s Android market includes Samsung models, budget phones, and Pixels rather than only current flagships.

implementation("androidx.biometric:biometric:1.1.0")
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
<uses-permission
    android:name="android.permission.USE_FINGERPRINT"
    android:maxSdkVersion="28" />

Check hardware and enrolment before opening the interface. canAuthenticate() distinguishes a ready device from cases such as missing hardware, no enrolled fingerprint, or a temporarily unavailable sensor. Show a setup path when needed. A modern BiometricPrompt cannot force every device to use a fingerprint sensor, so describe the feature as biometric authentication and explain the available fallback honestly.

Run the BiometricPrompt flow

Use BIOMETRIC_STRONG for sensitive operations and reject unsupported devices early:

val status = BiometricManager.from(this).canAuthenticate(
    BiometricManager.Authenticators.BIOMETRIC_STRONG
)

A successful status means the app may present its prompt; the fingerprint has not yet been checked.

Build a prompt that names the action and keep its callback on the main executor:

val promptInfo = BiometricPrompt.PromptInfo.Builder()
    .setTitle("Unlock secure records")
    .setSubtitle("Use your fingerprint to continue")
    .setAllowedAuthenticators(BiometricManager.Authenticators.BIOMETRIC_STRONG)
    .setNegativeButtonText("Use PIN")
    .build()

The negative button opens the app’s recovery path; it does not authenticate a PIN by itself. Use the legacy FingerprintManager only when a product requirement truly excludes face or iris recognition and you accept narrower device coverage.

Create one BiometricPrompt per Activity or Fragment and call authenticate(promptInfo) from a user action. Avoid launching it automatically at screen startup, which can feel intrusive and create duplicate prompts after configuration changes.

Protect data with a Keystore key

BiometricPrompt without a CryptoObject only gates the interface or session. To protect stored data, generate an AES-GCM key in AndroidKeyStore that requires a fresh strong biometric for each use. Pass an initialised Cipher to the prompt so Android authorises that exact cryptographic operation.

For API 30 and later, configure per-use authentication with setUserAuthenticationParameters(0, KeyProperties.AUTH_BIOMETRIC_STRONG). On earlier supported versions, use setUserAuthenticationValidityDurationSeconds(-1). Supply the Cipher through CryptoObject, then encrypt or decrypt only in onAuthenticationSucceeded. Store the random IV beside the ciphertext, but never export the key from AndroidKeyStore.

Enrolment changes can invalidate a key bound to biometric identity. Catch KeyPermanentlyInvalidatedException, remove the unreadable encrypted payload, and ask the user to enrol again before creating a replacement key. This prevents a revoked fingerprint from continuing to unlock old data.

Handle outcomes and recovery

Treat the callback outcomes precisely. onAuthenticationSucceeded means the biometric check and cryptographic authorisation succeeded. onAuthenticationFailed usually means a non-matching finger was presented, so keep the system prompt open and avoid alarming error messages for every attempt.

onAuthenticationError covers cancellation, a chosen fallback, missing enrolment, hardware failure, and lockout. Map user cancellation to a quiet return, offer PIN recovery for the negative-button action, and explain temporary lockout. After permanent lockout, direct the user to the device’s secure screen-lock settings rather than looping the prompt.

Do not expose a screen containing sensitive data before authorisation completes, and clear temporary decrypted values when the session ends. Handle configuration changes through the AndroidX lifecycle, and disable repeat taps while a check is active. Server-side actions still need their own re-authentication challenge.

Design for Australian users

Australian users need speed in busy settings. A commuter opening a banking or rewards app on a crowded train in Sydney or Melbourne benefits from a short prompt, plain labels, and controls reachable with one thumb. Avoid collecting a fingerprint again for a routine screen that contains no protected data.

Accessibility and enrolment states need equal attention. Support large text, screen readers, and the system font scale, provide an accessible PIN fallback, and send users to Android enrolment settings when no biometric exists. Say clearly that the sensor verifies identity and that Android stores the template.

If the protected screen sits inside a navigation drawer, adaptive screen layouts can keep the authentication action usable on Android tablets used in Australian classrooms, studios, and field offices. Responsive behaviour must not hide the fallback or place critical controls outside comfortable reach.

Choose and validate the authentication approach

Test on real hardware, not only emulators. Cover a current Pixel, representative Samsung devices, an older supported phone, no enrolled biometric, a changed enrolment, repeated bad fingers, cancellation, and lockout. Automated unit tests can verify result mapping, while instrumentation tests should confirm the complete system prompt.

Release in stages and monitor anonymised authentication failure rates, not identity data. Ask testers whether the wording matches the action, whether the PIN route works, and whether the flow remains usable with low battery, accessibility settings, and unstable connectivity. Keep a documented rollback that disables biometric unlock without deleting encrypted records.

Approach Security boundary Suitable use Main limitation
BiometricPrompt with CryptoObject Authorises a Keystore-backed cryptographic operation Protecting high-value offline data Depends on sensor support and enrolment
BiometricPrompt without CryptoObject Gates the interface or current session Quick approval for low-risk actions Does not encrypt data by itself
Device PIN, pattern, or password Uses the operating system’s secure credential Universal fallback May be slower and easier to observe
App-specific PIN Uses a separate application secret Recovery and controlled fallback Requires secure storage and reset handling

For most Android apps, BiometricPrompt with a Keystore-backed CryptoObject offers the strongest balance: convenient local approval, hardware-backed protection, and a controlled fallback to device or app credentials.