Offline authentication best practices in Xamarin

6k views Asked by At

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:

  • Storing username and password in Preferences - it is not encrypted, easy to reset, easy to obtain etc.
  • Storing username and password in database - it could be encrypted (I presume), easy to reset

What are the best practices? Is there any built-in solution for Xamarin?

1

There are 1 answers

7
IdoT On BEST ANSWER

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.