In this lesson, you will learn how to use ProtectedBrowserStorage in Blazor to securely cache application data across browser sessions.
When building Blazor Server applications, you often need to persist user settings or temporary data without sending it back to your database on every click. While standard localStorage is accessible via JavaScript, it is plain text and vulnerable to tampering. ProtectedBrowserStorage provides a secure alternative by encrypting the data before storing it in the browser, ensuring it remains tamper-proof.
Injecting and Using Protected Storage
To use this feature, you must first register the required services in your Program.cs file (usually done by default in modern templates). Once configured, you can inject ProtectedLocalStorage or ProtectedSessionStorage directly into your Razor components.
The difference is simple: ProtectedLocalStorage persists even after the browser is closed, while ProtectedSessionStorage is cleared when the tab is closed.
Here is a quick example of how to save and retrieve a user’s preference:
@inject ProtectedLocalStorage ProtectedLocalStore
<button @onclick="SaveTheme">Save Dark Mode</button>
@code {
private async Task SaveTheme()
{
await ProtectedLocalStore.SetAsync("userTheme", "dark");
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
var result = await ProtectedLocalStore.GetAsync<string>("userTheme");
if (result.Success)
{
// Apply the theme logic here
}
}
}
}
Important Considerations
Because Blazor Server needs to interact with the browser's storage, these calls are asynchronous. You must always wait for the component to render before attempting to read from storage, as the "JavaScript bridge" is not available during the initial server-side prerendering phase. By wrapping your retrieval logic in OnAfterRenderAsync and checking the firstRender flag, you ensure that you don't trigger errors when the page first loads.
Key Takeaway: Use ProtectedBrowserStorage to keep user data secure by automatically encrypting it, and always perform read operations after the component has rendered to ensure the storage bridge is ready.