Managing Legacy User Settings in SharePoint Framework: A Practical Guide
After SPFx 1.18, Entra ID app registration changes can silently break user preference storage in existing web parts. A practical comparison of profile properties, localStorage, and hidden list approaches with migration strategies.
Why Legacy User Settings Break in Modern SPFx
Starting with SharePoint Framework (SPFx) 1.18, Microsoft fundamentally changed how Entra ID app registrations work for custom solutions. If your SPFx web parts store user preferences through SharePoint User Profile properties, Graph API calls via AadHttpClient, or even localStorage keyed to manifest IDs, there is a real chance those settings stopped persisting after a recent upgrade — without throwing any visible errors.
This article walks through the storage mechanisms we encounter most often in enterprise SPFx deployments and the migration paths we have used in production.
Understanding the Storage Landscape
Before choosing a migration strategy, you need to map which storage mechanism each web part uses. In our experience, most enterprise SPFx solutions rely on a mix of these:
- Web Part Properties (PropertyPane): Stored in the page JSON. Not user-specific — any page editor can modify them. Typically used for display configuration (list source, item count, layout mode). These survive SPFx upgrades without issues since they live in the page content.
- localStorage / sessionStorage: Browser-side, device-bound. Good for lightweight preferences like collapsed sidebar state or theme selection. Survives SPFx upgrades unless the storage key includes the web part manifest ID, which changes if you create a new solution package.
- SharePoint User Profile Properties: Server-side, consistent across devices. Requires Graph API or legacy CSOM calls to read/write custom properties. This is the mechanism most affected by Entra ID changes because it depends on specific API permissions.
- SharePoint Hidden List: A custom list (often hidden from site navigation) with one row per user. Offers full control, audit trail through version history, and is independent of Entra ID app registration changes since it uses standard SharePoint REST API.
What Changed in the Entra ID App Model
Before SPFx 1.18, most custom solutions shared a single Entra ID application called SharePoint Online Client Extensibility. Tenant administrators would approve permission requests through the API Management page in SharePoint Admin Center, and all SPFx solutions in the tenant would share those permissions via AadHttpClient or MSGraphClient.
The new model pushes toward solution-specific app registrations. This is a better security posture (least-privilege principle) but creates several practical issues for existing solutions:
- Legacy
webApiPermissionRequestsinpackage-solution.jsonmay no longer be honoured if the shared app registration is deprecated or reconfigured. - API calls through
AadHttpClientreturn 401 or 403 errors when the token comes from an app registration that no longer holds the required scopes. - Solutions that write to User Profile properties often need
User.ReadWriteas a delegated permission, which may not be granted to the new per-solution app registration by default.
A Real Scenario: Silent Settings Loss
In a project we delivered for a manufacturing client, an SPFx web part stored the user's preferred language and notification frequency in custom SharePoint User Profile properties. After upgrading to SPFx 1.19, the web part continued to load without errors, but preferences were no longer being saved. The root cause: the User.ReadWrite.All permission on the shared app registration had been removed during a tenant security review, and the new solution-specific registration did not include it.
The web part's error handling swallowed the 403 response — a common pattern when developers use try/catch with a silent fallback. Users only noticed weeks later when their settings kept resetting.
Migration Strategies
1. Move from Profile Properties to Graph Open Extensions
Instead of SharePoint User Profile Service, use Microsoft Graph Open Extensions to store user-specific JSON data. Open Extensions are attached directly to the user object in Entra ID and accessible via a simple Graph call:
- Endpoint:
PATCH /me/extensions/{extensionId} - Required permission:
User.ReadWrite(delegated) - Payload: free-form JSON, up to 2KB per extension
For the actual migration, we typically build a one-time Power Automate flow: read the existing User Profile property for each user, write it to a Graph Open Extension, then clear the old property. This can run during a maintenance window with minimal disruption.
2. Stabilise localStorage Keys
If your web parts use localStorage, ensure the storage keys are not tied to the web part's manifest GUID or instance ID. When you redeploy a solution with a new package, the manifest ID can change, which orphans the old localStorage entries.
A safer pattern is to use a fixed namespace combined with the user's login name: fiboo-userprefs-{loginName}. This survives redeployment and is still scoped to the individual user on that device.
3. Hidden List Pattern
For complex user preferences — multi-filter states, dashboard layouts, favourite items — the most reliable approach is a hidden SharePoint list with one item per user. Advantages:
- Fully independent of Entra ID app registration changes. Uses standard SharePoint REST API with site-level permissions.
- Consistent across all devices and browsers.
- Built-in version history for audit compliance.
- Administrators can bulk-edit or reset user settings through PowerShell or PnP CLI.
The trade-off is an extra REST call on each page load. To mitigate this, cache the settings in sessionStorage and sync with the server at intervals (every 15 minutes works well in practice).
Audit Checklist for Existing Solutions
Before planning any migration, inventory your current SPFx solutions with this checklist:
- Review
webApiPermissionRequestsin every package-solution.json. Are the listed permissions still approved in the API Management page? - Search your codebase for AadHttpClient and MSGraphClient usage. Document which Graph scopes each call requires.
- Identify any calls to the User Profile REST endpoint (
/_api/SP.UserProfiles.PeopleManager) and note whether they read or write. - List all localStorage and sessionStorage keys your web parts create. Verify they do not depend on values that change during redeployment.
- Check whether each solution is deployed as tenant-scoped or site-scoped, as this affects the app registration and permission model.
Wrapping Up
The Entra ID changes in SPFx are a genuine risk for solutions that manage user settings, but it is a manageable risk if you catch it early. Our recommendation: map your current storage mechanisms first, define the target architecture for each one, and migrate incrementally. Updating web parts one at a time is less risky than a big-bang refactor and avoids disrupting the user experience across the board.