@@ -7,10 +7,18 @@ import (
77 "net/http"
88 "net/url"
99 "strings"
10+ "time"
1011
1112 hydra "github.com/ory/hydra-client-go/v2"
1213)
1314
15+ const (
16+ hydraAuthMethodClientSecretPost = "client_secret_post"
17+ hydraGrantTypeClientCredentials = "client_credentials"
18+ hydraResponseTypeToken = "token"
19+ hydraClientFormatJSON = "json"
20+ )
21+
1422// HydraClientManager is a ClientManager for a hydra server
1523type HydraClientManager struct {
1624 hydraAdmin * hydra.APIClient
@@ -34,14 +42,23 @@ func NewHydraClientManager(adminURL string, logger *slog.Logger) *HydraClientMan
3442
3543// CreateClient creates a new client
3644func (h * HydraClientManager ) CreateClient (ctx context.Context , clientInfo ClientInfo ) (ClientInfo , error ) {
45+ authMethod := hydraAuthMethodClientSecretPost
3746 newClient := hydra.OAuth2Client {
38- ClientId : & clientInfo .ClientID ,
39- Scope : & clientInfo .Scope ,
40- GrantTypes : []string {"client_credentials" },
47+ ClientId : & clientInfo .ClientID ,
48+ Scope : & clientInfo .Scope ,
49+ GrantTypes : []string {hydraGrantTypeClientCredentials },
50+ TokenEndpointAuthMethod : & authMethod ,
51+ ResponseTypes : []string {hydraResponseTypeToken },
4152 }
4253 if clientInfo .ClientSecret != "" {
4354 newClient .ClientSecret = & clientInfo .ClientSecret
4455 }
56+ if clientInfo .Owner != "" {
57+ newClient .Owner = & clientInfo .Owner
58+ }
59+ if clientInfo .ClientName != "" {
60+ newClient .ClientName = & clientInfo .ClientName
61+ }
4562
4663 createdClient , response , err := h .hydraAdmin .OAuth2API .CreateOAuth2Client (ctx ).OAuth2Client (newClient ).Execute ()
4764 if response != nil {
@@ -51,13 +68,13 @@ func (h *HydraClientManager) CreateClient(ctx context.Context, clientInfo Client
5168 }
5269 }()
5370 if response .StatusCode == 409 {
54- return ClientInfo {}, fmt .Errorf ("failed to create client: client with id %s already exists" , * newClient .ClientId )
71+ return ClientInfo {}, NewAuthError ( fmt .Sprintf ("failed to create client: client with id %s already exists" , * newClient .ClientId ), http . StatusConflict )
5572 }
5673 if response .StatusCode == 400 {
57- return ClientInfo {}, fmt . Errorf ("failed to create client: invalid request" )
74+ return ClientInfo {}, NewAuthError ("failed to create client: invalid request" , http . StatusBadRequest )
5875 }
5976 if response .StatusCode != 201 {
60- return ClientInfo {}, fmt . Errorf ("failed to create client: status=%s " , response .Status )
77+ return ClientInfo {}, NewAuthError ("failed to create client" , response .StatusCode )
6178 }
6279 }
6380 // these can be confusing and related to internal client failures, so handled after http status codes
@@ -78,10 +95,10 @@ func (h *HydraClientManager) DeleteClientByID(ctx context.Context, clientID stri
7895 }
7996 }()
8097 if response .StatusCode == 404 {
81- return fmt .Errorf ("client %s not found" , clientID )
98+ return NewAuthError ( fmt .Sprintf ("client %s not found" , clientID ), http . StatusNotFound )
8299 }
83100 if response .StatusCode != 204 {
84- return fmt . Errorf ("failed to delete client from hydra: status=%s " , response .Status )
101+ return NewAuthError ("failed to delete client from hydra" , response .StatusCode )
85102 }
86103 }
87104 // these can be confusing and related to internal client failures, so handled after http status codes
@@ -102,10 +119,10 @@ func (h *HydraClientManager) RetrieveClientByID(ctx context.Context, clientID st
102119 }
103120 }()
104121 if response .StatusCode == 404 {
105- return ClientInfo {}, fmt .Errorf ("client %s not found" , clientID )
122+ return ClientInfo {}, NewAuthError ( fmt .Sprintf ("client %s not found" , clientID ), http . StatusNotFound )
106123 }
107124 if response .StatusCode != 200 {
108- return ClientInfo {}, fmt . Errorf ("failed to retrieve client: status=%s " , response .Status )
125+ return ClientInfo {}, NewAuthError ("failed to retrieve client" , response .StatusCode )
109126 }
110127 }
111128 // these tend to be confusing and related to internal client failures, so handled after http status codes
@@ -120,15 +137,26 @@ func (h *HydraClientManager) RetrieveClientByID(ctx context.Context, clientID st
120137func (h * HydraClientManager ) RetrieveClients (ctx context.Context , q RetrieveClientsRequest ) (RetrieveClientsResponse , error ) {
121138 var out RetrieveClientsResponse
122139
123- clients , response , err := h .hydraAdmin .OAuth2API .ListOAuth2Clients (ctx ).PageToken (q .PageToken ).Execute ()
140+ req := h .hydraAdmin .OAuth2API .ListOAuth2Clients (ctx )
141+ if q .Owner != "" {
142+ req = req .Owner (q .Owner )
143+ }
144+ if q .PageToken != "" {
145+ req = req .PageToken (q .PageToken )
146+ }
147+ if q .PageSize > 0 {
148+ req = req .PageSize (int64 (q .PageSize ))
149+ }
150+
151+ clients , response , err := req .Execute ()
124152 if response != nil {
125153 defer func () {
126154 if err := response .Body .Close (); err != nil {
127155 h .logger .Error ("failed to close response body" , "error" , err )
128156 }
129157 }()
130158 if response .StatusCode != 200 {
131- return out , fmt . Errorf ("failed to retrieve clients: status=%s " , response .Status )
159+ return out , NewAuthError ("failed to retrieve clients" , response .StatusCode )
132160 }
133161 }
134162 if err != nil {
@@ -150,43 +178,62 @@ func clientInfoFromHydraClient(client *hydra.OAuth2Client) ClientInfo {
150178 if client == nil {
151179 return clientInfo
152180 }
153-
154181 if client .ClientId != nil {
155182 clientInfo .ClientID = * client .ClientId
156183 }
157184 if client .Scope != nil {
158185 clientInfo .Scope = * client .Scope
159186 }
160-
187+ if client .Owner != nil {
188+ clientInfo .Owner = * client .Owner
189+ }
190+ if client .ClientName != nil {
191+ clientInfo .ClientName = * client .ClientName
192+ }
193+ if client .CreatedAt != nil {
194+ clientInfo .CreatedAt = client .CreatedAt .Format (time .RFC3339 )
195+ }
196+ if client .ClientSecret != nil {
197+ clientInfo .ClientSecret = * client .ClientSecret
198+ }
161199 return clientInfo
162200}
163201
164202func getHydraNextPageToken (response * http.Response , logger * slog.Logger ) string {
165203 for _ , linkHeader := range response .Header .Values ("Link" ) {
166- params := strings .Split (linkHeader , ";" )
167- link := params [0 ]
168- params = params [1 :]
169- // search for rel="next"
170- for _ , param := range params {
171- vs := strings .Split (param , "=" )
172- if len (vs ) != 2 {
204+ links := strings .Split (linkHeader , "," )
205+ for _ , link := range links {
206+ params := strings .Split (link , ";" )
207+ if len (params ) < 2 {
173208 continue
174209 }
175- k , v := strings .TrimSpace (vs [0 ]), strings .TrimSpace (vs [1 ])
176- if k == "rel" && (v == "next" || v == "\" next\" " ) {
177- parsedURL , err := url .Parse (link )
178- if err != nil {
179- logger .Warn ("failed to parse url in rel=next link" , "error" , err , "link" , linkHeader )
180- return ""
210+ link := params [0 ]
211+ params = params [1 :]
212+ // search for rel="next"
213+ for _ , param := range params {
214+ vs := strings .Split (param , "=" )
215+ if len (vs ) != 2 {
216+ continue
181217 }
182- queryParams := parsedURL .Query ()
183- for key , values := range queryParams {
184- if key == "page_token" {
185- return values [0 ]
218+ k , v := strings .TrimSpace (vs [0 ]), strings .TrimSpace (vs [1 ])
219+ if k == "rel" && (v == "next" || v == "\" next\" " ) {
220+ link = strings .TrimPrefix (link , "<" )
221+ link = strings .TrimSuffix (link , ">" )
222+ parsedURL , err := url .Parse (link )
223+ if err != nil {
224+ logger .Warn ("failed to parse url in rel=next link" , "error" , err , "link" , linkHeader )
225+ return ""
186226 }
227+ queryParams := parsedURL .Query ()
228+ for key , values := range queryParams {
229+ if key == "page_token" {
230+ logger .Info ("found next page token" , "token" , values [0 ])
231+ return values [0 ]
232+ }
233+ }
234+ logger .Warn ("failed to find next page token in rel=next url" , "link" , linkHeader )
235+ return ""
187236 }
188- logger .Warn ("failed to find next page token in rel=next url" , "link" , linkHeader )
189- return ""
190237 }
191238 }
192239 }
0 commit comments