Your users store sensitive data in your app. Financial info. Health records. Private messages.
They expect it to be locked down.
Face ID. Touch ID. Fingerprint sensors. These aren't just cool — they're expected. And now you can add them with a single line of code.
In this post:
#The Basics
Biometric auth in NativePHP is beautifully simple.
#PHP (Livewire)
Copied!
use Native\Mobile\Facades\Biometrics;use Native\Mobile\Events\Biometric\Completed; public function authenticate(){ Biometrics::prompt()->id('secure-action');} #[On('native:' . Completed::class)]public function handleBiometric(bool $success, string $id){ if ($id === 'secure-action' && $success) { $this->authorized = true; }}
#JavaScript (Vue/React/Inertia)
Copied!
import { Biometric, On, Off, Events } from '@nativephp/mobile'; const authenticate = async () => { await Biometric.prompt().id('secure-action');}; On(Events.Biometrics.Completed, ({ success, id }) => { if (id === 'secure-action' && success) { authorized.value = true; }});
#Handling the Result
The Completed event gives you everything you need.
#PHP (Livewire)
Copied!
#[On('native:' . Completed::class)]public function handleBiometric(bool $success, string $id, ?string $error = null){ if ($success) { $this->proceed(); } else { match ($error) { 'user_cancel' => $this->showMessage('Cancelled'), 'lockout' => $this->showMessage('Too many attempts'), default => $this->showMessage('Auth failed'), }; }}
#JavaScript (Vue/React/Inertia)
Copied!
On(Events.Biometrics.Completed, ({ success, id, error }) => { if (success) { proceed(); } else { switch (error) { case 'user_cancel': showMessage('Cancelled'); break; case 'lockout': showMessage('Too many attempts'); break; default: showMessage('Auth failed'); } }});
#Real-World Patterns
#Protect App Launch (PHP)
Copied!
public function mount(){ Biometrics::prompt()->id('app-unlock');} #[On('native:' . Completed::class)]public function handleAuth(bool $success, string $id){ if ($id === 'app-unlock' && $success) { $this->unlocked = true; }}
#Protect App Launch (JavaScript)
Copied!
import { Biometric, On, Off, Events } from '@nativephp/mobile'; onMounted(async () => { await Biometric.prompt().id('app-unlock');}); On(Events.Biometrics.Completed, ({ success, id }) => { if (id === 'app-unlock' && success) { unlocked.value = true; }});
#View Sensitive Data (PHP)
Copied!
public string $balance = '••••••'; public function reveal(){ Biometrics::prompt()->id('reveal-balance');} #[On('native:' . Completed::class)]public function handleAuth(bool $success, string $id){ if ($id === 'reveal-balance' && $success) { $this->balance = '$' . number_format(auth()->user()->balance, 2); }}
#View Sensitive Data (JavaScript)
Copied!
const balance = ref('••••••'); const reveal = async () => { await Biometric.prompt().id('reveal-balance');}; On(Events.Biometrics.Completed, ({ success, id }) => { if (id === 'reveal-balance' && success) { balance.value = formatCurrency(user.balance); }});
#Best Practices
- Always provide a fallback — Not everyone has biometrics enabled
- Don't over-prompt — Cache auth status for a few minutes
- Explain why — Tell users what they're authenticating for
- Test failure paths — Handle cancellation and lockouts gracefully
Your users trust you with their data. With NativePHP biometrics, you can prove that trust is well-placed.
Ship secure. 🔐