From ee9f835ceb996225b2aa2fb82df5657fd6787601 Mon Sep 17 00:00:00 2001 From: chan Date: Tue, 13 Jan 2026 10:24:13 +0900 Subject: [PATCH] =?UTF-8?q?=ED=86=A0=ED=81=B0=208=EC=9E=90=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/internal/handler/auth_handler.go | 47 ++++++++++++++---------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/backend/internal/handler/auth_handler.go b/backend/internal/handler/auth_handler.go index 7da69c53..85a06933 100644 --- a/backend/internal/handler/auth_handler.go +++ b/backend/internal/handler/auth_handler.go @@ -4,6 +4,8 @@ import ( "baron-sso-backend/internal/domain" "baron-sso-backend/internal/service" "context" + crand "crypto/rand" + "encoding/hex" "encoding/json" "fmt" "log" @@ -24,6 +26,15 @@ type AuthHandler struct { DescopeClient *client.DescopeClient } +// Helper to generate secure random strings +func generateSecureToken(length int) string { + b := make([]byte, length) + if _, err := crand.Read(b); err != nil { + return "" + } + return hex.EncodeToString(b) +} + func NewAuthHandler() *AuthHandler { redisService, err := service.NewRedisService() if err != nil { @@ -108,10 +119,9 @@ func (h *AuthHandler) InitEnchantedLink(c *fiber.Ctx) error { loginID := strings.ReplaceAll(req.LoginID, "-", "") loginID = strings.ReplaceAll(loginID, " ", "") - // Generate tokens - rand.Seed(time.Now().UnixNano()) - token := fmt.Sprintf("tk_%d%d", time.Now().Unix(), rand.Intn(100000)) - pendingRef := fmt.Sprintf("ref_%d%d", time.Now().Unix(), rand.Intn(100000)) + // Generate secure tokens + token := generateSecureToken(4) + pendingRef := generateSecureToken(4) // Store in Redis h.RedisService.Set("enchanted_session:"+pendingRef, `{"status":"pending"}`, 5*time.Minute) @@ -177,7 +187,7 @@ func (h *AuthHandler) VerifyMagicLink(c *fiber.Ctx) error { } var tokenData map[string]string - json.Unmarshal([]byte(val), &tokenData) + json.Unmarshal([]byte(val), &data := tokenData) pendingRef := tokenData["pendingRef"] loginID := tokenData["loginId"] @@ -186,10 +196,9 @@ func (h *AuthHandler) VerifyMagicLink(c *fiber.Ctx) error { return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Descope Client not configured"}) } - // Use GenerateEmbeddedLink to get a session JWT directly for the user. - // This generates a JWT that mimics a successful login. - // In the Go SDK, GenerateEmbeddedLink usually returns the token string directly. - jwtToken, err := h.DescopeClient.Management.User().GenerateEmbeddedLink(context.Background(), loginID, nil, 0) + // Use GenerateEmbeddedLink to get a temporary token directly for the user. + // This generates a token that will be exchanged for a real session. + embeddedToken, err := h.DescopeClient.Management.User().GenerateEmbeddedLink(context.Background(), loginID, nil, 0) if err != nil { // If user does not exist, create it and retry if strings.Contains(err.Error(), "User not found") || strings.Contains(err.Error(), "E062108") { @@ -203,7 +212,6 @@ func (h *AuthHandler) VerifyMagicLink(c *fiber.Ctx) error { userObj.Email = loginID } else { // LoginID is likely a phone number - // Convert 010-XXXX-XXXX (sanitized to 010XXXXXXXX) to +8210XXXXXXXX if strings.HasPrefix(loginID, "010") { descopeLoginID = "+82" + loginID[1:] } @@ -217,8 +225,8 @@ func (h *AuthHandler) VerifyMagicLink(c *fiber.Ctx) error { return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Failed to create new user"}) } - // Retry generating token with the Descope LoginID - jwtToken, err = h.DescopeClient.Management.User().GenerateEmbeddedLink(context.Background(), descopeLoginID, nil, 0) + // Retry generating embedded token with the Descope LoginID + embeddedToken, err = h.DescopeClient.Management.User().GenerateEmbeddedLink(context.Background(), descopeLoginID, nil, 0) if err != nil { log.Printf("Failed to generate Descope Session after creation: %v", err) return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Failed to generate token for new user"}) @@ -229,24 +237,23 @@ func (h *AuthHandler) VerifyMagicLink(c *fiber.Ctx) error { } } - // Exchange the Embedded Token for a real Session JWT - // We pass nil for ResponseWriter as we don't need the SDK to set cookies here. - authInfo, err := h.DescopeClient.Auth.MagicLink().Verify(context.Background(), jwtToken, nil) + // Exchange the Embedded Token for a real User Session JWT + authInfo, err := h.DescopeClient.Auth.MagicLink().Verify(context.Background(), embeddedToken, nil) if err != nil { log.Printf("Failed to verify embedded token: %v", err) return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Failed to verify upstream token"}) } - realJwtToken := authInfo.SessionToken.JWT + sessionToken := authInfo.SessionToken.JWT - // Update Session + // Update Session in Redis for the polling client sessionData, _ := json.Marshal(map[string]string{ "status": "success", - "jwt": realJwtToken, + "jwt": sessionToken, }) h.RedisService.Set("enchanted_session:"+pendingRef, string(sessionData), 5*time.Minute) return c.JSON(fiber.Map{ - "token": realJwtToken, + "token": sessionToken, "message": "Login successful", }) } @@ -330,4 +337,4 @@ func (h *AuthHandler) HandleDescopeEmailRelay(c *fiber.Ctx) error { // You would need an SMTP service here if you route ALL emails through this relay. log.Printf("[Email Webhook] Real email skipped (Not implemented): %s", req.To) return c.Status(501).JSON(fiber.Map{"error": "Real email sending not implemented"}) -} +} \ No newline at end of file