diff --git a/backend/cmd/server/main.go b/backend/cmd/server/main.go index f5326946..11818e2c 100644 --- a/backend/cmd/server/main.go +++ b/backend/cmd/server/main.go @@ -253,11 +253,12 @@ func main() { hydraService := service.NewHydraAdminService() relyingPartyService := service.NewRelyingPartyService(hydraService, ketoService) secretRepo := repository.NewClientSecretRepository(db) + consentRepo := repository.NewClientConsentRepository(db) auditHandler := handler.NewAuditHandler(auditRepo) - authHandler := handler.NewAuthHandler(redisService, idpProvider, auditRepo, oathkeeperRepo, tenantService, ketoService, userRepo) + authHandler := handler.NewAuthHandler(redisService, idpProvider, auditRepo, oathkeeperRepo, tenantService, ketoService, userRepo, consentRepo) adminHandler := handler.NewAdminHandler() - devHandler := handler.NewDevHandler(redisService, secretRepo) + devHandler := handler.NewDevHandler(redisService, secretRepo, consentRepo) tenantHandler := handler.NewTenantHandler(db, tenantService) relyingPartyHandler := handler.NewRelyingPartyHandler(relyingPartyService) kratosAdminService := service.NewKratosAdminService() diff --git a/backend/internal/handler/auth_handler.go b/backend/internal/handler/auth_handler.go index 7359f48f..a38acc4b 100644 --- a/backend/internal/handler/auth_handler.go +++ b/backend/internal/handler/auth_handler.go @@ -89,6 +89,7 @@ type AuthHandler struct { TenantService service.TenantService KetoService service.KetoService UserRepo repository.UserRepository + ConsentRepo repository.ClientConsentRepository } type signupState struct { @@ -146,7 +147,7 @@ func checkPollInterval(redis *service.RedisService, key string, interval time.Du return false, int(interval.Seconds()) } -func NewAuthHandler(redisService *service.RedisService, idpProvider domain.IdentityProvider, auditRepo domain.AuditRepository, oathkeeperRepo domain.OathkeeperLogRepository, tenantService service.TenantService, ketoService service.KetoService, userRepo repository.UserRepository) *AuthHandler { +func NewAuthHandler(redisService *service.RedisService, idpProvider domain.IdentityProvider, auditRepo domain.AuditRepository, oathkeeperRepo domain.OathkeeperLogRepository, tenantService service.TenantService, ketoService service.KetoService, userRepo repository.UserRepository, consentRepo repository.ClientConsentRepository) *AuthHandler { return &AuthHandler{ SmsService: service.NewSmsService(), EmailService: service.NewEmailService(), @@ -159,6 +160,7 @@ func NewAuthHandler(redisService *service.RedisService, idpProvider domain.Ident TenantService: tenantService, KetoService: ketoService, UserRepo: userRepo, + ConsentRepo: consentRepo, } } @@ -3425,6 +3427,15 @@ func (h *AuthHandler) GetConsentRequest(c *fiber.Ctx) error { slog.Error("failed to auto-accept hydra consent request", "error", err) // 자동 승인 실패 시 일반 흐름으로 진행 } else { + // [New] Sync to local DB even on auto-accept to ensure data consistency + if h.ConsentRepo != nil { + consent := &domain.ClientConsent{ + ClientID: consentRequest.Client.ClientID, + Subject: consentRequest.Subject, + GrantedScopes: consentRequest.RequestedScope, + } + _ = h.ConsentRepo.Upsert(c.Context(), consent) + } slog.Info("Consent skipped and auto-accepted", "subject", consentRequest.Subject, "client", consentRequest.Client.ClientID) return c.JSON(acceptResp) } @@ -3538,6 +3549,19 @@ func (h *AuthHandler) AcceptConsentRequest(c *fiber.Ctx) error { return fiber.NewError(fiber.StatusInternalServerError, "Failed to accept consent request") } + // [New] Sync to local DB for "List All Consents" feature + if h.ConsentRepo != nil { + consent := &domain.ClientConsent{ + ClientID: consentRequest.Client.ClientID, + Subject: consentRequest.Subject, + GrantedScopes: consentRequest.RequestedScope, + } + if err := h.ConsentRepo.Upsert(c.Context(), consent); err != nil { + slog.Error("failed to sync consent to local DB", "error", err, "subject", consent.Subject, "client", consent.ClientID) + // Don't fail the whole request, but log it + } + } + if h.AuditRepo != nil { detailsMap := map[string]interface{}{ "client_id": consentRequest.Client.ClientID,