While migrating from Nested Content to Block List in Umbraco 13, I ran into an unexpected issue with the umbracoExternalLogin table.
Everything in the migration went smoothly until I noticed that the table was empty in my local database copy.
When I copied the database locally and ran the migration, I didn’t configure any external login providers.
In my appsettings.json, this section was blank:
"AzureAd": {
"TenantId": "",
"ClientId": "",
"ClientSecret": ""
}
Because no providers were registered, Umbraco automatically removed all external login records.
This happens due to a cleanup process in ExternalLoginRepository and BackOfficeExternalLoginProviders.
Here’s the relevant part:
public void DeleteUserLoginsForRemovedProviders(IEnumerable<string> currentLoginProviders)
{
Sql<ISqlContext> sql = Sql()
.Select<ExternalLoginDto>(x => x.Id)
.From<ExternalLoginDto>()
.Where<ExternalLoginDto>(x => !x.LoginProvider.StartsWith(Constants.Security.MemberExternalAuthenticationTypePrefix))
.WhereNotIn<ExternalLoginDto>(x => x.LoginProvider, currentLoginProviders);
var toDelete = Database.Query<ExternalLoginDto>(sql).Select(x => x.Id).ToList();
DeleteExternalLogins(toDelete);
}
This is called from InvalidateSessionsIfExternalLoginProvidersChanged():
public void InvalidateSessionsIfExternalLoginProvidersChanged()
{
var previousExternalLoginProvidersValue = _keyValueService.GetValue(ExternalLoginProvidersKey);
var currentExternalLoginProvidersValue = string.Join("|", _externalLogins.Keys.OrderBy(key => key));
if ((previousExternalLoginProvidersValue ?? string.Empty) != currentExternalLoginProvidersValue)
{
_logger.LogWarning("The configured external login providers have changed. Existing backoffice sessions using the removed providers will be invalidated and external login data removed.");
_userService.InvalidateSessionsForRemovedProviders(_externalLogins.Keys);
_externalLoginWithKeyService.DeleteUserLoginsForRemovedProviders(_externalLogins.Keys);
_keyValueService.SetValue(ExternalLoginProvidersKey, currentExternalLoginProvidersValue);
}
}
So when Umbraco detects a change (or no provider at all), it assumes the old ones were removed and clears out related entries in umbracoExternalLogin.
If you’re doing a local migration or testing a copy of your production database, make sure to configure your external login credentials, even if they’re dummy values.
Example:
"AzureAd": {
"TenantId": "dummy-tenant-id",
"ClientId": "dummy-client-id",
"ClientSecret": "dummy-secret"
}
This prevents Umbraco from thinking the provider has been removed and keeps your umbracoExternalLogin records intact.
When working on upgrades or local migrations:
Always double-check your external login settings and other settings, and do not clear any tables you want to keep.
Keep a backup of the original database and compare it if any issues arise.
A small configuration detail, but one that can save you a lot of head-scratching.