From 9f7c6bfd272938a4657180948ed35e8eed706e5b Mon Sep 17 00:00:00 2001 From: kyy Date: Wed, 4 Feb 2026 15:48:44 +0900 Subject: [PATCH] =?UTF-8?q?Hydra=20Client=20Patch=20=EA=B7=9C=EA=B2=A9=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20=EB=B0=8F=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?= =?UTF-8?q?=EA=B1=B0=EB=B6=80=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../internal/service/hydra_admin_service.go | 57 +++++++++++++++++-- 1 file changed, 53 insertions(+), 4 deletions(-) diff --git a/backend/internal/service/hydra_admin_service.go b/backend/internal/service/hydra_admin_service.go index 88a13996..06f79c0f 100644 --- a/backend/internal/service/hydra_admin_service.go +++ b/backend/internal/service/hydra_admin_service.go @@ -139,9 +139,12 @@ func (s *HydraAdminService) GetClient(ctx context.Context, clientID string) (*do } func (s *HydraAdminService) PatchClientStatus(ctx context.Context, clientID, status string) (*domain.HydraClient, error) { - payload := map[string]interface{}{ - "metadata": map[string]interface{}{ - "status": status, + // JSON Patch format + payload := []map[string]interface{}{ + { + "op": "replace", + "path": "/metadata/status", + "value": status, }, } body, _ := json.Marshal(payload) @@ -151,7 +154,7 @@ func (s *HydraAdminService) PatchClientStatus(ctx context.Context, clientID, sta if err != nil { return nil, err } - req.Header.Set("Content-Type", "application/merge-patch+json") + req.Header.Set("Content-Type", "application/json-patch+json") resp, err := s.httpClient().Do(req) if err != nil { @@ -382,6 +385,10 @@ type RejectConsentRequestResponse struct { RedirectTo string `json:"redirectTo"` } +type RejectLoginRequestResponse struct { + RedirectTo string `json:"redirectTo"` +} + func (s *HydraAdminService) GetConsentRequest(ctx context.Context, challenge string) (*HydraConsentRequest, error) { params := map[string]string{ "consent_challenge": challenge, @@ -457,6 +464,48 @@ func (s *HydraAdminService) RejectConsentRequest(ctx context.Context, challenge return &RejectConsentRequestResponse{RedirectTo: hydraResp.RedirectTo}, nil } +func (s *HydraAdminService) RejectLoginRequest(ctx context.Context, challenge, error, errorDescription string) (*RejectLoginRequestResponse, error) { + params := map[string]string{ + "login_challenge": challenge, + } + endpoint, err := s.buildURLWithParams("/oauth2/auth/requests/login/reject", params) + if err != nil { + return nil, err + } + + payload := map[string]interface{}{ + "error": error, + "error_description": errorDescription, + } + body, _ := json.Marshal(payload) + + req, err := http.NewRequestWithContext(ctx, "PUT", endpoint, bytes.NewReader(body)) + if err != nil { + return nil, fmt.Errorf("hydra admin: create request for reject login failed: %w", err) + } + req.Header.Set("Content-Type", "application/json") + + resp, err := s.httpClient().Do(req) + if err != nil { + return nil, fmt.Errorf("hydra admin: reject login request failed: %w", err) + } + defer resp.Body.Close() + + respBody, _ := io.ReadAll(resp.Body) + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("hydra admin: reject login failed status=%d body=%s", resp.StatusCode, string(respBody)) + } + + var hydraResp struct { + RedirectTo string `json:"redirect_to"` + } + if err := json.Unmarshal(respBody, &hydraResp); err != nil { + return nil, fmt.Errorf("hydra admin: decode reject login response failed: %w", err) + } + + return &RejectLoginRequestResponse{RedirectTo: hydraResp.RedirectTo}, nil +} + func (s *HydraAdminService) GetLoginRequest(ctx context.Context, challenge string) (*HydraLoginRequest, error) { params := map[string]string{ "login_challenge": challenge,