Migrating from AccountStore to Xamarin.Essentials SecureStorage - xamarin/Xamarin.Auth GitHub Wiki

Migrating from AccountStore to Xamarin.Essentials SecureStorage

AccountStore has been deprecated and we recommend using Xamarin.Essentials Secure Storage as a replacement.

It is best practice to never store actual OAuth tokens on device as all devices are considered inherently insecure. Instead you should only ever persist Refresh Tokens which can be used to fetch OAuth tokens which can be kept in memory as needed. It's always best practice to limit the expiration time of OAuth tokens.

Migration / Helper Class

We've made a simple class to help with the migration of both data and your code from using AccountStore to Xamarin.Essentials SecureStorage:

using Newtonsoft.Json;
using Xamarin.Auth;
using Xamarin.Essentials;

public class SecureStorageAccountStore
{
    public static async Task SaveAsync(Account account, string serviceId)
    {
        // Find existing accounts for the service
        var accounts = await FindAccountsForServiceAsync(serviceId);

        // Remove existing account with Id if exists
        accounts.RemoveAll(a => a.Username == account.Username);

        // Add account we are saving
        accounts.Add(account);

        // Serialize all the accounts to javascript
        var json = JsonConvert.SerializeObject(accounts);

        // Securely save the accounts for the given service
        await SecureStorage.SetAsync(serviceId, json);
    }

    public static async Task<List<Account>> FindAccountsForServiceAsync(string serviceId)
    {
        // Get the json for accounts for the service
        var json = await SecureStorage.GetAsync(serviceId);

        try {
            // Try to return deserialized list of accounts
            return JsonConvert.DeserializeObject<List<Account>>(json);
        } catch { }

        // If this fails, return an empty list
        return new List<Account>();
    }

    public static async Task MigrateAllAccountsAsync(string serviceId, IEnumerable<Account> accountStoreAccounts)
    {
        var wasMigrated = await SecureStorage.GetAsync($"XamarinAuthAccountStoreMigrated{serviceId}");

        if (wasMigrated == "1")
            return;

        await SecureStorage.SetAsync($"XamarinAuthAccountStoreMigrated{serviceId}", "1");

        // Just in case, look at existing 'new' accounts
        var accounts = await FindAccountsForServiceAsync(serviceId);

        foreach (var account in accountStoreAccounts) {

            // Check if the new storage already has this account
            // We don't want to overwrite it if it does
            if (accounts.Any(a => a.Username == account.Username))
                continue;   
            
            // Add the account we are migrating
            accounts.Add(account);
        }

        // Serialize all the accounts to javascript
        var json = JsonConvert.SerializeObject(accounts);

        // Securely save the accounts for the given service
        await SecureStorage.SetAsync(serviceId, json);
    }
}

To use the migration helper you should run this code to fetch existing AccountStore accounts and move them to Xamarin.Essentials:

var accountStoreAccounts = AccountStore.Create().FindAccountsForService("Facebook");

await SecureStorageAccountStore.MigrateAllAccountsAsync("Facebook", accountStoreAccounts);

Store the account

With AccountStore, you would have stored account information like this:

AccountStore.Create ().Save (account, "Facebook");

Now, instead, using the helper class you'd write:

await SecureStorageAccountStore.SaveAsync(account, "Facebook");

Retrieve stored accounts

With AccountStore, you would have retrieved accounts for a service like this:

var accounts = AccountStore.Create (this).FindAccountsForService ("Facebook");

Using the helper class you can now write:

var accounts = await SecureStorageAccountStore.FindAccountsForServiceAsync("Facebook");
⚠️ **GitHub.com Fallback** ⚠️