Skip to main content

Overview

The useBioKey hook provides a complete React interface for biometric authentication. It manages the BioKeyClient instance, handles state management, and provides methods for enrollment, authentication, and identity management.

Import

import { useBioKey } from 'biokey-react'

Usage

import { useBioKey } from 'biokey-react'

function App() {
  const { 
    identity, 
    status, 
    error, 
    isEnrolled, 
    isLoading, 
    enroll, 
    authenticate, 
    reset 
  } = useBioKey({
    rpId: 'example.com',
    rpName: 'My App',
    serverUrl: 'https://api.example.com'
  })

  return (
    <div>
      {isEnrolled ? (
        <button onClick={() => authenticate('user-123')} disabled={isLoading}>
          {isLoading ? 'Authenticating...' : 'Authenticate'}
        </button>
      ) : (
        <button onClick={() => enroll('user-123')} disabled={isLoading}>
          {isLoading ? 'Enrolling...' : 'Enroll Biometric'}
        </button>
      )}
      {error && <p style={{ color: 'red' }}>{error}</p>}
    </div>
  )
}

Parameters

The hook accepts an optional options object that is passed directly to the BioKeyClient constructor.
options
object
Configuration options for the BioKeyClient instance

Return Value

The hook returns an object with state values and methods:
identity
object | null
The current enrolled identity. Contains credential information if a user has enrolled, otherwise null.
status
string
Current operation status. One of:
  • 'idle' - No operation in progress
  • 'enrolling' - Enrollment in progress
  • 'enrolled' - Enrollment completed successfully
  • 'authenticating' - Authentication in progress
  • 'authenticated' - Authentication completed successfully
  • 'error' - An error occurred
error
string | null
Error message if an operation failed, otherwise null
isEnrolled
boolean
Convenience boolean indicating if a credential is enrolled (!!identity)
isLoading
boolean
Convenience boolean indicating if an operation is in progress (status === 'enrolling' || status === 'authenticating')
enroll
(userId?: string) => Promise<object>
Function to enroll a new biometric credential. See Hooks API for details.
authenticate
(userId?: string) => Promise<object>
Function to authenticate using the enrolled credential. See Hooks API for details.
reset
() => void
Function to clear the stored identity and reset state. See Hooks API for details.

Complete Example

Here’s a complete authentication component with error handling and state management:
import { useBioKey } from 'biokey-react'
import { useEffect } from 'react'

function BiometricAuth({ userId, onAuthenticated }) {
  const {
    identity,
    status,
    error,
    isEnrolled,
    isLoading,
    enroll,
    authenticate,
    reset
  } = useBioKey({
    rpId: 'myapp.com',
    rpName: 'My Secure App',
    serverUrl: 'https://api.myapp.com'
  })

  const handleEnroll = async () => {
    try {
      const result = await enroll(userId)
      console.log('Enrolled successfully:', result)
    } catch (err) {
      console.error('Enrollment failed:', err)
    }
  }

  const handleAuthenticate = async () => {
    try {
      const result = await authenticate(userId)
      console.log('Authenticated:', result)
      onAuthenticated(result)
    } catch (err) {
      console.error('Authentication failed:', err)
    }
  }

  const handleReset = () => {
    if (confirm('Remove your biometric credential?')) {
      reset()
    }
  }

  useEffect(() => {
    if (status === 'authenticated') {
      console.log('User authenticated with public key:', identity.publicKey)
    }
  }, [status, identity])

  return (
    <div>
      <h2>Biometric Authentication</h2>
      
      {error && (
        <div style={{ color: 'red', padding: '10px', marginBottom: '10px' }}>
          Error: {error}
        </div>
      )}
      
      <div style={{ marginBottom: '10px' }}>
        <strong>Status:</strong> {status}
      </div>
      
      {identity && (
        <div style={{ marginBottom: '10px' }}>
          <strong>Enrolled:</strong> {new Date(identity.enrolledAt).toLocaleString()}<br/>
          <strong>Method:</strong> {identity.method}<br/>
          <strong>Device:</strong> {identity.deviceId}
        </div>
      )}
      
      <div style={{ display: 'flex', gap: '10px' }}>
        {!isEnrolled ? (
          <button 
            onClick={handleEnroll} 
            disabled={isLoading}
            style={{ padding: '10px 20px' }}
          >
            {isLoading ? 'Enrolling...' : 'Enroll Biometric'}
          </button>
        ) : (
          <>
            <button 
              onClick={handleAuthenticate} 
              disabled={isLoading}
              style={{ padding: '10px 20px' }}
            >
              {isLoading ? 'Authenticating...' : 'Authenticate'}
            </button>
            <button 
              onClick={handleReset} 
              disabled={isLoading}
              style={{ padding: '10px 20px' }}
            >
              Remove Credential
            </button>
          </>
        )}
      </div>
    </div>
  )
}

export default BiometricAuth

State Management

The hook automatically manages state for you:
  1. Initial Load: On mount, the hook reads any existing identity from localStorage and initializes the status to 'idle'
  2. Enrollment: When enroll() is called, status changes to 'enrolling', then 'enrolled' on success or 'error' on failure
  3. Authentication: When authenticate() is called, status changes to 'authenticating', then 'authenticated' on success or 'error' on failure
  4. Reset: When reset() is called, identity is cleared and status returns to 'idle'
  5. Errors: Any errors are caught and stored in the error state, and the status changes to 'error'

Error Handling

The hook provides multiple ways to handle errors:

Using the error state

const { error, status } = useBioKey()

if (status === 'error' && error) {
  return <div>Error: {error}</div>
}

Using try-catch

const { enroll } = useBioKey()

try {
  await enroll('user-123')
} catch (err) {
  // Handle error
  console.error('Enrollment failed:', err.message)
}

Common errors

  • "No enrolled credential. Call enroll() first." - Attempted to authenticate without enrolling first
  • "PRF key mismatch — identity verification failed." - Biometric verification failed (wrong user)
  • "Server verification failed." - Server rejected the authentication
  • Browser errors - WebAuthn API errors (user cancelled, no biometrics available, etc.)

Client Instance Stability

The hook uses useRef to maintain a stable BioKeyClient instance across re-renders. The client is only created once when the component first mounts, ensuring that:
  • Configuration options are applied consistently
  • Local storage operations remain stable
  • Multiple hook calls in the same component tree share the same client instance

Best Practices

Pass options on first render: The options object is only used when creating the client instance. Changing options after mount will not affect the client.
Handle loading states: Always disable UI elements when isLoading is true to prevent duplicate operations.
Store userId separately: The hook does not store the userId - you must manage this in your application state and pass it to enroll() and authenticate().
Server URL is optional: If you omit serverUrl, the hook works in client-only mode with credentials stored in localStorage.

Next Steps

Hooks API Reference

Detailed reference for all methods and state values

React Integration Guide

Complete guide for integrating BioKey in React apps

BioKeyClient

Learn about the underlying client class

Examples

See full React application examples

Build docs developers (and LLMs) love