forked from baron/baron-sso
토큰 8자리
This commit is contained in:
@@ -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"})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user