fix(auth): configurable SameSite cookie for cross-origin dev setup
Chrome 89+ schemeful same-site treats http://localhost and https://localhost as different sites, blocking SameSite=Strict cookies on cross-origin fetch (e.g. Vite on port 5173, API on port 7221). Fix: make CookieSameSite configurable per environment in JwtSettings. - Default: Strict (production) - appsettings.Development.json: None (allows cross-origin cookie in dev) - When SameSite=None, Secure is always forced (browser requirement) Revert the earlier Vite proxy approach in favour of this backend config. VITE_API_BASE_URL remains a freely configurable URL in .env.local. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -13,7 +13,8 @@
|
||||
"Issuer": "SlpModularCms",
|
||||
"Audience": "SlpModularCmsPortal",
|
||||
"ExpiryMinutes": 60,
|
||||
"RefreshTokenExpiryDays": 7
|
||||
"RefreshTokenExpiryDays": 7,
|
||||
"CookieSameSite": "None"
|
||||
},
|
||||
"Availability": {
|
||||
"CircuitBreakerSeconds": 30,
|
||||
|
||||
@@ -10,4 +10,10 @@ public class JwtSettings
|
||||
public string Audience { get; set; } = string.Empty;
|
||||
public int ExpiryMinutes { get; set; } = 60;
|
||||
public int RefreshTokenExpiryDays { get; set; } = 7;
|
||||
/// <summary>
|
||||
/// SameSite-modus voor de refreshToken cookie: Strict | Lax | None.
|
||||
/// Gebruik None in ontwikkelomgevingen waar frontend en backend
|
||||
/// op verschillende poorten draaien (vereist Secure=true).
|
||||
/// </summary>
|
||||
public string CookieSameSite { get; set; } = "Strict";
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.RateLimiting;
|
||||
using Microsoft.Extensions.Options;
|
||||
using SlpModularCms.Core.Identity.Models;
|
||||
using SlpModularCms.Core.Identity.Services;
|
||||
|
||||
@@ -12,10 +13,12 @@ namespace SlpModularCms.Modules.Identity.Controllers;
|
||||
public class AuthController : ControllerBase
|
||||
{
|
||||
private readonly IAuthService _authService;
|
||||
private readonly JwtSettings _jwtSettings;
|
||||
|
||||
public AuthController(IAuthService authService)
|
||||
public AuthController(IAuthService authService, IOptions<JwtSettings> jwtSettings)
|
||||
{
|
||||
_authService = authService;
|
||||
_jwtSettings = jwtSettings.Value;
|
||||
}
|
||||
|
||||
[HttpPost("login")]
|
||||
@@ -65,11 +68,15 @@ public class AuthController : ControllerBase
|
||||
|
||||
private CookieOptions GetCookieOptions()
|
||||
{
|
||||
var sameSite = Enum.TryParse<SameSiteMode>(_jwtSettings.CookieSameSite, ignoreCase: true, out var parsed)
|
||||
? parsed
|
||||
: SameSiteMode.Strict;
|
||||
|
||||
return new CookieOptions
|
||||
{
|
||||
HttpOnly = true,
|
||||
Secure = Request.IsHttps,
|
||||
SameSite = SameSiteMode.Strict,
|
||||
Secure = Request.IsHttps || sameSite == SameSiteMode.None,
|
||||
SameSite = sameSite,
|
||||
Path = "/api/v1/auth",
|
||||
Expires = DateTimeOffset.UtcNow.AddDays(7)
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user