feat: App Keys API v2 (#10140)

# Which Problems Are Solved

This PR *partially* addresses #9450 . Specifically, it implements the
resource based API for app keys.

This PR, together with https://github.com/zitadel/zitadel/pull/10077
completes #9450 .

# How the Problems Are Solved

- Implementation of the following endpoints: `CreateApplicationKey`,
`DeleteApplicationKey`, `GetApplicationKey`, `ListApplicationKeys`
- `ListApplicationKeys` can filter by project, app or organization ID.
Sorting is also possible according to some criteria.
  - All endpoints use permissions V2

# TODO

 - [x] Deprecate old endpoints

# Additional Context

Closes #9450
This commit is contained in:
Marco A.
2025-07-02 09:34:19 +02:00
committed by GitHub
parent 64a03fba28
commit fce9e770ac
19 changed files with 1350 additions and 69 deletions

View File

@@ -2,6 +2,7 @@ package convert
import (
"net/url"
"strings"
"github.com/muhlemmer/gu"
"google.golang.org/protobuf/types/known/timestamppb"
@@ -9,6 +10,7 @@ import (
"github.com/zitadel/zitadel/internal/api/grpc/filter/v2"
"github.com/zitadel/zitadel/internal/config/systemdefaults"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/eventstore/v1/models"
"github.com/zitadel/zitadel/internal/query"
"github.com/zitadel/zitadel/internal/zerrors"
app "github.com/zitadel/zitadel/pkg/grpc/app/v2beta"
@@ -163,3 +165,98 @@ func appQueryToModel(appQuery *app.ApplicationSearchFilter) (query.SearchQuery,
return nil, zerrors.ThrowInvalidArgument(nil, "CONV-z2mAGy", "List.Query.Invalid")
}
}
func CreateAPIClientKeyRequestToDomain(key *app.CreateApplicationKeyRequest) *domain.ApplicationKey {
return &domain.ApplicationKey{
ObjectRoot: models.ObjectRoot{
AggregateID: strings.TrimSpace(key.GetProjectId()),
},
ExpirationDate: key.GetExpirationDate().AsTime(),
Type: domain.AuthNKeyTypeJSON,
ApplicationID: strings.TrimSpace(key.GetAppId()),
}
}
func ListApplicationKeysRequestToDomain(sysDefaults systemdefaults.SystemDefaults, req *app.ListApplicationKeysRequest) (*query.AuthNKeySearchQueries, error) {
var queries []query.SearchQuery
switch req.GetResourceId().(type) {
case *app.ListApplicationKeysRequest_ApplicationId:
object, err := query.NewAuthNKeyObjectIDQuery(strings.TrimSpace(req.GetApplicationId()))
if err != nil {
return nil, err
}
queries = append(queries, object)
case *app.ListApplicationKeysRequest_OrganizationId:
resourceOwner, err := query.NewAuthNKeyResourceOwnerQuery(strings.TrimSpace(req.GetOrganizationId()))
if err != nil {
return nil, err
}
queries = append(queries, resourceOwner)
case *app.ListApplicationKeysRequest_ProjectId:
aggregate, err := query.NewAuthNKeyAggregateIDQuery(strings.TrimSpace(req.GetProjectId()))
if err != nil {
return nil, err
}
queries = append(queries, aggregate)
case nil:
default:
return nil, zerrors.ThrowInvalidArgument(nil, "CONV-t3ENme", "unexpected resource id")
}
offset, limit, asc, err := filter.PaginationPbToQuery(sysDefaults, req.GetPagination())
if err != nil {
return nil, err
}
return &query.AuthNKeySearchQueries{
SearchRequest: query.SearchRequest{
Offset: offset,
Limit: limit,
Asc: asc,
SortingColumn: appKeysSortingToColumn(req.GetSortingColumn()),
},
Queries: queries,
}, nil
}
func appKeysSortingToColumn(sortingCriteria app.ApplicationKeysSorting) query.Column {
switch sortingCriteria {
case app.ApplicationKeysSorting_APPLICATION_KEYS_SORT_BY_PROJECT_ID:
return query.AuthNKeyColumnAggregateID
case app.ApplicationKeysSorting_APPLICATION_KEYS_SORT_BY_CREATION_DATE:
return query.AuthNKeyColumnCreationDate
case app.ApplicationKeysSorting_APPLICATION_KEYS_SORT_BY_EXPIRATION:
return query.AuthNKeyColumnExpiration
case app.ApplicationKeysSorting_APPLICATION_KEYS_SORT_BY_ORGANIZATION_ID:
return query.AuthNKeyColumnResourceOwner
case app.ApplicationKeysSorting_APPLICATION_KEYS_SORT_BY_TYPE:
return query.AuthNKeyColumnType
case app.ApplicationKeysSorting_APPLICATION_KEYS_SORT_BY_APPLICATION_ID:
return query.AuthNKeyColumnObjectID
case app.ApplicationKeysSorting_APPLICATION_KEYS_SORT_BY_ID:
fallthrough
default:
return query.AuthNKeyColumnID
}
}
func ApplicationKeysToPb(keys []*query.AuthNKey) []*app.ApplicationKey {
pbAppKeys := make([]*app.ApplicationKey, len(keys))
for i, k := range keys {
pbKey := &app.ApplicationKey{
Id: k.ID,
ApplicationId: k.ApplicationID,
ProjectId: k.AggregateID,
CreationDate: timestamppb.New(k.CreationDate),
OrganizationId: k.ResourceOwner,
ExpirationDate: timestamppb.New(k.Expiration),
}
pbAppKeys[i] = pbKey
}
return pbAppKeys
}