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:
@@ -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(),
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user