Overview
This page provides detailed documentation for all methods and state values returned by the useBioKey hook.
State Values
identity
The currently enrolled biometric identity. Returns null if no credential has been enrolled.
Type Definition
interface Identity {
publicKey : string // Hex-encoded derived key
credentialId : string // Hex-encoded WebAuthn credential ID
deviceId : string // Device fingerprint (16 chars)
enrolledAt : number // Timestamp in milliseconds
method : 'prf' | 'rawid' // Key derivation method
}
Example
const { identity } = useBioKey ()
if ( identity ) {
console . log ( 'Public key:' , identity . publicKey )
console . log ( 'Enrolled on:' , new Date ( identity . enrolledAt ). toLocaleString ())
console . log ( 'Device:' , identity . deviceId )
console . log ( 'Method:' , identity . method )
}
Storage
The identity object is automatically stored in localStorage with the key biokey:{rpId}. The hook reads this value on mount and updates it when enrollment succeeds.
status
Current operation status indicating the state of the authentication flow.
Possible Values
Value Description 'idle'No operation in progress (initial state) 'enrolling'Enrollment operation in progress 'enrolled'Enrollment completed successfully 'authenticating'Authentication operation in progress 'authenticated'Authentication completed successfully 'error'An error occurred during the last operation
State Flow
idle → enrolling → enrolled
↓
error
enrolled → authenticating → authenticated
↓
error
Example
const { status } = useBioKey ()
const statusMessage = {
idle: 'Ready to enroll' ,
enrolling: 'Setting up your biometric...' ,
enrolled: 'Biometric enrolled successfully!' ,
authenticating: 'Verifying your identity...' ,
authenticated: 'Welcome back!' ,
error: 'Something went wrong'
}
return < div > { statusMessage [ status ] } </ div >
error
Error message from the last failed operation. Returns null when no error has occurred or after a successful operation.
When Errors Occur
The error state is set when:
Enrollment fails (user cancels, hardware unavailable, etc.)
Authentication fails (wrong credential, verification error, etc.)
Network errors (when using server mode)
WebAuthn API errors
Common Error Messages
// Authentication without enrollment
"No enrolled credential. Call enroll() first."
// Biometric mismatch
"PRF key mismatch — identity verification failed."
"Key mismatch — identity verification failed."
// Server errors
"Server verification failed."
"Server public key mismatch."
// Browser/user errors
"User cancelled the operation"
"No available authenticator"
Example
const { error , status } = useBioKey ()
if ( status === 'error' && error ) {
return (
< div style = { {
padding: '12px' ,
background: '#fee' ,
border: '1px solid #c00' ,
borderRadius: '4px'
} } >
< strong > Error: </ strong > { error }
</ div >
)
}
isEnrolled
Convenience boolean indicating whether a credential is currently enrolled. Equivalent to !!identity.
Example
const { isEnrolled , enroll , authenticate } = useBioKey ()
return (
< div >
{ isEnrolled ? (
< button onClick = { () => authenticate ( 'user-123' ) } >
Sign In with Biometric
</ button >
) : (
< button onClick = { () => enroll ( 'user-123' ) } >
Set Up Biometric
</ button >
) }
</ div >
)
isLoading
Convenience boolean indicating if an operation is in progress. Equivalent to status === 'enrolling' || status === 'authenticating'.
Example
const { isLoading , enroll } = useBioKey ()
return (
< button onClick = { () => enroll ( 'user-123' ) } disabled = { isLoading } >
{ isLoading ? (
<>
< Spinner /> Enrolling...
</>
) : (
'Enroll Biometric'
) }
</ button >
)
Methods
enroll()
enroll
(userId?: string) => Promise<Identity>
Enrolls a new biometric credential and derives a cryptographic key.
Parameters
Optional user identifier. If provided and serverUrl is configured, the enrollment will be synced with the server. If omitted, a random 16-byte ID is generated.
Return Value
Returns a Promise that resolves to an Identity object:
Promise <{
publicKey : string
credentialId : string
deviceId : string
enrolledAt : number
method : 'prf' | 'rawid'
}>
Behavior
Sets status to 'enrolling' and clears any previous error
Prompts the user for biometric authentication (Face ID, Touch ID, Windows Hello, etc.)
Creates a new WebAuthn credential with PRF extension
Derives a cryptographic key using either PRF or HKDF (fallback)
Stores the identity in localStorage
If serverUrl and userId are provided, sends enrollment to server
Updates status to 'enrolled' and sets identity state
On error, sets status to 'error', sets error state, and throws
Example
const { enroll , isLoading , error } = useBioKey ({
serverUrl: 'https://api.example.com'
})
const handleEnroll = async () => {
try {
const result = await enroll ( 'user-123' )
console . log ( 'Enrollment successful!' )
console . log ( 'Public key:' , result . publicKey )
console . log ( 'Credential ID:' , result . credentialId )
console . log ( 'Device ID:' , result . deviceId )
console . log ( 'Method used:' , result . method )
} catch ( err ) {
console . error ( 'Enrollment failed:' , err . message )
// Error is also available in the error state
}
}
return (
< button onClick = { handleEnroll } disabled = { isLoading } >
{ isLoading ? 'Enrolling...' : 'Enroll' }
</ button >
)
Notes
Platform Support : The user’s device must support WebAuthn platform authenticators (biometrics). If not available, the Promise will reject.
Server Sync : Enrollment data is only sent to the server if both serverUrl and userId are provided. Network failures are silently caught to allow offline enrollment.
authenticate()
authenticate
(userId?: string) => Promise<AuthResult>
Authenticates using the enrolled biometric credential and verifies the derived key.
Parameters
Optional user identifier. If provided and serverUrl is configured, authentication will be verified with the server.
Return Value
Returns a Promise that resolves to an authentication result:
Promise <{
verified : boolean
publicKey : string
method : 'prf' | 'rawid'
}>
Behavior
Checks if a credential is enrolled (throws error if not)
Sets status to 'authenticating' and clears any previous error
Requests a challenge from the server (if serverUrl and userId provided) or generates one locally
Prompts the user for biometric verification
Re-derives the cryptographic key using the stored credential
Verifies the derived key matches the stored publicKey
If using server mode, sends the challenge response to server for verification
Updates status to 'authenticated'
On error, sets status to 'error', sets error state, and throws
Example
const { authenticate , isEnrolled , isLoading } = useBioKey ({
serverUrl: 'https://api.example.com'
})
const handleSignIn = async () => {
if ( ! isEnrolled ) {
alert ( 'Please enroll first' )
return
}
try {
const result = await authenticate ( 'user-123' )
if ( result . verified ) {
console . log ( 'Authentication successful!' )
console . log ( 'Public key:' , result . publicKey )
console . log ( 'Method:' , result . method )
// Proceed with login
}
} catch ( err ) {
console . error ( 'Authentication failed:' , err . message )
}
}
return (
< button onClick = { handleSignIn } disabled = { isLoading } >
{ isLoading ? 'Authenticating...' : 'Sign In' }
</ button >
)
Error Cases
// No credential enrolled
try {
await authenticate ( 'user-123' )
} catch ( err ) {
// err.message === "No enrolled credential. Call enroll() first."
}
// Key mismatch (wrong user/device)
try {
await authenticate ( 'user-123' )
} catch ( err ) {
// err.message === "PRF key mismatch — identity verification failed."
}
// Server verification failed
try {
await authenticate ( 'user-123' )
} catch ( err ) {
// err.message === "Server verification failed."
}
Notes
Requires Enrollment : You must call enroll() successfully before calling authenticate(). The method will throw if no credential exists.
Key Verification : The method automatically verifies that the re-derived key matches the stored key, providing cryptographic proof of identity.
reset()
Clears the stored identity and resets all state to initial values.
Parameters
None
Return Value
void - This method does not return a value.
Behavior
Calls client.clearIdentity() to remove identity from localStorage
Sets identity state to null
Sets status to 'idle'
Sets error to null
Example
const { reset , isEnrolled , identity } = useBioKey ()
const handleRemoveCredential = () => {
if ( confirm ( 'Remove your biometric credential?' )) {
reset ()
console . log ( 'Credential removed' )
}
}
if ( ! isEnrolled ) return null
return (
< div >
< p > Enrolled on: {new Date ( identity . enrolledAt ). toLocaleString () } </ p >
< button onClick = { handleRemoveCredential } >
Remove Credential
</ button >
</ div >
)
Use Cases
User wants to remove their biometric credential
Switching between different user accounts
Error recovery (forcing re-enrollment)
Logout functionality
Notes
Local Only : This method only clears the client-side data. If you’re using server mode, you should also call your server’s API to remove the credential from the database.
Immediate Effect : The reset is synchronous and takes effect immediately. All state values are updated in the same render cycle.
Complete TypeScript Example
Here’s a fully-typed example showing all methods and state:
import { useBioKey } from 'biokey-react'
import { useState } from 'react'
interface AuthComponentProps {
userId : string
onSuccess : ( publicKey : string ) => void
}
const AuthComponent : React . FC < AuthComponentProps > = ({ userId , onSuccess }) => {
const {
identity ,
status ,
error ,
isEnrolled ,
isLoading ,
enroll ,
authenticate ,
reset
} = useBioKey ({
rpId: 'example.com' ,
rpName: 'My App' ,
serverUrl: 'https://api.example.com'
})
const [ lastAction , setLastAction ] = useState < string >( '' )
const handleEnroll = async () => {
setLastAction ( 'enroll' )
try {
const result = await enroll ( userId )
console . log ( 'Enrolled:' , result . publicKey )
} catch ( err ) {
console . error ( 'Enroll error:' , err )
}
}
const handleAuth = async () => {
setLastAction ( 'authenticate' )
try {
const result = await authenticate ( userId )
if ( result . verified ) {
onSuccess ( result . publicKey )
}
} catch ( err ) {
console . error ( 'Auth error:' , err )
}
}
const handleReset = () => {
setLastAction ( 'reset' )
reset ()
}
return (
< div className = "auth-container" >
< h2 > Biometric Authentication </ h2 >
{ /* Status Display */ }
< div className = "status-badge" data-status = { status } >
{ status }
</ div >
{ /* Error Display */ }
{ error && (
< div className = "error-message" >
< strong > Error: </ strong > { error }
</ div >
) }
{ /* Identity Info */ }
{ identity && (
< div className = "identity-info" >
< div > Public Key: { identity . publicKey . slice ( 0 , 16 ) } ... </ div >
< div > Device: { identity . deviceId } </ div >
< div > Method: { identity . method . toUpperCase () } </ div >
< div > Enrolled: {new Date ( identity . enrolledAt ). toLocaleDateString () } </ div >
</ div >
) }
{ /* Action Buttons */ }
< div className = "button-group" >
{ ! isEnrolled ? (
< button
onClick = { handleEnroll }
disabled = { isLoading }
className = "btn-primary"
>
{ isLoading && lastAction === 'enroll'
? 'Enrolling...'
: 'Enroll Biometric'
}
</ button >
) : (
<>
< button
onClick = { handleAuth }
disabled = { isLoading }
className = "btn-primary"
>
{ isLoading && lastAction === 'authenticate'
? 'Authenticating...'
: 'Authenticate'
}
</ button >
< button
onClick = { handleReset }
disabled = { isLoading }
className = "btn-secondary"
>
Remove Credential
</ button >
</>
) }
</ div >
</ div >
)
}
export default AuthComponent
State Machine Diagram
The hook follows a predictable state machine:
Client Instance
The hook uses useRef to maintain a single BioKeyClient instance across re-renders. This ensures:
Options are only processed once
No unnecessary re-initializations
Stable reference for callbacks
Callback Stability
All methods (enroll, authenticate, reset) are wrapped in useCallback with stable dependencies, making them safe to use in effect dependencies:
const { authenticate } = useBioKey ()
// This is safe - authenticate has a stable reference
useEffect (() => {
// Auto-authenticate on mount if enrolled
if ( isEnrolled ) {
authenticate ( 'user-123' )
}
}, [ isEnrolled , authenticate ])
Best Practices
Check isEnrolled first : Always verify isEnrolled is true before calling authenticate().
Disable during operations : Use isLoading to disable UI elements and prevent concurrent operations.
Handle both error patterns : Check both the error state and use try-catch for comprehensive error handling.
Don’t rely on status strings : Use the provided boolean helpers (isEnrolled, isLoading) instead of comparing status strings directly.
Next Steps
useBioKey Hook Back to main hook documentation
BioKeyClient Learn about the underlying client
React Guide Complete React integration guide
Security Model Understand the security architecture