I intend to create a Xamarin(.Forms) application, and it has to have authentication: the user should provide a username and password to obtain data.
The problem is that it has to work offline as well (meaning it shouldn't rely on a server for the authentication process).
I considered the following so far:
What are the best practices? Is there any built-in solution for Xamarin?
It depends on your app needs - if you just need to authenticate the user to access some restricted data offline - I suggest you to hash the user name and password, and storing it in the local device (doesn't matter where, it's hashed).
If you need to use the username & password later on for authenticate it with the server, then you should use a secured data like keychain, Xamarin has a built in abstraction for using it, it's called Xamarin.Auth, where you can store your credentials securely.
*note - in jailbroken/rooted devices storing sensitive data is risky, use it with caution.
Edit - I have added a working code sample of how to consume and use these services:
1) In your portable project add this interface:
public interface ISecuredDataProvider
{
void Store(string userId, string providerName, IDictionary<string, string> data);
void Clear(string providerName);
Dictionary<string, string> Retreive(string providerName);
}
2) In your Android project, add this implementation:
public class AndroidSecuredDataProvider : ISecuredDataProvider
{
public void Store(string userId, string providerName, IDictionary<string, string> data)
{
Clear(providerName);
var accountStore = AccountStore.Create(Android.App.Application.Context);
var account = new Account(userId, data);
accountStore.Save(account, providerName);
}
public void Clear(string providerName)
{
var accountStore = AccountStore.Create(Android.App.Application.Context);
var accounts = accountStore.FindAccountsForService(providerName);
foreach (var account in accounts)
{
accountStore.Delete(account, providerName);
}
}
public Dictionary<string, string> Retreive(string providerName)
{
var accountStore = AccountStore.Create(Android.App.Application.Context);
var accounts = accountStore.FindAccountsForService(providerName).FirstOrDefault();
return (accounts != null) ? accounts.Properties : new Dictionary<string, string>();
}
}
3) In your iOS project, add this implementation:
public class IOSSecuredDataProvider : ISecuredDataProvider
{
public void Store(string userId, string providerName, IDictionary<string, string> data)
{
Clear(providerName);
var accountStore = AccountStore.Create();
var account = new Account(userId, data);
accountStore.Save(account, providerName);
}
public void Clear(string providerName)
{
var accountStore = AccountStore.Create();
var accounts = accountStore.FindAccountsForService(providerName);
foreach (var account in accounts)
{
accountStore.Delete(account, providerName);
}
}
public Dictionary<string, string> Retreive(string providerName)
{
var accountStore = AccountStore.Create();
var accounts = accountStore.FindAccountsForService(providerName).FirstOrDefault();
return (accounts != null) ? accounts.Properties : new Dictionary<string, string>();
}
}
4) An example of Usage - after fetching facebook token, we'll store it like this:
securedDataProvider.Store(user.Id, "FacebookAuth", new Dictionary<string, string> { { "FacebookToken", token } });
Note - I added two layers of data in order to have the first layer to indicate whether the authentication was Facebook/UserName-Password/other. The 2nd layer was the data itself - i.e facebook token / credentials.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With