From 2863ce4859d5de7ab5a2a8b6ca0e21cae333ba34 Mon Sep 17 00:00:00 2001 From: Cemal Kilic Date: Thu, 6 Nov 2025 16:00:28 +0300 Subject: [PATCH 1/3] feat(oauthserver): update oauth grant list response structure --- internal/api/oauthserver/handlers.go | 23 ++++++++------- internal/api/oauthserver/handlers_test.go | 6 ++-- openapi.yaml | 34 +++++++++++++---------- 3 files changed, 33 insertions(+), 30 deletions(-) diff --git a/internal/api/oauthserver/handlers.go b/internal/api/oauthserver/handlers.go index 1f4c460c5..d4dea517d 100644 --- a/internal/api/oauthserver/handlers.go +++ b/internal/api/oauthserver/handlers.go @@ -541,12 +541,9 @@ func (s *Server) getTokenService() *tokens.Service { // UserOAuthGrantResponse represents an OAuth grant that a user has authorized type UserOAuthGrantResponse struct { - ClientID string `json:"client_id"` - ClientName string `json:"client_name,omitempty"` - ClientURI string `json:"client_uri,omitempty"` - LogoURI string `json:"logo_uri,omitempty"` - Scopes []string `json:"scopes"` - GrantedAt time.Time `json:"granted_at"` + Client ClientDetailsResponse `json:"client"` + Scopes []string `json:"scopes"` + GrantedAt time.Time `json:"granted_at"` } // UserOAuthGrantsListResponse represents the response for listing user's OAuth grants @@ -587,12 +584,14 @@ func (s *Server) UserListOAuthGrants(w http.ResponseWriter, r *http.Request) err } response := UserOAuthGrantResponse{ - ClientID: client.ID.String(), - ClientName: utilities.StringValue(client.ClientName), - ClientURI: utilities.StringValue(client.ClientURI), - LogoURI: utilities.StringValue(client.LogoURI), - Scopes: consent.GetScopeList(), - GrantedAt: consent.GrantedAt, + Client: ClientDetailsResponse{ + ClientID: client.ID.String(), + ClientName: utilities.StringValue(client.ClientName), + ClientURI: utilities.StringValue(client.ClientURI), + LogoURI: utilities.StringValue(client.LogoURI), + }, + Scopes: consent.GetScopeList(), + GrantedAt: consent.GrantedAt, } grants = append(grants, response) diff --git a/internal/api/oauthserver/handlers_test.go b/internal/api/oauthserver/handlers_test.go index 3a5c6c5f3..dbf076468 100644 --- a/internal/api/oauthserver/handlers_test.go +++ b/internal/api/oauthserver/handlers_test.go @@ -520,8 +520,8 @@ func (ts *OAuthClientTestSuite) TestUserListOAuthGrants() { // Verify client details are included for _, grant := range response.Grants { - assert.NotEmpty(ts.T(), grant.ClientID) - assert.Equal(ts.T(), "Test Client", grant.ClientName) + assert.NotEmpty(ts.T(), grant.Client.ClientID) + assert.Equal(ts.T(), "Test Client", grant.Client.ClientName) assert.NotEmpty(ts.T(), grant.Scopes) assert.NotEmpty(ts.T(), grant.GrantedAt) } @@ -529,7 +529,7 @@ func (ts *OAuthClientTestSuite) TestUserListOAuthGrants() { // Check that client1 (with read and write scopes) is in the response found := false for _, grant := range response.Grants { - if grant.ClientID == client1.ID.String() { + if grant.Client.ClientID == client1.ID.String() { found = true assert.Contains(ts.T(), grant.Scopes, "read") assert.Contains(ts.T(), grant.Scopes, "write") diff --git a/openapi.yaml b/openapi.yaml index b1dc943ed..3b184e37c 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -844,21 +844,25 @@ paths: items: type: object properties: - client_id: - type: string - format: uuid - description: Unique client identifier - client_name: - type: string - description: Human-readable name of the client application - client_uri: - type: string - format: uri - description: URL of the client application's homepage - logo_uri: - type: string - format: uri - description: URL of the client application's logo + client: + type: object + description: OAuth client details + properties: + client_id: + type: string + format: uuid + description: Unique client identifier + client_name: + type: string + description: Human-readable name of the client application + client_uri: + type: string + format: uri + description: URL of the client application's homepage + logo_uri: + type: string + format: uri + description: URL of the client application's logo scopes: type: array items: From c46b1e9624d6fb2bae925660c9452a8c59fd9015 Mon Sep 17 00:00:00 2001 From: Cemal Kilic Date: Fri, 7 Nov 2025 10:34:34 +0300 Subject: [PATCH 2/3] fix: vibe code cleanup --- internal/api/oauthserver/authorize.go | 16 +++--- internal/api/oauthserver/handlers.go | 19 ++----- internal/api/oauthserver/handlers_test.go | 22 ++++---- openapi.yaml | 61 +++++++++++------------ 4 files changed, 53 insertions(+), 65 deletions(-) diff --git a/internal/api/oauthserver/authorize.go b/internal/api/oauthserver/authorize.go index e7bcf1c73..6d87c3cc4 100644 --- a/internal/api/oauthserver/authorize.go +++ b/internal/api/oauthserver/authorize.go @@ -43,10 +43,10 @@ type AuthorizationDetailsResponse struct { // ClientDetailsResponse represents client details in authorization response type ClientDetailsResponse struct { - ClientID string `json:"client_id"` - ClientName string `json:"client_name,omitempty"` - ClientURI string `json:"client_uri,omitempty"` - LogoURI string `json:"logo_uri,omitempty"` + ID string `json:"id"` + Name string `json:"name,omitempty"` + URI string `json:"uri,omitempty"` + LogoURI string `json:"logo_uri,omitempty"` } // UserDetailsResponse represents user details in authorization response @@ -237,10 +237,10 @@ func (s *Server) OAuthServerGetAuthorization(w http.ResponseWriter, r *http.Requ AuthorizationID: authorization.AuthorizationID, RedirectURI: authorization.RedirectURI, Client: ClientDetailsResponse{ - ClientID: authorization.Client.ID.String(), - ClientName: utilities.StringValue(authorization.Client.ClientName), - ClientURI: utilities.StringValue(authorization.Client.ClientURI), - LogoURI: utilities.StringValue(authorization.Client.LogoURI), + ID: authorization.Client.ID.String(), + Name: utilities.StringValue(authorization.Client.ClientName), + URI: utilities.StringValue(authorization.Client.ClientURI), + LogoURI: utilities.StringValue(authorization.Client.LogoURI), }, User: UserDetailsResponse{ ID: user.ID.String(), diff --git a/internal/api/oauthserver/handlers.go b/internal/api/oauthserver/handlers.go index d4dea517d..d606f2d5b 100644 --- a/internal/api/oauthserver/handlers.go +++ b/internal/api/oauthserver/handlers.go @@ -546,11 +546,6 @@ type UserOAuthGrantResponse struct { GrantedAt time.Time `json:"granted_at"` } -// UserOAuthGrantsListResponse represents the response for listing user's OAuth grants -type UserOAuthGrantsListResponse struct { - Grants []UserOAuthGrantResponse `json:"grants"` -} - // UserListOAuthGrants handles GET /user/oauth/grants // Lists all OAuth grants that the authenticated user has authorized (active consents) func (s *Server) UserListOAuthGrants(w http.ResponseWriter, r *http.Request) error { @@ -585,10 +580,10 @@ func (s *Server) UserListOAuthGrants(w http.ResponseWriter, r *http.Request) err response := UserOAuthGrantResponse{ Client: ClientDetailsResponse{ - ClientID: client.ID.String(), - ClientName: utilities.StringValue(client.ClientName), - ClientURI: utilities.StringValue(client.ClientURI), - LogoURI: utilities.StringValue(client.LogoURI), + ID: client.ID.String(), + Name: utilities.StringValue(client.ClientName), + URI: utilities.StringValue(client.ClientURI), + LogoURI: utilities.StringValue(client.LogoURI), }, Scopes: consent.GetScopeList(), GrantedAt: consent.GrantedAt, @@ -597,11 +592,7 @@ func (s *Server) UserListOAuthGrants(w http.ResponseWriter, r *http.Request) err grants = append(grants, response) } - response := UserOAuthGrantsListResponse{ - Grants: grants, - } - - return shared.SendJSON(w, http.StatusOK, response) + return shared.SendJSON(w, http.StatusOK, grants) } // UserRevokeOAuthGrant handles DELETE /user/oauth/grants?client_id=... diff --git a/internal/api/oauthserver/handlers_test.go b/internal/api/oauthserver/handlers_test.go index dbf076468..6d86b2d09 100644 --- a/internal/api/oauthserver/handlers_test.go +++ b/internal/api/oauthserver/handlers_test.go @@ -511,25 +511,25 @@ func (ts *OAuthClientTestSuite) TestUserListOAuthGrants() { // Check response assert.Equal(ts.T(), http.StatusOK, w.Code) - var response UserOAuthGrantsListResponse - err = json.Unmarshal(w.Body.Bytes(), &response) + var grants []UserOAuthGrantResponse + err = json.Unmarshal(w.Body.Bytes(), &grants) require.NoError(ts.T(), err) // Should have 2 grants - assert.Len(ts.T(), response.Grants, 2) + assert.Len(ts.T(), grants, 2) // Verify client details are included - for _, grant := range response.Grants { - assert.NotEmpty(ts.T(), grant.Client.ClientID) - assert.Equal(ts.T(), "Test Client", grant.Client.ClientName) + for _, grant := range grants { + assert.NotEmpty(ts.T(), grant.Client.ID) + assert.Equal(ts.T(), "Test Client", grant.Client.Name) assert.NotEmpty(ts.T(), grant.Scopes) assert.NotEmpty(ts.T(), grant.GrantedAt) } // Check that client1 (with read and write scopes) is in the response found := false - for _, grant := range response.Grants { - if grant.Client.ClientID == client1.ID.String() { + for _, grant := range grants { + if grant.Client.ID == client1.ID.String() { found = true assert.Contains(ts.T(), grant.Scopes, "read") assert.Contains(ts.T(), grant.Scopes, "write") @@ -553,12 +553,12 @@ func (ts *OAuthClientTestSuite) TestUserListOAuthGrantsEmpty() { assert.Equal(ts.T(), http.StatusOK, w.Code) - var response UserOAuthGrantsListResponse - err = json.Unmarshal(w.Body.Bytes(), &response) + var grants []UserOAuthGrantResponse + err = json.Unmarshal(w.Body.Bytes(), &grants) require.NoError(ts.T(), err) // Should have 0 grants - assert.Len(ts.T(), response.Grants, 0) + assert.Len(ts.T(), grants, 0) } func (ts *OAuthClientTestSuite) TestUserListOAuthGrantsNoAuth() { diff --git a/openapi.yaml b/openapi.yaml index 3b184e37c..6e719d4fa 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -837,41 +837,38 @@ paths: content: application/json: schema: - type: object - properties: - grants: - type: array - items: + type: array + items: + type: object + properties: + client: type: object + description: OAuth client details properties: - client: - type: object - description: OAuth client details - properties: - client_id: - type: string - format: uuid - description: Unique client identifier - client_name: - type: string - description: Human-readable name of the client application - client_uri: - type: string - format: uri - description: URL of the client application's homepage - logo_uri: - type: string - format: uri - description: URL of the client application's logo - scopes: - type: array - items: - type: string - description: List of scopes granted to this client - granted_at: + id: type: string - format: date-time - description: Timestamp when grant was authorized + format: uuid + description: Unique client identifier + name: + type: string + description: Human-readable name of the client application + uri: + type: string + format: uri + description: URL of the client application's homepage + logo_uri: + type: string + format: uri + description: URL of the client application's logo + scopes: + type: array + items: + type: string + description: List of scopes granted to this client + granted_at: + type: string + format: date-time + description: Timestamp when grant was authorized 401: $ref: "#/components/responses/UnauthorizedResponse" 403: From 02daaf9f3378cef90bf835e4cda720074d1b9683 Mon Sep 17 00:00:00 2001 From: Cemal Kilic Date: Fri, 7 Nov 2025 13:29:02 +0300 Subject: [PATCH 3/3] fix: update openapi for the existing endpoint --- openapi.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index 6e719d4fa..30a675efc 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -2480,12 +2480,12 @@ paths: client: type: object properties: - client_id: + id: type: string format: uuid - client_name: + name: type: string - client_uri: + uri: type: string format: uri logo_uri: