1
0
forked from baron/baron-sso

fix: resolve OIDC session state issue and synchronize portal sessions

Details:
- Backend: Extract Kratos session cookies and propagate via SetCookies in AuthInfo.
- Backend: Include sessionJwt and token during OIDC flows in PasswordLogin.
- UserFront: Add _silentSessionRecovery in main.dart to recover session via cookies if localStorage token is missing.
- UserFront: Update AuthProxyService, AuthTokenStore, AuthNotifier to support silent recovery and immediate local state update before redirect.
- AdminFront/DevFront: Fix OIDC authority to point directly to Gateway proxy and add recovery/error UI components.
This commit is contained in:
2026-04-21 14:10:27 +09:00
parent 1024ad17d3
commit 0f79b7635b
12 changed files with 199 additions and 5 deletions

View File

@@ -17,6 +17,7 @@ import (
"io"
"log/slog"
"math/rand"
"net"
"net/http"
"net/url"
"os"
@@ -1641,6 +1642,10 @@ func (h *AuthHandler) VerifyMagicLink(c *fiber.Ctx) error {
sessionToken := authInfo.SessionToken.JWT
c.Locals("login_id", loginID)
setSessionIDLocal(c, authInfo.SessionToken)
// Write Kratos session cookies to the response
h.writeAuthCookies(c, authInfo.SetCookies)
sessionID := extractSessionIDFromToken(authInfo.SessionToken)
slog.Info("[Verify] Success! Updating Redis session", "pendingRef", pendingRef)
@@ -1752,6 +1757,9 @@ func (h *AuthHandler) VerifyLoginCode(c *fiber.Ctx) error {
c.Locals("login_id", lookupLoginID)
setSessionIDLocal(c, authInfo.SessionToken)
// Write Kratos session cookies to the response
h.writeAuthCookies(c, authInfo.SetCookies)
h.RedisService.Delete(prefixLoginCode + lookupLoginID)
h.RedisService.Delete(prefixLoginCodeSmsTarget + lookupLoginID)
@@ -2414,6 +2422,10 @@ func (h *AuthHandler) completeApprovedLinkLogin(c *fiber.Ctx, pendingRef string)
c.Locals("login_id", loginID)
setSessionIDLocal(c, authInfo.SessionToken)
// Write Kratos session cookies to the response
h.writeAuthCookies(c, authInfo.SetCookies)
sessionID := extractSessionIDFromToken(authInfo.SessionToken)
if sessionID == "" && authInfo.SessionToken != nil && authInfo.SessionToken.JWT != "" {
if resolved, err := h.getKratosSessionID(authInfo.SessionToken.JWT); err == nil && resolved != "" {
@@ -2784,6 +2796,40 @@ func (h *AuthHandler) HeadlessLinkPoll(c *fiber.Ctx) error {
})
}
func (h *AuthHandler) writeAuthCookies(c *fiber.Ctx, cookies []*http.Cookie) {
if len(cookies) == 0 {
return
}
host := c.Hostname()
domain := ""
// IP address or localhost check
if ip := net.ParseIP(host); ip != nil || host == "localhost" {
domain = host
} else {
// Extract root domain (e.g., .hmac.kr from sso.hmac.kr)
parts := strings.Split(host, ".")
if len(parts) >= 2 {
domain = "." + strings.Join(parts[len(parts)-2:], ".")
}
}
for _, cookie := range cookies {
c.Cookie(&fiber.Cookie{
Name: cookie.Name,
Value: cookie.Value,
Path: "/",
Domain: domain,
MaxAge: cookie.MaxAge,
Expires: cookie.Expires,
Secure: true,
HTTPOnly: true,
SameSite: "Lax",
})
}
}
func (h *AuthHandler) PasswordLogin(c *fiber.Ctx) error {
startTime := time.Now()
ale := logger.NewAuditLogEntry(c, "login")
@@ -2832,6 +2878,10 @@ func (h *AuthHandler) PasswordLogin(c *fiber.Ctx) error {
c.Locals("user_id", authInfo.Subject)
c.Locals("login_id", loginID)
setSessionIDLocal(c, authInfo.SessionToken)
// Write Kratos session cookies to the response
h.writeAuthCookies(c, authInfo.SetCookies)
if req.LoginChallenge == "" {
attachAuditClientDetails(c, domain.HydraClient{
ClientID: "userfront",
@@ -2864,16 +2914,22 @@ func (h *AuthHandler) PasswordLogin(c *fiber.Ctx) error {
return fiber.NewError(fiber.StatusInternalServerError, "Failed to accept OIDC login request")
}
logOidcRedirectSummary("password_login", acceptResp.RedirectTo)
// IMPORTANT: Also return sessionJwt and token during OIDC flow to ensure portal session.
return c.JSON(fiber.Map{
"redirectTo": acceptResp.RedirectTo,
"status": "ok",
"provider": h.IdpProvider.Name(),
"sessionJwt": authInfo.SessionToken.JWT,
"token": authInfo.SessionToken.JWT,
"subject": authInfo.Subject,
})
}
// --- OIDC 로그인 흐름 처리 끝 ---
resp := fiber.Map{
"sessionJwt": authInfo.SessionToken.JWT,
"token": authInfo.SessionToken.JWT,
"status": "ok",
"provider": h.IdpProvider.Name(),
}