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 1f4c460c5..d606f2d5b 100644 --- a/internal/api/oauthserver/handlers.go +++ b/internal/api/oauthserver/handlers.go @@ -541,17 +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"` -} - -// UserOAuthGrantsListResponse represents the response for listing user's OAuth grants -type UserOAuthGrantsListResponse struct { - Grants []UserOAuthGrantResponse `json:"grants"` + Client ClientDetailsResponse `json:"client"` + Scopes []string `json:"scopes"` + GrantedAt time.Time `json:"granted_at"` } // UserListOAuthGrants handles GET /user/oauth/grants @@ -587,22 +579,20 @@ 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{ + 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, } 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 3a5c6c5f3..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.ClientID) - assert.Equal(ts.T(), "Test Client", grant.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.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 b1dc943ed..30a675efc 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -837,21 +837,22 @@ 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_id: + id: type: string format: uuid description: Unique client identifier - client_name: + name: type: string description: Human-readable name of the client application - client_uri: + uri: type: string format: uri description: URL of the client application's homepage @@ -859,15 +860,15 @@ paths: 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 + 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: @@ -2479,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: