Fix OAuth state validation error by improving authentication configuration

Co-authored-by: clayschaad <11883505+clayschaad@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot] 2025-08-27 17:57:54 +00:00
parent aa56f84f34
commit 53819b1731
2 changed files with 27 additions and 28 deletions

View file

@ -23,35 +23,10 @@ namespace ShiftScheduler.Server.Controllers
{ {
return Challenge(new AuthenticationProperties return Challenge(new AuthenticationProperties
{ {
RedirectUri = "/api/auth/callback" RedirectUri = "/"
}, GoogleDefaults.AuthenticationScheme); }, GoogleDefaults.AuthenticationScheme);
} }
[HttpGet("callback")]
public async Task<IActionResult> Callback()
{
// Explicitly specify the Google authentication scheme for the callback
var result = await HttpContext.AuthenticateAsync(GoogleDefaults.AuthenticationScheme);
if (!result.Succeeded || result.Principal == null)
{
return Redirect("/?error=auth_failed");
}
var emailClaim = result.Principal.FindFirst(ClaimTypes.Email) ??
result.Principal.FindFirst("email");
if (emailClaim?.Value == null || !_authorizedEmails.Contains(emailClaim.Value))
{
await HttpContext.SignOutAsync();
return Redirect("/?error=unauthorized");
}
// Sign in with the cookie scheme after successful Google authentication
await HttpContext.SignInAsync(result.Principal);
return Redirect("/");
}
[HttpPost("logout")] [HttpPost("logout")]
[Authorize] [Authorize]
public async Task<IActionResult> Logout() public async Task<IActionResult> Logout()

View file

@ -35,12 +35,36 @@ builder.Services.AddAuthentication(options =>
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = GoogleDefaults.AuthenticationScheme; options.DefaultChallengeScheme = GoogleDefaults.AuthenticationScheme;
}) })
.AddCookie() .AddCookie(options =>
{
options.LoginPath = "/api/auth/login";
options.LogoutPath = "/api/auth/logout";
options.AccessDeniedPath = "/";
options.ExpireTimeSpan = TimeSpan.FromDays(7);
options.SlidingExpiration = true;
options.Cookie.SameSite = SameSiteMode.Lax;
options.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest;
})
.AddGoogle(googleOptions => .AddGoogle(googleOptions =>
{ {
googleOptions.ClientId = builder.Configuration["Authentication:Google:ClientId"] ?? ""; googleOptions.ClientId = builder.Configuration["Authentication:Google:ClientId"] ?? "";
googleOptions.ClientSecret = builder.Configuration["Authentication:Google:ClientSecret"] ?? ""; googleOptions.ClientSecret = builder.Configuration["Authentication:Google:ClientSecret"] ?? "";
googleOptions.CallbackPath = "/api/auth/callback"; googleOptions.CallbackPath = "/signin-google";
googleOptions.SaveTokens = true;
googleOptions.Events.OnTicketReceived = async context =>
{
var emailClaim = context.Principal?.FindFirst(ClaimTypes.Email) ??
context.Principal?.FindFirst("email");
if (emailClaim?.Value == null || !authorizedEmails.Contains(emailClaim.Value))
{
context.Fail("Email not authorized");
context.Response.Redirect("/?error=unauthorized");
return;
}
await Task.CompletedTask;
};
}); });
// Configure authorization policy for allowed emails // Configure authorization policy for allowed emails