Nefarius.Legacy.DataProtector 1.3.0

Prefix Reserved
dotnet add package Nefarius.Legacy.DataProtector --version 1.3.0
                    
NuGet\Install-Package Nefarius.Legacy.DataProtector -Version 1.3.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Nefarius.Legacy.DataProtector" Version="1.3.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Nefarius.Legacy.DataProtector" Version="1.3.0" />
                    
Directory.Packages.props
<PackageReference Include="Nefarius.Legacy.DataProtector" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Nefarius.Legacy.DataProtector --version 1.3.0
                    
#r "nuget: Nefarius.Legacy.DataProtector, 1.3.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Nefarius.Legacy.DataProtector@1.3.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Nefarius.Legacy.DataProtector&version=1.3.0
                    
Install as a Cake Addin
#tool nuget:?package=Nefarius.Legacy.DataProtector&version=1.3.0
                    
Install as a Cake Tool

Nefarius.Legacy.DataProtector

.NET Nuget Nuget

ASP.NET Data Protection key store using EF (Legacy and Core).

Motivation

Recently I was tasked with the challenge of starting migrating an ASP.NET 4 MVC monolith over to the sacred .NET core universe. Since no direct upgrade paths exist, a common strategy is to gradually migrate over app logic to a new backend-frontend-combination while keeping the old app on life support and incorporated with the new software stack. A major pain-point is modernizing authentication and giving users an acceptable SSO experience. One such strategy is shared auth cookies between the ASP.NET Classic and Core apps.

Session cookies are encrypted by default, so both app environments need to have means to decrypt the session details. ASP.NET Core Data Protection is used to offload encryption and decryption, and the key material can be shared by a common filesystem directory or other means.

Since I already had to deal with EF (Core) and an MS SQL Server, I chose to backport an EF-based SQL Server backed key repository consumable both in ASP.NET Classic and Core from a single class library.

Usage

The main advantage is getting SSO via shared cookies to work while not relying on a shared directory, but SQL database instead. The example below assumes you have an ASP.NET Core backend playing reverse proxy to a legacy ASP.NET 4.x app and share the user session via cookie that gets decrypted via the DB-backed keys.

The table name DataProtectionKeys is hard-coded and needs to be created in the target database. See SQL_CreateTable.sql for details.

ASP.NET Core (.NET 8)

builder.Services.AddDbContext<DataProtectionDbContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("DataProtection")));

builder.Services.AddDataProtection()
    .PersistKeysToSqlServer(builder.Configuration.GetConnectionString("DataProtection")!)    
    .SetApplicationName("iis-app-name");

// example to use SSO via shared cookie with ASP.NET 4 
builder.Services.AddAuthentication(options =>
    {
        options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    })
    // Shared cookie authentication
    .AddCookie(options =>
    {
        options.Cookie.Name = ".AspNet.SharedCookie";
        options.Cookie.SameSite = SameSiteMode.Lax;
        options.Cookie.Path = "/";
        options.Cookie.HttpOnly = true;
        options.Cookie.IsEssential = true;
        options.ExpireTimeSpan = TimeSpan.FromMinutes(120);
    })

ASP.NET 4 (.NET Framework)

If your web app doesn't yet use OWIN you need to add it first (video guide) for this example to work!

// assumes OwinStartup is used

string connectionString = ConfigurationManager.ConnectionStrings["DataProtection"].ConnectionString;

app.UseCookieAuthentication(new CookieAuthenticationOptions
{
    AuthenticationType = CookieAuthenticationDefaults.AuthenticationType,
    CookieName = ".AspNet.SharedCookie",
    CookieSameSite = SameSiteMode.Lax,
    SlidingExpiration = true,
    ExpireTimeSpan = TimeSpan.FromMinutes(120),
    TicketDataFormat = new AspNetTicketDataFormat(
        new DataProtectorShim(
            SqlDataProtectionProvider.Create(connectionString, "iis-app-name")
                .CreateProtector(
                    "Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware",
                    "Cookies",
                    "v2"))),
    CookieManager = new ChunkingCookieManager()
});

The values .AspNet.SharedCookie and iis-app-name used here need to match across web projects that share the same cookie(s)!

Documentation

Link to API docs.

Sources & 3rd party credits

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Framework net472 is compatible.  net48 was computed.  net481 was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.3.0 105 6/28/2025
1.3.0-pre005 96 6/28/2025
1.3.0-pre004 100 6/28/2025
1.3.0-pre003 93 6/28/2025
1.3.0-pre002 98 6/28/2025
1.3.0-pre001 97 6/28/2025
1.1.3 148 5/21/2025
1.1.2 176 2/17/2025
1.1.1 112 2/17/2025
1.1.0 111 2/17/2025
1.0.0 126 2/16/2025
1.0.0-pre005 97 2/16/2025
1.0.0-pre004 96 2/16/2025
1.0.0-pre003 107 2/16/2025
1.0.0-pre002 97 2/16/2025
1.0.0-pre001 103 2/16/2025