fix: Auth cookies invalidated on every deployment (Data Protection discriminator)

User reported: "배포가 되면 인증이 풀린다" (auth resets after every
deployment).

Root cause: Program.cs had no explicit Data Protection configuration.
Without SetApplicationName, ASP.NET Core derives the key-ring
discriminator from the app's physical content root path. Every
deployment lands in a brand-new directory
(~/deployments/quantengine_{tag}_{hash}/), so the discriminator
changed on every single release. The cookie authentication ticket is
encrypted/signed via this key ring, so once the discriminator
changed, every previously-issued auth cookie became undecryptable --
forcing all logged-in users to authenticate again after each deploy,
even well inside their 12-hour ExpireTimeSpan.

Fix: explicit .SetApplicationName("QuantEngine") pins a stable
discriminator across deployments, and .PersistKeysToFileSystem points
at %LOCALAPPDATA%/quantengine-keys (Linux: ~/.local/share/quantengine-keys
via User=kjh2064 in the systemd unit) -- a location outside the
versioned deployment directories, so the actual key material also
survives every redeploy and service restart instead of only the
discriminator being stable.
This commit is contained in:
2026-07-12 02:04:03 +09:00
parent 7283532c38
commit a274ef448a
+17
View File
@@ -1,3 +1,4 @@
using Microsoft.AspNetCore.DataProtection;
using QuantEngine.Infrastructure.Data;
using QuantEngine.Infrastructure.Repositories;
using QuantEngine.Infrastructure.Services;
@@ -22,6 +23,22 @@ try
var builder = WebApplication.CreateBuilder(args);
builder.Host.UseSerilog();
// Data Protection: without this, ASP.NET Core derives its key-ring
// discriminator from the app's physical content root path. Every
// deployment lands in a brand-new directory
// (~/deployments/quantengine_{tag}_{hash}/), so the discriminator
// changed on every single deploy and every previously-issued auth
// cookie became undecryptable -- forcing all users to log in again
// after each release. SetApplicationName pins a stable discriminator;
// PersistKeysToFileSystem points at a location outside the versioned
// deployment folders so the actual key material also survives restarts.
var dataProtectionKeysPath = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
"quantengine-keys");
builder.Services.AddDataProtection()
.SetApplicationName("QuantEngine")
.PersistKeysToFileSystem(new DirectoryInfo(dataProtectionKeysPath));
// Authentication & Authorization
builder.Services.AddAuthentication(opts =>
{