Storing Secrets Safely in Xamarin.Forms with Xamarin.Essentials SecureStorage
Learn how to use Xamarin.Essentials SecureStorage for cross‑platform secure key‑value storage, see a concrete code example, and understand its limits and verification steps.
09 Jul 2025, 16:48 UTC

Problem: Where to keep a user token or API key safely
When a Xamarin.Forms app needs to persist a secret such as an authentication token, writing it to plain Preferences or a local file leaves the data exposed if the device is compromised. Developers need a storage mechanism that leverages the operating system’s built‑in secure containers, works the same way on iOS, Android and UWP, and fails loudly when something goes wrong.
How Xamarin.Essentials SecureStorage solves it
Xamarin.Essentials SecureStorage (available from version 1.6.0) provides a simple key‑value API that stores each value in the platform‑specific secure container:
- iOS → Keychain
- Android → Keystore (backed by the device lock‑screen credentials)
- UWP → DataProtectionAPI
The API is synchronous (Set, Get, Remove) and throws an exception on any failure, making error handling straightforward in shared code. Values are encrypted at rest and are automatically removed when the app is uninstalled, giving a higher security baseline than plain preferences.
Worked example: Storing and retrieving an auth token
Assume you have a Xamarin.Forms project targeting iOS, Android and UWP. Add the NuGet package Xamarin.Essentials version 1.6.0 or later to all projects.
In a shared service class you can wrap the SecureStorage calls:
using Xamarin.Essentials;
public static class TokenStore
{
private const string TokenKey = "user_auth_token";
public static void SaveToken(string token)
{
// SecureStorage.Set is synchronous; call from a background thread if UI responsiveness matters
SecureStorage.Set(TokenKey, token);
}
public static string LoadToken()
{
return SecureStorage.Get(TokenKey); // returns null if not found
}
public static void DeleteToken()
{
SecureStorage.Remove(TokenKey);
}
}
To use it from a ViewModel or code‑behind:
// After a successful login
TokenStore.SaveToken(response.AccessToken);
// Later, when making a secured request
var token = TokenStore.LoadToken();
if (token != null)
{
// attach token to HTTP header
}
else
{
// handle missing token (e.g., redirect to login)
}
Where to run: The calls can be made from any thread, but because they are synchronous they will block the caller. For UI‑thread safety, wrap them in Task.Run or use Device.BeginInvokeOnMainThread after the operation completes.
Required permissions: No special Android manifest permissions are needed for SecureStorage itself, but the underlying Keystore relies on the device having a lock screen (PIN, pattern, password or biometric). If none is set, Android falls back to a software‑based implementation that is less secure.
Trade‑offs and limitations
While SecureStorage raises the bar for data protection, there are a few practical constraints to keep in mind:
- Android lock‑screen dependency: If the device lacks a secure lock screen, the Keystore may revert to a less secure software backup. You can detect this scenario by checking
KeyguardManager.IsKeyguardSecure(requiresandroid.permission.DISABLE_KEYGUARDfor certain APIs) and prompting the user to enable a lock screen. - iOS Keychain binding to bundle identifier: Values stored in the Keychain are tied to the app’s
CFBundleIdentifier. Reinstalling the app with a different bundle ID will not retrieve the previous token, which is usually desirable but can be surprising during development when you change the identifier for testing. - Synchronous API: Because the methods block, heavy usage (e.g., storing many large blobs) could cause UI jitter. The library is intended for small secrets like tokens or keys, not for bulk data.
- No cross‑device sync: SecureStorage is local to the device; if you need the secret to roam with the user’s account, you must implement your own synchronization layer on top of a secure backend.
Verification: Practical steps to confirm it works
You can verify the behavior without needing to claim any test results:
- Android: On an emulator or physical device, enable a lock screen PIN. Run the app, call
TokenStore.SaveToken("test"), restart the app, and callLoadToken()– you should receive "test". Then clear the app data via Settings → Apps → YourApp → Storage → Clear Data; the token should be gone, confirming the tie to the app’s private storage. - iOS: On a physical device with Face ID or Touch ID enabled, store a token, uninstall the app, then reinstall using the same bundle identifier. After launch,
LoadToken()should still return the token, showing Keychain retention across reinstalls. - UWP: Run the app, store a token, close and relaunch; the token persists. Uninstalling the app removes the value.
If any of these steps fail, check the exception message from SecureStorage – it will indicate whether the underlying secure container is unavailable (common on Android without a lock screen).
Actionable closing
For most Xamarin.Forms applications that need to keep a user‑authentication token, a API key, or any other small secret, Xamarin.Essentials SecureStorage offers a straightforward, cross‑platform solution that leans on the OS’s native secure storage. Add the package, use the synchronous Set/Get/Remove methods, remember the Android lock‑screen caveat and iOS bundle‑ID binding, and verify the flow on a real device or emulator with the steps above. When those conditions are met, you can trust that the secret is stored more securely than in plain preferences.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.