fix: SameSite=Lax for auth cookie + bidirectional identity linking
Deploy Telegram Bot / build-and-push (push) Successful in 4m45s
Deploy Telegram Bot / scan-images (push) Successful in 2m7s
Deploy Telegram Bot / deploy (push) Successful in 28s

- Change cookie auth SameSite from Strict to Lax so Discord OAuth callback
can see existing Telegram auth session and perform linking instead of
creating a new standalone Discord session (root cause of broken linking).
- Add linking logic to /auth/telegram endpoint for Discord→Telegram linking.
- Add Telegram Login Widget in Profile.razor for Discord users.
- Add CookieAuthOptionsTests to verify Lax SameSite configuration.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-25 14:58:25 +03:00
parent 63193310f2
commit 5e3028e470
3 changed files with 79 additions and 10 deletions
+29 -10
View File
@@ -61,7 +61,7 @@ builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationSc
options.AccessDeniedPath = "/access-denied";
options.Cookie.HttpOnly = true;
options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
options.Cookie.SameSite = SameSiteMode.Strict;
options.Cookie.SameSite = SameSiteMode.Lax;
options.ExpireTimeSpan = TimeSpan.FromDays(7);
options.SlidingExpiration = true;
});
@@ -123,19 +123,38 @@ app.MapHealthChecks("/alive", new HealthCheckOptions
});
// Endpoint to handle Telegram Login callback
app.MapGet("/auth/telegram", async (HttpContext context, TelegramAuthService authService) =>
app.MapGet("/auth/telegram", async (HttpContext context, TelegramAuthService authService, ISessionStore sessionStore) =>
{
if (authService.Verify(context.Request.Query, out var telegramId, out var name))
if (!authService.Verify(context.Request.Query, out var telegramId, out var name))
return Results.Redirect("/login?error=auth_failed");
await sessionStore.UpsertPlayerAsync("Telegram", telegramId.ToString(System.Globalization.CultureInfo.InvariantCulture), name, null);
// If already authenticated via another platform, link instead of replacing session
if (context.User.Identity?.IsAuthenticated == true
&& context.User.TryGetPlatformIdentity(out var currentPlatform, out var currentExternalUserId)
&& currentPlatform != "Telegram")
{
var authProperties = new AuthenticationProperties { IsPersistent = true };
await context.SignInAsync(
CookieAuthenticationDefaults.AuthenticationScheme,
CreateTelegramPrincipal(telegramId, name),
authProperties);
return Results.Redirect("/");
try
{
await sessionStore.LinkIdentityAsync(
currentPlatform, currentExternalUserId,
"Telegram", telegramId.ToString(System.Globalization.CultureInfo.InvariantCulture),
name);
return Results.Redirect("/profile?linked=telegram");
}
catch (InvalidOperationException ex)
{
return Results.Redirect($"/profile?link_error={Uri.EscapeDataString(ex.Message)}");
}
}
return Results.Redirect("/login?error=auth_failed");
var authProperties = new AuthenticationProperties { IsPersistent = true };
await context.SignInAsync(
CookieAuthenticationDefaults.AuthenticationScheme,
CreateTelegramPrincipal(telegramId, name),
authProperties);
return Results.Redirect("/");
});
app.MapPost("/auth/telegram-webapp", async (