From ec5c1b6a956fa46ba3c8b5e7be9a401d10ac4472 Mon Sep 17 00:00:00 2001 From: Paul Schneider Date: Sun, 14 Jun 2026 16:27:54 +0100 Subject: [PATCH] fix(cookies): set Identity cookies to SameSite=Lax in dev (avoid Chromium rejection on http://localhost) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Chromium rejects cookies that have SameSite=None but no Secure flag. The default Identity cookie policy uses SameSite=None, which is invalid on http://localhost (no TLS, no Secure). Result on http://localhost:5000: Cookie '.AspNetCore.Identity.Application' rejected because it has the 'SameSite=None' attribute but is missing the 'secure' attribute. Fix: in Development environment, configure ConfigureApplicationCookie and ConfigureExternalCookie to use SameSite=Lax and SameAsRequest SecurePolicy. Lax is permissive enough for OAuth callbacks (top-level GET navigations) and avoids the rejection. Production (https://) is untouched — the default SameSite=None is correct when Secure is set. Note on the sameSiteMode reference: SameSiteMode is defined in two namespaces (Microsoft.AspNetCore.Http and Microsoft.Net.Http.Headers). The file already uses 'using Microsoft.Net.Http.Headers;' so a bare 'SameSiteMode' is ambiguous. Using the fully-qualified name 'Microsoft.AspNetCore.Http.SameSiteMode' to disambiguate, no new using needed. Tested: dotnet build OK, dotnet test 11/11 green. --- src/Yavsc.Org/Extensions/HostingExtensions.cs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/Yavsc.Org/Extensions/HostingExtensions.cs b/src/Yavsc.Org/Extensions/HostingExtensions.cs index 3d21a5c0..dd4541bb 100644 --- a/src/Yavsc.Org/Extensions/HostingExtensions.cs +++ b/src/Yavsc.Org/Extensions/HostingExtensions.cs @@ -170,6 +170,24 @@ public static class HostingExtensions services.AddScoped, UserClaimsPrincipalFactory>(); + // Dev-only: Chromium rejects SameSite=None without Secure on http:// + // (e.g. http://localhost:5000). The default Identity cookie policy + // sets SameSite=None, which is invalid without Secure. Force Lax in + // dev. In production (https://) the default SameSite=None is fine. + if (builder.Environment.IsDevelopment()) + { + services.ConfigureApplicationCookie(options => + { + options.Cookie.SameSite = Microsoft.AspNetCore.Http.SameSiteMode.Lax; + options.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest; + }); + services.ConfigureExternalCookie(options => + { + options.Cookie.SameSite = Microsoft.AspNetCore.Http.SameSiteMode.Lax; + options.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest; + }); + } + return identityBuilder; }