Mobile DevelopmentBiometrics authentication in NFT Reality
Krzysztof Kapli ński
Recently I was asked to implement biometrics authentication in our mobile project, NFT Reality. In my previous project, my colleague from the team was working on a similar solution, so I had some basic knowledge of what I should do. After some discussion and reading many articles, I was sure about one thing - technical implementation is not my main concern.
I started my research by reading the documentation of two popular libraries in React Native, which provide native biometric functionality - react-native-keychain and react-native-biometrics. The first one is used for storing sensitive data in our application, but if we want, we can additionally secure this data with biometrics. The second library is dedicated to server authentication using biometry.
First, I asked myself what our use case is. This is the most crucial part of the work. Some solutions can’t be safely implemented into our authentication flow, and some require a bunch of work on the backend side. I will try to bring you closer to the problems I encountered during my work on biometric authentication.
What is our use case?
add biometric login to the app; after the first login,
add a biometry option inside the app to easily switch ON/OFF biometry
Our auth environment:
- token with auto refresh
- every request sent with the token expands his lifetime
What can we do if we build something that does not require changes on our backend side? First, according to best practices, we should not save user credentials on user devices. We should use secure storage for tokens or other forms of sensitive information but not user credentials such as passwords. react-native-keychain uses iOS Keychain and Android Keystore, which provides a high level of security but is not for all android devices. Android Keystore is used for API level 23+, and in lower versions, there is an increased risk of obtaining secret information. Of course, if the security of your application is not the highest priority and we want a simple and fast solution, we can still use this option. You can read more information about types of secure storage: React Native security.
Let’s look at our environment a second time. We have a token with auto refresh. Why can't we store our access token and obtain it with biometry anytime we want? We can, but is it a real biometry login implementation? Our token has a lifetime which will expand after every successful request. What if we stop using the app for a long time and later decide to log in? We will obtain a terminated token, and login will fail. There is a different approach using manual refresh tokens, which I will discuss in the next chapter of this article.
Let’s assume that we will save the username and password with react-native-keychain. Is it fit our use case? Well, after the first login, we can show a popup to the user, and we can save user credentials if the user says YES. But what if the user says NO? Our second task is to add biometry options to switch ON/OFF biometry in the app. How can we switch ON biometry in the settings screen? We don’t have user credentials. We had a chance to save them in the login form, but the user decided to cancel this action. I can’t find a good answer for that problem because it’s not a technical issue. The answer can be simple, right? We can save user credentials permanently with an additional variable IS_BIOMETRY_ENABLED, and using that boolean, and we can switch ON/OFF biometry in the settings screen. Is it fair to save something even if the user answers explicitly that he doesn't want to enable biometry for the app? I will strongly disagree that this is a good solution, and it doesn't testify to our transparency. It can also be a source of future problems with positive reviews before the publication of our app.
What is a workaround to that problem? We can ask the user to confirm his action with his password in the settings screen. We will save the username and password only after successful verification. Finally, we took a step in the backend direction. We can’t verify the user password locally! You can see that implementing local authentication flow with biometry is not simple.
There are a lot of concerns and tradeoffs we have to take, and still, you will find new problems on the horizon. What about resetting the password in the web application created next to the mobile app? If we change the password in the web app, we will break our authentication flow in the mobile app.
We can’t locally set up full biometric authentication for our app, at least not without some drawbacks.
Manual refresh token using biometry
Previously I mentioned that our application uses a token with auto refresh. The implementation I will describe in this section can not be used in my case. If sessions in your application also are pretty long and your token is auto-refreshing, you probably don’t need to use biometry for refreshing sessions. This approach is the best if your sessions are short and you want to authenticate the user every time he uses the application. Maybe you have already refreshed the token, and this solution fits your environment without any changes on the backend side.
Implementation is simple. We save the refresh token in our secure storage, and after our permit expires, we can refresh the session using biometry to get the previously saved refresh token. We can quickly implement biometry settings inside the app because we can keep both access and refresh tokens in secure storage without concern. Switching ON/OFF biometry will be handled by additional variables like IS_BIOMETRY_ENABLED.
A refresh token is used to get new access tokens with a short lifetime. Remember that the refresh token also has a lifetime, it can be very long, but if we don’t use the app for months, our biometric authentication can fail.
Let’s talk about the logout function in your app. If your backend gives you a logout method, you will probably be unable to use the refresh token after successful logout. The logout function triggered on a backend will clean the user session, and the refresh token will no longer work. As you can see, this implementation of biometry can not be considered a login implementation. We can only refresh a user session. It can be enough for your client, but If you want to create a separate method for login, you will have to go with a complete backend solution.
If you want to build an accurate biometry login method, you should use this solution. It requires work on both frontend and backend sides, but this is probably the safest solution you can go with. Using react-native biometrics, we can create a public-private key pair protected with biometry. A basic example can be described below:
When a user decides to enable biometry, we use the
create keys()function to create a public-private key pair which will be stored in the Keystore. Additionally, a public key is returned by a process, and we can send it to our backend.
When a user tries to log in, we call
createSignature(), and the user is prompted to authenticate with biometry. Successful authentication will return a signature generated from our private key stored in the Keystore. Next, we will send a signature to our backend, and in response, we will get a new access token.
When users want to disable or enable biometrics in settings screens, we can use
deleteKeys()to trigger ON/OFF actions.
Comparing this flow to the previous chapters, we do not consume our existing authentication flow. This approach requires creating new login methods on the backend side. It’s worth mentioning that react-native-biometrics was recently updated, and now it supports passcode fallback when Face ID or Touch ID fails.
Another solution for that implementation will be to use separate libraries for biometric authentication and key pair generation.
This article helps you to find the best solution for your use case. You may want to test biometry with a simple approach or decide to use biometry only for refreshing tokens. Finally, if you want to implement solid biometric authentication you will go with server authentication using biometry. The NFT Reality app is now in a process of developing and is planned to be released in 2023.