Umbraco CMS
CloudHeartcoreDXPMarketplace
10.latest (LTS)
10.latest (LTS)
  • Umbraco CMS Documentation
  • Legacy Documentation
    • Umbraco 11 Documentation
    • Umbraco 8 Documentation
    • Umbraco 7 Documentation
  • Release Notes
  • Contribute
  • Sustainability Best Practices
  • Fundamentals
    • Get to know Umbraco
    • Setup
      • Requirements
      • Installation
        • Install using .NET CLI
        • Install using Visual Studio
        • Local IIS With Umbraco
        • Install Umbraco With Visual Studio Code
        • Installing Nightly Builds
        • Running Umbraco On Linux/macOS
        • Unattended Installs
      • Upgrade your project
        • Version Specific Upgrades
          • Upgrade from Umbraco 8 to Umbraco 10
          • Migrate content to Umbraco 8
          • Minor upgrades for Umbraco 8
          • Upgrade to Umbraco 7
          • Minor upgrades for Umbraco 7
      • Server setup
        • Running Umbraco On Azure Web Apps
        • Hosting Umbraco in IIS
        • File And Folder Permissions
        • Runtime Modes
        • Running Umbraco in Docker
        • Umbraco in Load Balanced Environments
          • Load Balancing Azure Web Apps
          • Standalone File System
          • Advanced Techniques With Flexible Load Balancing
          • Logging With Load Balancing
    • Backoffice
      • Sections
      • Property Editors
        • Built-in Property Editors
          • Checkbox List
          • Color Picker
          • Content Picker
          • DateTime
          • Date
          • Decimal
          • Email Address
          • Eye Dropper Color Picker
          • File Upload
          • Image Cropper
          • Label
          • List View
          • Markdown Editor
          • Media Picker
          • Media Picker (Legacy)
          • Member Group Picker
          • Member Picker
          • Multi Url Picker
          • Multinode Treepicker
          • Repeatable Textstrings
          • Nested Content (Legacy)
          • Numeric
          • Radiobutton List
          • Slider
          • Tags
          • Textarea
          • Textbox
          • Toggle
          • User Picker
          • Block Editors
            • Block Grid
            • Block List
            • Build a Custom View for a Block
            • Configuring Block Editor Label Properties
          • Dropdown
          • Grid Layout (Legacy)
            • What Are Grid Layouts?
            • Configuring The Grid Layout
            • Settings And Styling
            • Grid Editors
            • Build Your Own Editor
            • Rendering Grid In a Template
            • Grid Layout Best Practices
            • Add Values Programmatically
          • Rich Text Editor
            • Rich Text Editor Configuration
            • Rich Text Editor Styles
      • Login
      • Content Templates
      • Infinite Editing
      • Log Viewer
      • Language Variants
      • Settings Dashboards
    • Data
      • Defining Content
        • Default Document Types
      • Creating Media
        • Default Data/Media Types
      • Members
      • Data Types
        • Default Data Types
      • Scheduled Publishing
      • Using Tabs
      • Users
      • Relations
      • Dictionary Items
      • Content Version Cleanup
    • Design
      • Templates
        • Basic Razor Syntax
        • Named Sections
        • Razor Cheatsheet
      • Rendering Content
      • Rendering Media
      • Partial Views
      • Partial View Macro Files
      • Stylesheets And JavaScript
    • Code
      • Service APIs
      • Subscribing To Notifications
      • Creating Forms
      • Debugging
        • Logging
      • Source Control
  • Implementation
    • Learn how Umbraco works
    • Routing
      • Controller & Action Selection
      • Execute Request
      • Request Pipeline
    • Custom Routing
      • Adding a hub with SignalR and Umbraco
    • Controllers
    • Data Persistence (CRUD)
    • Composing
    • Integration Testing
    • Nullable Reference Types
    • Services and Helpers
      • Circular Dependencies
    • Unit Testing
  • Extending
    • Customize the editing experience
    • Dashboards
    • Sections & Trees
      • Sections
      • Trees
        • Tree Actions
      • Searchable Trees (ISearchableTree)
    • Property Editors
      • Package Manifest
      • Property Value Converters
      • Property Actions
      • Tracking References
      • Declaring your property editor
      • Content Picker Value Converter Example
    • Macro Parameter Editors
    • Health Check
      • Health Check Guides
        • Click-Jacking Protection
        • Content/MIME Sniffing Protection
        • Cross-site scripting Protection (X-XSS-Protection header)
        • Debug Compilation Mode
        • Excessive Headers
        • Fixed Application Url
        • Folder & File Permissions
        • HTTPS Configuration
        • Macro Errors
        • Notification Email Settings
        • SMTP
        • Strict-Transport-Security Header
    • Language Files & Localization
    • Backoffice Search
    • Backoffice Tours
    • Backoffice UI API Documentation
    • Content Apps
    • Creating a Custom Database Table
    • Embedded Media Providers
    • Custom File Systems (IFileSystem)
      • Using Azure Blob Storage for Media and ImageSharp Cache
    • Configuring Azure Key Vault
    • Packages
      • Package Types
      • Creating a Package
      • Language file for packages
      • Listing a Package on the Umbraco Marketplace
      • Good practice and defaults
      • Packages on Umbraco Cloud
      • Installing and Uninstalling Packages
      • Maintaining packages
      • Create accessible Umbraco packages
      • Example Package Repository
    • UI Library
  • Reference
    • Dive into the code
    • Configuration
      • Basic Authentication Settings
      • Connection strings settings
      • Content Dashboard Settings
      • Content Settings
      • Data Types Settings
      • Debug settings
      • Examine settings
      • Exception filter settings
      • FileSystemProviders Configuration
      • Global Settings
      • Health checks
      • Hosting settings
      • Imaging settings
      • Indexing settings
      • Install Default Data Settings
      • Keep alive settings
      • Logging settings
      • Maximum Upload Size Settings
      • Models builder settings
      • NuCache Settings
      • Package Migration
      • Plugins settings
      • Request handler settings
      • Rich text editor settings
      • Runtime minification settings
      • Runtime settings
      • Security Settings
      • Serilog settings
      • Tours settings
      • Type finder settings
      • Unattended
      • Web routing
    • Templating
      • Macros
        • Managing macros
        • Partial View Macros
      • Models Builder
        • Introduction
        • Configuration
        • Builder Modes
        • Understand and Extend
        • Using Interfaces
        • Tips and Tricks
      • Working with MVC
        • Working with MVC Views in Umbraco
        • View/Razor Examples
        • Using MVC Partial Views in Umbraco
        • Using View Components in Umbraco
        • Querying & Traversal
        • Creating Forms
    • Querying & Models
      • IMemberManager
      • IPublishedContentQuery
      • ITagQuery
      • UDI Identifiers
      • UmbracoContext helper
      • UmbracoHelper
      • IPublishedContent
        • IPublishedContent Collections
        • IPublishedContent IsHelpers
        • IPublishedContent Property Access & Extension Methods
    • Routing & Controllers
      • Routing requirements for backoffice authentication
      • Custom MVC controllers (Umbraco Route Hijacking)
      • Custom MVC Routes
      • URL Rewrites in Umbraco
      • Special Property Type aliases for routing
      • URL Redirect Management
      • Routing in Umbraco
        • FindPublishedContentAndTemplate()
        • IContentFinder
        • Inbound request pipeline
        • Outbound request pipeline
        • Published Content Request Preparation
      • Surface controllers
        • Surface controller actions
      • Umbraco API Controllers
        • Umbraco Api - Authorization
        • Umbraco Api - Routing & Urls
    • Searching
      • Examine
        • Examine Management
        • Examine Manager
        • Custom indexing
        • PDF indexes and multisearchers
        • quick-start
    • Using Notifications
      • Notification Handler
      • CacheRefresher Notifications Example
      • ContentService Notifications Example
      • Creating And Publishing Notifications
      • Determining if an entity is new
      • MediaService Notifications Example
      • MemberService Notifications Example
      • Sending Allowed Children Notification
      • Umbraco Application Lifetime Notifications
      • EditorModel Notifications
        • Customizing the "Links" box
    • Inversion of Control / Dependency injection
    • Management
      • Models Reference
        • Content
        • ContentType
        • DataType
        • DictionaryItem
        • Language
        • Media
        • MediaType
        • Relation
        • RelationType
        • ServerRegistration
        • Template
      • Services Reference
        • AuditService
        • ConsentService
        • DataTypeService
        • DomainService
        • EntityService
        • ExternalLoginService
        • FileService
        • MacroService
        • MediaService
        • MemberGroupService
        • MemberService
        • MemberTypeService
        • NotificationService
        • PackagingService
        • PublicAccessService
        • RedirectUrlService
        • RelationService
        • ServerRegistrationService
        • TagService
        • TextService
        • ContentService
          • Create content programmatically
        • ContentTypeService
          • Retrieving content types
          • Retrieving content types
        • LocalizationService
          • Retrieving languages
        • UserService
          • Creating a user
    • Plugins
      • Creating Resolvers
      • Finding types
    • Cache & Distributed Cache
      • Accessing the cache
      • ICacheRefresher
      • IServerMessenger
      • Getting/Adding/Updating/Inserting Into Cache
      • Examples
        • Working with caching
    • Response Caching
    • Security
      • Linking External Login Provider accounts
      • BackOfficeUserManager and Events
      • Cookies
      • Replacing the basic username/password check
      • External login providers
      • Locking of Users and password reset
      • Reset admin password
      • Umbraco Security Hardening
      • Umbraco Security Settings
      • Sensitive data
      • Sanitizing the Rich Text Editor
      • Setup Umbraco for a FIPS Compliant Server
      • HTTPS
      • Two-factor Authentication
      • Server-side file validation
    • Scheduling
    • Common Pitfalls & Anti-Patterns
    • API Documentation
    • Debugging with SourceLink
    • Language Variation
    • UmbracoMapper
    • Distributed Locks
    • AngularJS
      • Directives
        • umbLayoutSelector
        • umbLoadIndicator
        • umbProperty
      • Services
        • Editor Service
        • Events Service
          • changeTitle
  • Tutorials
    • Overview
    • Creating a Basic Website
      • Getting Started
      • Document Types
      • Creating Your First Template
      • CSS and Images
      • Displaying the Document Type Properties
      • Creating a Master Template
      • Creating Pages and Using the Master Template
      • Setting the Navigation Menu
      • Articles and Article Items
      • Adding Language Variants
      • Conclusions
    • Creating a Custom Dashboard
    • Creating a Property Editor
      • Adding configuration to a property editor
      • Integrating services with a property editor
      • Adding server-side data to a property editor
    • Creating a Multilingual Site
    • Add Google Authentication
    • Add Microsoft Entra ID authentication (Members)
    • The Starter Kit
      • Lessons
        • Customize the Starter Kit
        • Add a Blog Post Publication Date
          • Add a Blog Post Publication Date
          • Add a Blog Post Publication Date
        • Add Open Graph
          • Add Open Graph - Step 1
          • Add Open Graph - Step 2
          • Add Open Graph - Step 3
          • Add Open Graph - Step 4
          • Add Open Graph - Summary
        • Ask For Help and Join the Community
    • Editor's Manual
      • Getting Started
        • Logging In and Out
        • Umbraco Interface
        • Creating, Saving and Publishing Content Options
        • Finding Content
        • Editing Existing Content
        • Sorting Pages
        • Moving a Page
        • Copying a Page
        • Deleting and Restoring Pages
      • Working with Rich Text Editor
      • Version Management
        • Comparing Versions
        • Rollback to a Previous Version
      • Media Management
        • Working with Folders
        • Working with Media Types
        • Cropping Images
      • Tips & Tricks
        • Refreshing the Tree View
        • Audit Trail
        • Notifications
        • Preview Pane Responsive View
        • Session Timeout
    • Multisite Setup
    • Member Registration and Login
    • Custom Views for Block List
    • Connecting Umbraco Forms and Zapier
    • Creating an XML Sitemap
    • Implementing Custom Error Pages
Powered by GitBook
On this page
  • Configure External Login provider
  • Example for users
  • Example for members
  • Local logins
  • Transfering Claims from External identities
  • Example
  • Storing external login provider data
Edit on GitHub
Export as PDF
  1. Reference
  2. Security

Linking External Login Provider accounts

PreviousSecurityNextBackOfficeUserManager and Events

Last updated 1 year ago

Traditionally when using , a backoffice user or website member will need to exist first and then that user can link their user account to an external login provider in the backoffice or edit profile page.

In many cases, however, the external login provider you install will be the source of truth for all of your users.

In this case, you will want to provide a Single Sign On (SSO) approach to logging in. This would enable the creating of user accounts on the external login provider and then automatically give them access to Umbraco. This is called auto-Linking.

Configure External Login provider

To enable auto linking you have to implement a custom named configuration of BackOfficeExternalLoginProviderOptions or MemberExternalLoginProviderOptions for users or members, respectively.

Example for users

This example shows connection to an Open ID Connect Service such as or

You can first create a OpenIdConnectBackOfficeExternalLoginProviderOptions.cs file which configures the options like

using Microsoft.Extensions.Options;
using Umbraco.Cms.Core;
using Umbraco.Cms.Web.BackOffice.Security;

namespace Umbraco9
{
    public class OpenIdConnectBackOfficeExternalLoginProviderOptions : IConfigureNamedOptions<BackOfficeExternalLoginProviderOptions>
    {
        public const string SchemeName = "OpenIdConnect";
        public void Configure(string name, BackOfficeExternalLoginProviderOptions options)
        {
            if (name != "Umbraco." + SchemeName)
            {
                return;
            }

            Configure(options);
        }

        public void Configure(BackOfficeExternalLoginProviderOptions options)
        {
            options.ButtonStyle = "btn-danger";
            options.Icon = "fa fa-cloud";
            options.AutoLinkOptions = new ExternalSignInAutoLinkOptions(
                // must be true for auto-linking to be enabled
                autoLinkExternalAccount: true,

                // Optionally specify default user group, else
                // assign in the OnAutoLinking callback
                // (default is editor)
                defaultUserGroups: new[] { Constants.Security.EditorGroupAlias },

                // Optionally specify the default culture to create
                // the user as. If null it will use the default
                // culture defined in the web.config, or it can
                // be dynamically assigned in the OnAutoLinking
                // callback.

                defaultCulture: null,
                // Optionally you can disable the ability to link/unlink
                // manually from within the back office. Set this to false
                // if you don't want the user to unlink from this external
                // provider.
                allowManualLinking: false
            )
            {
                // Optional callback
                OnAutoLinking = (autoLinkUser, loginInfo) =>
                {
                    // You can customize the user before it's linked.
                    // i.e. Modify the user's groups based on the Claims returned
                    // in the externalLogin info
                },
                OnExternalLogin = (user, loginInfo) =>
                {
                    // You can customize the user before it's saved whenever they have
                    // logged in with the external provider.
                    // i.e. Sync the user's name based on the Claims returned
                    // in the externalLogin info

                    return true; //returns a boolean indicating if sign in should continue or not.
                }
            };

            // Optionally you can disable the ability for users
            // to login with a username/password. If this is set
            // to true, it will disable username/password login
            // even if there are other external login providers installed.
            options.DenyLocalLogin = false;

            // Optionally choose to automatically redirect to the
            // external login provider so the user doesn't have
            // to click the login button. This is
            options.AutoRedirectLoginToExternalProvider = false;
        }
    }
}

Additionally, there are more advanced properties for BackOfficeExternalLoginProviderOptions:

  • BackOfficeExternalLoginProviderOptions.CustomBackOfficeView

    • Allows for specifying a custom angular HTML view that will render in place of the default external login button. The purpose of this is in case you want to completely change the UI but also in these circumstances:

      • You want to display something different where external login providers are listed: in the login screen vs the backoffice panel vs on the logged-out screen. This same view will render in all of these cases but you can use the current route parameters to customize what is shown.

      • You want to change how the button interacts with the external login provider. For example, instead of having the site redirect on button-click, you want to open a popup window to load the external login provider.

    • The path is a virtual path, for example: "~/App_Plugins/MyPlugin/BackOffice/my-external-login.html"

    • When specifying this view it is 100% up to your angular view and affiliated angular controller to perform all required logic.

To register this configuration class, you can call the following from your startup.cs:

services.ConfigureOptions<OpenIdConnectBackOfficeExternalLoginProviderOptions>();

We recommend to create an extension method on the IUmbracoBuilder, to add the Open Id Connect Authentication, like this This extension can also handle the configuration of OpenIdConnectBackOfficeExternalLoginProviderOptions:

public static IUmbracoBuilder AddOpenIdConnectAuthentication(this IUmbracoBuilder builder)
{
    // Register OpenIdConnectBackOfficeExternalLoginProviderOptions here rather than require it in startup
    builder.Services.ConfigureOptions<OpenIdConnectBackOfficeExternalLoginProviderOptions>();

    builder.AddBackOfficeExternalLogins(logins =>
    {
        logins.AddBackOfficeLogin(
            backOfficeAuthenticationBuilder =>
            {
                backOfficeAuthenticationBuilder.AddOpenIdConnect(
                    // The scheme must be set with this method to work for the back office
                    backOfficeAuthenticationBuilder.SchemeForBackOffice(OpenIdConnectBackOfficeExternalLoginProviderOptions.SchemeName),
                    options =>
                    {
                        // use cookies
                        options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                        // pass configured options along
                        options.Authority = "https://localhost:5000";
                        options.ClientId = "YOURCLIENTID";
                        options.ClientSecret = "YOURCLIENTSECRET";
                        // Use the authorization code flow
                        options.ResponseType = OpenIdConnectResponseType.Code;
                        options.AuthenticationMethod = OpenIdConnectRedirectBehavior.RedirectGet;
                        // map claims
                        options.TokenValidationParameters.NameClaimType = "name";
                        options.TokenValidationParameters.RoleClaimType = "role";


                        options.RequireHttpsMetadata = true;
                        options.GetClaimsFromUserInfoEndpoint = true;
                        options.SaveTokens = true;
                        // add scopes
                        options.Scope.Add("openid");
                        options.Scope.Add("email");
                        options.Scope.Add("roles");
                        options.UsePkce = true;
                    });
            });
    });
    return builder;
}

Finally this extension can also be called from the Startup.cs like the example below:

services.AddUmbraco(_env, _config)
   .AddBackOffice()
   .AddWebsite()
   .AddComposers()
   .AddOpenIdConnectAuthentication()
   .Build();

For some providers, it doesn't make sense to use auto-linking. This is especially true for public providers such as Google or Facebook. In those cases, it would mean that anyone who has a Google or Facebook account can log into your site. For public providers such as this, if auto-linking was needed you would need to limit the access by domain or other information provided in the Claims using the options/callbacks specified in those provider's authentication options.

Example for members

The way to implement auto linking for members is fairly similar to how it is for users. The main difference is the UI, where Umbraco do not have a fixed login page for members. Instead, Umbraco ships with some Partial Macro Snippets for Login and EditProfile that contains handling of Login and manual linking of the configured external member providers.

When auto-linking is enabled, only the Login snippet is relevant as users do not have to register before.

The following example will show how to use Google and external login provider. You can first create a GoogleMemberExternalLoginProviderOptions.cs file which configures the options like

using System;
using Microsoft.Extensions.Options;
using Umbraco.Cms.Core;
using Umbraco.Cms.Web.BackOffice.Security;

namespace Umbraco9
{
    public class GoogleMemberExternalLoginProviderOptions : IConfigureNamedOptions<MemberExternalLoginProviderOptions>
    {
        public const string SchemeName = "Google";

        public void Configure(string name, MemberExternalLoginProviderOptions options)
        {
            if (name != Constants.Security.MemberExternalAuthenticationTypePrefix + SchemeName)
            {
                return;
            }

            Configure(options);
        }

        public void Configure(MemberExternalLoginProviderOptions options) =>
            options.AutoLinkOptions = new MemberExternalSignInAutoLinkOptions(
                // Must be true for auto-linking to be enabled
                autoLinkExternalAccount: true,

                // Optionally specify the default culture to create
                // the user as. If null it will use the default
                // culture defined in the web.config, or it can
                // be dynamically assigned in the OnAutoLinking
                // callback.
                defaultCulture: null,

                // Optionally specify the default "IsApprove" status. Must be true for auto-linking.
                defaultIsApproved:true,

                // Optionally specify the member type alias. Default is "Member"
                defaultMemberTypeAlias:"Member",

                // Optionally specify the member groups names to add the auto-linking user to.
                defaultMemberGroups: Array.Empty<string>()
            )
            {
                // Optional callback
                OnAutoLinking = (autoLinkUser, loginInfo) =>
                {
                    // You can customize the member before it's linked.
                    // i.e. Modify the member's groups based on the Claims returned
                    // in the externalLogin info
                },
                OnExternalLogin = (user, loginInfo) =>
                {
                    // You can customize the member before it's saved whenever they have
                    // logged in with the external provider.
                    // i.e. Sync the member's name based on the Claims returned
                    // in the externalLogin info

                    return true; //returns a boolean indicating if sign in should continue or not.
                }
            };
    }
}

To register this configuration class, you can call the following from your startup.cs:

services.ConfigureOptions<GoogleMemberExternalLoginProviderOptions>();

Like for users, we recommend creating an extension method on the IUmbracoBuilder, to add the Google Authentication, like this. This extension can also handle the configuration of GoogleMemberExternalLoginProviderOptions:

public static IUmbracoBuilder AddMemberGoogleAuthentication(this IUmbracoBuilder builder)
{
    // Register GoogleMemberExternalLoginProviderOptions here rather than require it in startup
    builder.Services.ConfigureOptions<GoogleMemberExternalLoginProviderOptions>();

    builder.AddMemberExternalLogins(logins =>
    {
        logins.AddMemberLogin(
            memberAuthenticationBuilder =>
            {
                memberAuthenticationBuilder.AddGoogle(
                    // The scheme must be set with this method to work for the Umbraco members
                    memberAuthenticationBuilder.SchemeForMembers(GoogleMemberExternalLoginProviderOptions.SchemeName),
                    options =>
                    {
                        options.ClientId = "YOURCLIENTID";
                        options.ClientSecret = "YOURCLIENTSECRET";
                    });
            });
    });
    return builder;
}

Finally this extension can also be called from the Startup.cs like the example below:

services.AddUmbraco(_env, _config)
   .AddBackOffice()
   .AddWebsite()
   .AddComposers()
   .AddMemberGoogleAuthentication()
   .Build();

Auto-linking only makes sense if you have a public member registration anyway or the external provider does not have public account creation.

Local logins

If you have configured auto-linking, then any auto-linked user or member will have an empty password assigned and they will not be able to log in locally (via username and password). In order to log in locally, they will have to assign a password to their account in the backoffice or the edit profile page.

For users only, if the DenyLocalLogin option is enabled, then all password changing functionality in the backoffice is also disabled and local login is not possible.

Transfering Claims from External identities

In some cases you may want to flow a Claim returned in your external login provider to the Umbraco backoffice identity's Claims (the authentication cookie). This can be done during the OnAutoLinking and OnExternalLogin.

Reason for this could be to store the external login provider user ID into the backoffice identity cookie. That way it can be retrieved on each request in order to look up some data in another system that needs the current user id from the external login provider.

Example

This is a very simplistic example for brevity, no null checks, etc...

OnAutoLinking = (user, loginInfo) => {
    // You can customize the user before it's linked.
    // i.e. Modify the user's groups based on the Claims returned
    // in the externalLogin info
    var extClaim = externalLogin
        .Principal
        .FindFirst("MyClaim");
    user.Claims.Add(new IdentityUserClaim<string>
    {
        ClaimType = extClaim.Type,
        ClaimValue = extClaim.Value,
        UserId = user.Id
    });
},
OnExternalLogin = (user, loginInfo) => {
    // You can customize the user before it's saved whenever they have
    // logged in with the external provider.
    // i.e. Sync the user's name based on the Claims returned
    // in the externalLogin info
    var extClaim = externalLogin
        .Principal
        .FindFirst("MyClaim");
    user.Claims.Add(new IdentityUserClaim<string>
    {
        ClaimType = extClaim.Type,
        ClaimValue = extClaim.Value,
        UserId = user.Id
    });
    return true;
}

Storing external login provider data

In some cases, you may need to persist data from your external login provider like Access Tokens, etc. You can persist this data to the affiliated user's external login data via the IExternalLoginWithKeyService. The void Save(Guid userOrMemberKey,IEnumerable<IExternalLoginToken> tokens) overload takes a new model of type IEnumerable<IExternalLogin>. IExternalLogin contains a property called UserData. This is a blob text column so can store any arbitrary data for the external login provider.

Be aware that the local Umbraco user must already exist and be linked to the external login provider before data can be stored here. In cases where auto-linking occurs and the backoffice user isn't yet created, you will most likely need to store this data in memory. First, during auto-linking and then persist this data to the service once the user is linked and created.

Do not flow large amounts of data into the backoffice identity because this information is stored into the backoffice authentication cookie and cookie limits will apply. Data like JWT tokens need to be somewhere to be looked up and not stored within the backoffice identity itself.

External login providers (OAuth)
IdentityServer4
OpenIDDict
persisted