Open activebiz opened 4 years ago
The username/password examples are just to make the API usage clear I think.
What you need to store depends on your particular situation. Think of it like this: what can you store so that if there is a security breach, the impact will be minimal?
Token-based approach is not about this library, but about your login system. If you use oauth2 on your service/website for example, you will likely get some access token after logging in. This access token is sent with each API call to show the server you're authenticated. It can also be revoked. So you should store the access token rather than username/password.
In the event of a security breach, you can simply revoke the token and there will be no further damage. If the attacker gets a username/password, the impact is very big. They can for example try this username/password on other services. Storing passwords should not be taken lightly.
The other question to ask is: should you be storing this info at all? Why do you want to store a password? Wouldn't it be safer if the user just has to re-type their password? Maybe you can avoid the whole issue in the first place.
To add to @Brqqq's answer, if you want to authenticate users on your server and tokens is not a solution (for whatever reason), maybe you should consider following what react-native-biometrics recommends: https://github.com/SelfLender/react-native-biometrics#usage.
When a user enrolls in biometrics, a key pair is generated. The private key is stored securely on the device and the public key is sent to a server for registration. When the user wishes to authenticate, the user is prompted for biometrics, which unlocks the securely stored private key. Then a cryptographic signature is generated and sent to the server for verification. The server then verifies the signature. If the verification was successful, the server returns an appropriate response and authorizes the user.
See also https://android-developers.googleblog.com/2015/10/new-in-android-samples-authenticating.html
So you should store the access token rather than username/password.
I think the OP is actually asking what is the best practice for securely storing arbitrary data (such as a token) using this library. The API seems to be heavily focused on storing username and passwords. For example, the method setGenericPassword
has the following signature
setGenericPassword(username, password, [{ accessControl, accessible, accessGroup, service, securityLevel }])
That seems more than just an example to make usage clearer, I would expect something more like
setItem(key, value, options)
getItem(key)
I have 2 values (tokens) that i would like to store but I am not sure what is the best way to store them.. any recommendations?
I found two ways how it can be implemented (but both are some kind of hack)
Interface
type SetSecureValue = (key: string, value: string) => Promise<void>
type GetSecureValue = (key: string) => Promise<string | false>
type RemoveSecureValue = (key: string) => Promise<void>
const setSecureValue: SetSecureValue = (key, value) =>
Keychain.setGenericPassword(key /* <- can be a random string */, value, { service: key })
const getSecureValue: GetSecureValue = async (key) => { const result = await Keychain.getGenericPassword({ service: key }) if (result) { return result.password } return false }
const removeSecureValue: RemoveSecureValue = (key) => Keychain.resetGenericPassword({ service: key })
2. With internet credentials
```typescript
const setSecureValue: SetSecureValue = (key, value) =>
Keychain.setInternetCredentials(key, key /* <- can be a random string */, value)
const getSecureValue: GetSecureValue = async (key) => {
const result = await Keychain.getInternetCredentials(key)
if (result) {
return result.password
}
return false
}
const removeSecureValue: RemoveSecureValue = (key) =>
Keychain.resetInternetCredentials(key)
p.s. There is no options in examples, but it shouldn't be a problem to add them
This should really make it into the README.md
What would be the difference between saving with setGenericPassword
and setInternetCredentials
?
What would be the difference between saving with
setGenericPassword
andsetInternetCredentials
?
almost the same.
the internetCredentials
has more attributes to distinguish the remote access. (i.e. The generic one cannot save the server attribute)
@fattomhk So, if my app use credentials that are also used for a web portal, I need to use setInternetCredentials
and add the server
attribute (server will be web portal URL?)
@fattomhk So, if my app use credentials that are also used for a web portal, I need to use
setInternetCredentials
and add theserver
attribute (server will be web portal URL?)
yes, server
should be the domain name or IP address of url (etc. github.com
).
@fattomhk If I use setInternetCredentials
on iOS and in the key server
I use my domain name (etc. www.exampledomainservervalue.com
), those credentials will appear on my phone keychain (Settings > Passwords) and can be modified via phone settings?
@fattomhk If I use
setInternetCredentials
on iOS and in the keyserver
I use my domain name (etc.www.exampledomainservervalue.com
), those credentials will appear on my phone keychain (Settings > Passwords) and can be modified via phone settings?
No. If you want to do that, in short, you need to use setSharedWebCredentials
and requestSharedWebCredentials
Normal flow:
@fattomhk If I use
setInternetCredentials
on iOS and in the keyserver
I use my domain name (etc.www.exampledomainservervalue.com
), those credentials will appear on my phone keychain (Settings > Passwords) and can be modified via phone settings?No. If you want to do that, in short, you need to use
setSharedWebCredentials
andrequestSharedWebCredentials
Normal flow:
But to those functions are only available on iOS, so for Android use “setInternetCredentials”?
But to those functions are only available on iOS, so for Android use “setInternetCredentials”?
AFAIK, this lib cannot share pwd to another app (correct me if it support) or to web (Android) . If you want to implement it, maybe smartlock-passwords is the thing you are looking for.
smartlock-password is an android tech?
smartlock-password is an android tech?
yes, android only. A Google play service tech, required Android 4.4+ with play service 15+
Hello, @Iltimirov thanks your solution worked perfectly on my current app for saving access and refresh tokens on JWT authentication.
I used your code and I added its current library types
import * as Keychain from 'react-native-keychain';
type SetSecureValue = (key: string, value: string) => Promise<false | Keychain.Result>
type GetSecureValue = (key: string) => Promise<string | false>
type RemoveSecureValue = (key: string) => Promise<boolean>
export const setSecureValue: SetSecureValue = async (key, value) =>
await Keychain.setGenericPassword(key /* <- can be a random string */, value, { service: key })
export const getSecureValue: GetSecureValue = async (key) => {
const result = await Keychain.getGenericPassword({ service: key })
if (result) {
return result.password
}
return false
}
export const removeSecureValue: RemoveSecureValue = async (key) =>
await Keychain.resetGenericPassword({ service: key })
Is there an advantage to this over just using setGenericPassword directly? I guess API clarity?
Hi,
I am new to this package so apologies in advance if this sounds basic question. I understand the following statement which is on the readme.md.
Follow best practices and do not store user credentials on a device. Instead use tokens or other forms of authentication and re-ask for user credentials before performing sensitive operations.
However all the methods in the documentation and in he keychainexample is using username/passwords. So I am not sure how do I use tokens to store the sensitive data to the device using this library?!
Thanks