Last active
February 13, 2023 18:11
-
-
Save bnlokash/528ace6d52f3e0a96815da26e44c03ea to your computer and use it in GitHub Desktop.
React Native Biometrics Hook
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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