Skip to content

Instantly share code, notes, and snippets.

@bnlokash
Last active February 13, 2023 18:11
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save bnlokash/528ace6d52f3e0a96815da26e44c03ea to your computer and use it in GitHub Desktop.
Save bnlokash/528ace6d52f3e0a96815da26e44c03ea to your computer and use it in GitHub Desktop.
React Native Biometrics Hook
import React, { createContext, useState, useEffect, FC, useContext } from 'react'
import Keychain from 'react-native-keychain'
import AsyncStorage from '@react-native-async-storage/async-storage'
interface IBiometricsContext {
isBiometricsSupported: boolean
isBiometricsEnabled: boolean
isBiometricsLoading: boolean
biometricsType: Keychain.BIOMETRY_TYPE | null
enableBiometrics: (username: string; password: string) => Promise<void>
disableBiometrics: () => Promise<void>
promptBiometrics: () => Promise<false | Keychain.UserCredentials>
}
const BiometricsContext = createContext<IBiometricsContext>({
isBiometricsSupported: false,
isBiometricsEnabled: false,
isBiometricsLoading: true,
biometricsType: null,
enableBiometrics: async () => undefined,
disableBiometrics: async () => undefined,
// @ts-ignore
promptBiometrics: () => {}
})
export const BiometricsProvider: FC = ({ children }) => {
const [isBiometricsSupported, setBiometricsSupported] = useState(false)
const [biometricsType, setBiometricsType] = useState<Keychain.BIOMETRY_TYPE | null>(null)
const [isBiometricsEnabled, setBiometricsEnabled] = useState(false)
const [isBiometricsLoading, setBiometricsLoading] = useState(true)
useEffect(() => {
const init = async () => {
const type = await Keychain.getSupportedBiometryType()
if (!type) {
setBiometricsLoading(false)
return
}
setBiometricsSupported(true)
setBiometricsType(type)
setBiometricsEnabled((await AsyncStorage.getItem('is-biometrics-enabled')) === 'true')
setBiometricsLoading(false)
}
init()
}, [])
const enableBiometrics = async (username: string; password: string) => {
setBiometricsLoading(true)
try {
await Keychain.setGenericPassword(username, password, {
service: 'my-app',
accessControl: Keychain.ACCESS_CONTROL.BIOMETRY_ANY,
accessible: Keychain.ACCESSIBLE.WHEN_PASSCODE_SET_THIS_DEVICE_ONLY
})
await AsyncStorage.setItem('is-biometrics-enabled', 'true')
setBiometricsEnabled(true)
setBiometricsLoading(false)
} catch (error) {
setBiometricsLoading(false)
throw error
}
}
const disableBiometrics = async () => {
setBiometricsLoading(true)
try {
await Keychain.resetGenericPassword({ service: 'my-app' })
await AsyncStorage.setItem('is-biometrics-enabled', 'false')
setBiometricsEnabled(false)
setBiometricsLoading(false)
} catch (error) {
setBiometricsLoading(false)
throw error
}
}
const promptBiometrics = async () => {
return Keychain.getGenericPassword({
service: 'my-app',
authenticationPrompt: {
title: `Sign into MyApp using ${biometricsType}`
}
})
}
return (
<BiometricsContext.Provider
value={{
isBiometricsSupported,
isBiometricsEnabled,
isBiometricsLoading,
biometricsType,
enableBiometrics,
disableBiometrics,
promptBiometrics
}}
>
{children}
</BiometricsContext.Provider>
)
}
export default function useBiometrics() {
return useContext(BiometricsContext)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment