feat: user profile requests in resource APIs (#10151)

# Which Problems Are Solved

The commands for the resource based v2beta AuthorizationService API are
added.
Authorizations, previously knows as user grants, give a user in a
specific organization and project context roles.
The project can be owned or granted.
The given roles can be used to restrict access within the projects
applications.

The commands for the resource based v2beta InteralPermissionService API
are added.
Administrators, previously knows as memberships, give a user in a
specific organization and project context roles.
The project can be owned or granted.
The give roles give the user permissions to manage different resources
in Zitadel.

API definitions from https://github.com/zitadel/zitadel/issues/9165 are
implemented.

Contains endpoints for user metadata.

# How the Problems Are Solved

### New Methods

- CreateAuthorization
- UpdateAuthorization
- DeleteAuthorization
- ActivateAuthorization
- DeactivateAuthorization
- ListAuthorizations
- CreateAdministrator
- UpdateAdministrator
- DeleteAdministrator
- ListAdministrators
- SetUserMetadata to set metadata on a user
- DeleteUserMetadata to delete metadata on a user
- ListUserMetadata to query for metadata of a user

## Deprecated Methods

### v1.ManagementService
- GetUserGrantByID
- ListUserGrants
- AddUserGrant
- UpdateUserGrant
- DeactivateUserGrant
- ReactivateUserGrant
- RemoveUserGrant
- BulkRemoveUserGrant

### v1.AuthService
- ListMyUserGrants
- ListMyProjectPermissions

# Additional Changes

- Permission checks for metadata functionality on query and command side
- correct existence checks for resources, for example you can only be an
administrator on an existing project
- combined all member tables to singular query for the administrators
- add permission checks for command an query side functionality
- combined functions on command side where necessary for easier
maintainability

# Additional Context

Closes #9165

---------

Co-authored-by: Elio Bischof <elio@zitadel.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Livio Spring <livio.a@gmail.com>
This commit is contained in:
Stefan Benz
2025-07-04 18:12:59 +02:00
committed by GitHub
parent 9ebf2316c6
commit 5403be7c4b
142 changed files with 13223 additions and 2497 deletions

View File

@@ -859,6 +859,11 @@ service AuthService {
};
}
// List My Authorizations / User Grants
//
// Deprecated: [List authorizations](apis/resources/authorization_service_v2/zitadel-authorization-v-2-beta-authorization-service-list-authorizations.api.mdx) and pass the user ID filter with your users ID to search for your authorizations on granted and owned projects.
//
// Returns a list of the authorizations/user grants the authenticated user has. User grants consist of an organization, a project and 1-n roles.
rpc ListMyUserGrants(ListMyUserGrantsRequest) returns (ListMyUserGrantsResponse) {
option (google.api.http) = {
post: "/usergrants/me/_search"
@@ -869,9 +874,8 @@ service AuthService {
};
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
tags: "User Authorizations/Grants"
summary: "List My Authorizations/Grants";
description: "Returns a list of the authorizations/user grants the authenticated user has. User grants consist of an organization, a project and 1-n roles."
tags: "User Authorizations/Grants";
deprecated: true;
};
}
@@ -908,6 +912,11 @@ service AuthService {
};
}
// List My Project Roles
//
// Deprecated: [List authorizations](apis/resources/authorization_service_v2/zitadel-authorization-v-2-beta-authorization-service-list-authorizations.api.mdx) and pass the user ID filter with your users ID and the project ID filter to search for your authorizations on a granted and an owned project.
//
// Returns a list of roles for the authenticated user and for the requesting project.
rpc ListMyProjectPermissions(ListMyProjectPermissionsRequest) returns (ListMyProjectPermissionsResponse) {
option (google.api.http) = {
post: "/permissions/me/_search"
@@ -919,8 +928,7 @@ service AuthService {
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
tags: "User Authorizations/Grants"
summary: "List My Project Roles";
description: "Returns a list of roles for the authenticated user and for the requesting project (based on the token)."
deprecated: true;
};
}

View File

@@ -0,0 +1,181 @@
syntax = "proto3";
package zitadel.authorization.v2beta;
import "protoc-gen-openapiv2/options/annotations.proto";
import "google/protobuf/timestamp.proto";
import "validate/validate.proto";
import "zitadel/filter/v2beta/filter.proto";
option go_package = "github.com/zitadel/zitadel/pkg/grpc/authorization/v2beta;authorization";
message Authorization {
// ID is the unique identifier of the authorization.
string id = 1 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "\"69629012906488334\"";
}
];
// ID is the unique identifier of the project the user was granted the authorization for.
string project_id = 2;
// Name is the name of the project the user was granted the authorization for.
string project_name = 3;
// OrganizationID is the ID of the organization the project belongs to.
string project_organization_id = 4;
// ID of the granted project, only provided if it is a granted project.
optional string project_grant_id = 5;
// ID of the organization the project is granted to, only provided if it is a granted project.
optional string granted_organization_id = 6;
// The unique identifier of the organization the authorization belongs to.
string organization_id = 7 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "\"69629012906488334\"";
}
];
// CreationDate is the timestamp when the authorization was created.
google.protobuf.Timestamp creation_date = 8 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "\"2024-12-18T07:50:47.492Z\"";
}
];
// ChangeDate is the timestamp when the authorization was last updated.
// In case the authorization was not updated, this field is equal to the creation date.
google.protobuf.Timestamp change_date = 9 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "\"2025-01-23T10:34:18.051Z\"";
}
];
// State is the current state of the authorization.
State state = 10;
User user = 11;
// Roles contains the roles the user was granted for the project.
repeated string roles = 12;
}
enum State {
STATE_UNSPECIFIED = 0;
// An active authorization grants the user access with the roles specified on the project.
STATE_ACTIVE = 1;
// An inactive authorization temporarily deactivates the granted access and roles.
// ZITADEL will not include the specific authorization in any authorization information like an access token.
// But the information can still be accessed using the API.
STATE_INACTIVE = 2;
}
message User {
// ID represents the ID of the user who was granted the authorization.
string id = 1;
// PreferredLoginName represents the preferred login name of the granted user.
string preferred_login_name = 2;
// DisplayName represents the public display name of the granted user.
string display_name = 3;
// AvatarURL is the URL to the user's public avatar image.
string avatar_url = 4;
// The organization the user belong to.
// This does not have to correspond with the authorizations organization.
string organization_id = 5;
}
message AuthorizationsSearchFilter {
oneof filter {
option (validate.required) = true;
// Search for authorizations by their IDs.
zitadel.filter.v2beta.InIDsFilter authorization_ids = 1;
// Search for an organizations authorizations by its ID.
zitadel.filter.v2beta.IDFilter organization_id = 2;
// Search for authorizations by their state.
StateQuery state = 3;
// Search for authorizations by the ID of the user who was granted the authorization.
zitadel.filter.v2beta.IDFilter user_id = 4;
// Search for authorizations by the ID of the organisation the user is part of.
zitadel.filter.v2beta.IDFilter user_organization_id = 5;
// Search for authorizations by the preferred login name of the granted user.
UserPreferredLoginNameQuery user_preferred_login_name = 6;
// Search for authorizations by the public display name of the granted user.
UserDisplayNameQuery user_display_name = 7;
// Search for authorizations by the ID of the project the user was granted the authorization for.
// This will also include authorizations granted for project grants of the same project.
zitadel.filter.v2beta.IDFilter project_id = 8;
// Search for authorizations by the name of the project the user was granted the authorization for.
// This will also include authorizations granted for project grants of the same project.
ProjectNameQuery project_name = 9;
// Search for authorizations by the key of the role the user was granted.
RoleKeyQuery role_key = 10;
// Search for authorizations by the ID of the project grant the user was granted the authorization for.
// This will also include authorizations granted for project grants of the same project.
zitadel.filter.v2beta.IDFilter project_grant_id = 11;
}
}
message StateQuery {
// Specify the state of the authorization to search for.
State state = 1 [(validate.rules).enum = {defined_only: true, not_in: [0]}];
}
message UserPreferredLoginNameQuery {
// Specify the preferred login name of the granted user to search for.
string login_name = 1 [(validate.rules).string = {
min_len: 1
max_len: 200
}];
// Specify the method to search for the preferred login name. Default is EQUAL.
// For example, to search for all authorizations granted to a user with
// a preferred login name containing a specific string, use CONTAINS or CONTAINS_IGNORE_CASE.
zitadel.filter.v2beta.TextFilterMethod method = 2 [(validate.rules).enum.defined_only = true];
}
message UserDisplayNameQuery {
// Specify the public display name of the granted user to search for.
string display_name = 1 [(validate.rules).string = {
min_len: 1
max_len: 200
}];
// Specify the method to search for the display name. Default is EQUAL.
// For example, to search for all authorizations granted to a user with
// a display name containing a specific string, use CONTAINS or CONTAINS_IGNORE_CASE.
zitadel.filter.v2beta.TextFilterMethod method = 2 [(validate.rules).enum.defined_only = true];
}
message ProjectNameQuery {
// Specify the name of the project the user was granted the authorization for to search for.
// Note that this will also include authorizations granted for project grants of the same project.
string name = 1 [(validate.rules).string = {max_len: 200}];
// Specify the method to search for the project name. Default is EQUAL.
// For example, to search for all authorizations granted on a project with
// a name containing a specific string, use CONTAINS or CONTAINS_IGNORE_CASE.
zitadel.filter.v2beta.TextFilterMethod method = 2 [(validate.rules).enum.defined_only = true];
}
message OrganizationNameQuery {
// Specify the name of the organization the authorization was granted for to search for.
// This can either be the organization the project or the project grant is part of.
string name = 1 [(validate.rules).string = {max_len: 200}];
// Specify the method to search for the organization name. Default is EQUAL.
// For example, to search for all authorizations with an organization name containing a specific string,
// use CONTAINS or CONTAINS_IGNORE_CASE.
zitadel.filter.v2beta.TextFilterMethod method = 2 [(validate.rules).enum.defined_only = true];
}
message RoleKeyQuery {
// Specify the key of the role the user was granted to search for.
string key = 1 [(validate.rules).string = {max_len: 200}];
// Specify the method to search for the role key. Default is EQUAL.
// For example, to search for all authorizations starting with a specific role key,
// use STARTS_WITH or STARTS_WITH_IGNORE_CASE.
zitadel.filter.v2beta.TextFilterMethod method = 2 [(validate.rules).enum.defined_only = true];
}
enum AuthorizationFieldName {
AUTHORIZATION_FIELD_NAME_UNSPECIFIED = 0;
AUTHORIZATION_FIELD_NAME_CREATED_DATE = 1;
AUTHORIZATION_FIELD_NAME_CHANGED_DATE = 2;
AUTHORIZATION_FIELD_NAME_ID = 3;
AUTHORIZATION_FIELD_NAME_USER_ID = 4;
AUTHORIZATION_FIELD_NAME_PROJECT_ID = 5;
AUTHORIZATION_FIELD_NAME_ORGANIZATION_ID = 6;
AUTHORIZATION_FIELD_NAME_USER_ORGANIZATION_ID = 7;
}

View File

@@ -0,0 +1,456 @@
syntax = "proto3";
package zitadel.authorization.v2beta;
import "protoc-gen-openapiv2/options/annotations.proto";
import "google/protobuf/timestamp.proto";
import "validate/validate.proto";
import "google/api/annotations.proto";
import "zitadel/protoc_gen_zitadel/v2/options.proto";
import "zitadel/authorization/v2beta/authorization.proto";
import "zitadel/filter/v2beta/filter.proto";
option go_package = "github.com/zitadel/zitadel/pkg/grpc/authorization/v2beta;authorization";
// AuthorizationService provides methods to manage authorizations for users within your projects and applications.
//
// For managing permissions and roles for ZITADEL internal resources, like organizations, projects,
// users, etc., please use the InternalPermissionService.
service AuthorizationService {
// List Authorizations
//
// ListAuthorizations returns all authorizations matching the request and necessary permissions.
//
// Required permissions:
// - "user.grant.read"
// - no permissions required for listing own authorizations
rpc ListAuthorizations(ListAuthorizationsRequest) returns (ListAuthorizationsResponse) {
option (google.api.http) = {
// The only reason why it is used here is to avoid a conflict with the ListUsers endpoint, which already handles POST /v2/users.
post: "/v2beta/authorizations/search"
body: "*"
};
option (zitadel.protoc_gen_zitadel.v2.options) = {
auth_option: {
permission: "authenticated"
}
};
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
responses: {
key: "200";
value: {
description: "A list of all authorizations matching the query";
};
};
responses: {
key: "400";
value: {
description: "invalid list query";
};
};
};
}
// Create Authorization
//
// CreateAuthorization creates a new authorization for a user in an owned or granted project.
//
// Required permissions:
// - "user.grant.write"
rpc CreateAuthorization(CreateAuthorizationRequest) returns (CreateAuthorizationResponse) {
option (google.api.http) = {
post: "/v2beta/authorizations"
body: "*"
};
option (zitadel.protoc_gen_zitadel.v2.options) = {
auth_option: {
permission: "authenticated"
}
};
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
responses: {
key: "200";
value: {
description: "The newly created authorization";
};
};
responses: {
key: "400";
value: {
description: "invalid create request";
};
};
responses: {
key: "409"
value: {
description: "The authorization already exists.";
schema: {
json_schema: {
ref: "#/definitions/rpcStatus";
};
};
}
};
};
}
// Update Authorization
//
// UpdateAuthorization updates the authorization.
//
// Note that any role keys previously granted to the user and not present in the request will be revoked.
//
// Required permissions:
// - "user.grant.write"
rpc UpdateAuthorization(UpdateAuthorizationRequest) returns (UpdateAuthorizationResponse) {
option (google.api.http) = {
patch: "/v2beta/authorizations/{id}"
body: "*"
};
option (zitadel.protoc_gen_zitadel.v2.options) = {
auth_option: {
permission: "authenticated"
}
};
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
responses: {
key: "200";
value: {
description: "OK";
};
};
responses: {
key: "404";
value: {
description: "Authorization or one of the roles do not exist.";
schema: {
json_schema: {
ref: "#/definitions/rpcStatus";
};
};
}
}
};
}
// Delete Authorization
//
// DeleteAuthorization deletes the authorization.
//
// In case the authorization is not found, the request will return a successful response as
// the desired state is already achieved.
// You can check the deletion date in the response to verify if the authorization was deleted by the request.
//
// Required permissions:
// - "user.grant.delete"
rpc DeleteAuthorization(DeleteAuthorizationRequest) returns (DeleteAuthorizationResponse) {
option (google.api.http) = {
delete: "/v2beta/authorizations/{id}"
};
option (zitadel.protoc_gen_zitadel.v2.options) = {
auth_option: {
permission: "authenticated"
}
};
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
responses: {
key: "200";
value: {
description: "The authorization was deleted successfully.";
};
};
responses: {
key: "404";
value: {
description: "Authorization not found.";
schema: {
json_schema: {
ref: "#/definitions/rpcStatus";
};
};
};
};
};
}
// Activate Authorization
//
// ActivateAuthorization activates an existing but inactive authorization.
//
// In case the authorization is already active, the request will return a successful response as
// the desired state is already achieved.
// You can check the change date in the response to verify if the authorization was activated by the request.
//
// Required permissions:
// - "user.grant.write"
rpc ActivateAuthorization(ActivateAuthorizationRequest) returns (ActivateAuthorizationResponse) {
option (google.api.http) = {
post: "/v2beta/authorizations/{id}/activate"
body: "*"
};
option (zitadel.protoc_gen_zitadel.v2.options) = {
auth_option: {
permission: "authenticated"
}
};
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
responses: {
key: "200";
value: {
description: "The authorization was activated successfully.";
};
};
responses: {
key: "404";
value: {
description: "Authorization not found.";
schema: {
json_schema: {
ref: "#/definitions/rpcStatus";
};
};
};
};
};
}
// Deactivate Authorization
//
// DeactivateAuthorization deactivates an existing and active authorization.
//
// In case the authorization is already inactive, the request will return a successful response as
// the desired state is already achieved.
// You can check the change date in the response to verify if the authorization was deactivated by the request.
//
// Required permissions:
// - "user.grant.write"
rpc DeactivateAuthorization(DeactivateAuthorizationRequest) returns (DeactivateAuthorizationResponse) {
option (google.api.http) = {
post: "/v2beta/authorizations/{id}/deactivate"
body: "*"
};
option (zitadel.protoc_gen_zitadel.v2.options) = {
auth_option: {
permission: "authenticated"
}
};
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
responses: {
key: "200";
value: {
description: "The authorization was deactivated successfully.";
};
};
responses: {
key: "404";
value: {
description: "Authorization not found.";
schema: {
json_schema: {
ref: "#/definitions/rpcStatus";
};
};
};
};
};
}
}
message ListAuthorizationsRequest {
// Paginate through the results using a limit, offset and sorting.
optional zitadel.filter.v2beta.PaginationRequest pagination = 1;
// The field the result is sorted by. The default is the creation date. Beware that if you change this, your result pagination might be inconsistent.
optional AuthorizationFieldName sorting_column = 2 [
(validate.rules).enum = {defined_only: true},
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
default: "\"AUTHORIZATION_FIELD_NAME_CREATED_DATE\""
}
];
// Define the criteria to query for.
repeated AuthorizationsSearchFilter filters = 3;
}
message ListAuthorizationsResponse {
// Details contains the pagination information.
zitadel.filter.v2beta.PaginationResponse pagination = 1;
repeated Authorization authorizations = 2;
}
message CreateAuthorizationRequest {
// UserID is the ID of the user who should be granted the authorization.
string user_id = 1 [
(validate.rules).string = {min_len: 1, max_len: 200},
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
min_length: 1;
max_length: 200;
example: "\"163840776835432345\"";
}
];
// Project ID is the ID of the project the user should be authorized for.
string project_id = 2 [
(validate.rules).string = {min_len: 1, max_len: 200},
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
min_length: 1;
max_length: 200;
example: "\"163840776835432345\"";
}
];
// OrganizationID is the ID of the organization on which the authorization should be created.
// The organization must either own the project or have a grant for the project.
// If omitted, the authorization is created on the projects organization.
optional string organization_id = 3 [
(validate.rules).string = {max_len: 200},
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
max_length: 200;
example: "\"163840776835432345\"";
}
];
// RoleKeys are the keys of the roles the user should be granted.
repeated string role_keys = 4 [
(validate.rules).repeated = {
unique: true
items: {
string: {
min_len: 1
max_len: 200
}
}
},
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
min_length: 1;
max_length: 200;
example: "[\"user\",\"admin\"]";
}
];
}
message CreateAuthorizationResponse {
// ID is the unique identifier of the newly created authorization.
string id = 1 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "\"69629012906488334\"";
}
];
// CreationDate is the timestamp when the authorization was created.
google.protobuf.Timestamp creation_date = 2 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "\"2025-01-23T10:34:18.051Z\"";
}
];
}
message UpdateAuthorizationRequest {
// ID is the unique identifier of the authorization.
string id = 1 [
(validate.rules).string = {min_len: 1, max_len: 200},
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
min_length: 1;
max_length: 200;
example: "\"163840776835432345\"";
}
];
// RoleKeys are the keys of the roles the user should be granted.
// Note that any role keys previously granted to the user and not present in the list will be revoked.
repeated string role_keys = 2 [
(validate.rules).repeated = {
unique: true
items: {
string: {
min_len: 1
max_len: 200
}
}
},
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
min_length: 1;
max_length: 200;
example: "[\"user\",\"admin\"]";
}
];
}
message UpdateAuthorizationResponse {
// ChangeDate is the timestamp when the authorization was last updated.
google.protobuf.Timestamp change_date = 1 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "\"2024-12-18T07:50:47.492Z\"";
}
];
}
message DeleteAuthorizationRequest {
// ID is the unique identifier of the authorization that should be deleted.
string id = 1 [
(validate.rules).string = {min_len: 1, max_len: 200},
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
min_length: 1;
max_length: 200;
example: "\"163840776835432345\"";
}
];
}
message DeleteAuthorizationResponse {
// DeletionDate is the timestamp when the authorization was deleted.
google.protobuf.Timestamp deletion_date = 1 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "\"2024-12-18T07:50:47.492Z\"";
}
];
}
message ActivateAuthorizationRequest {
// ID is the unique identifier of the authorization that should be activated.
string id = 1 [
(validate.rules).string = {min_len: 1, max_len: 200},
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
min_length: 1;
max_length: 200;
example: "\"163840776835432345\"";
}
];
}
message ActivateAuthorizationResponse {
// ChangeDate is the last timestamp when the authorization was changed / activated.
google.protobuf.Timestamp change_date = 1 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "\"2024-12-18T07:50:47.492Z\"";
}
];
}
message DeactivateAuthorizationRequest {
// ID is the unique identifier of the authorization that should be deactivated.
string id = 1 [
(validate.rules).string = {min_len: 1, max_len: 200},
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
min_length: 1;
max_length: 200;
example: "\"163840776835432345\"";
}
];
}
message DeactivateAuthorizationResponse {
// ChangeDate is the last timestamp when the authorization was changed / deactivated.
google.protobuf.Timestamp change_date = 1 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "\"2024-12-18T07:50:47.492Z\"";
}
];
}

View File

@@ -86,7 +86,18 @@ message TimestampFilter {
message InIDsFilter {
// Defines the ids to query for.
repeated string ids = 1 [
(validate.rules).repeated = {
unique: true
items: {
string: {
min_len: 1
max_len: 200
}
}
},
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
min_length: 1;
max_length: 200;
example: "[\"69629023906488334\",\"69622366012355662\"]";
}
];

View File

@@ -0,0 +1,384 @@
syntax = "proto3";
package zitadel.internal_permission.v2beta;
import "google/api/annotations.proto";
import "google/api/field_behavior.proto";
import "google/protobuf/duration.proto";
import "google/protobuf/struct.proto";
import "protoc-gen-openapiv2/options/annotations.proto";
import "validate/validate.proto";
import "zitadel/protoc_gen_zitadel/v2/options.proto";
import "google/protobuf/timestamp.proto";
import "zitadel/filter/v2beta/filter.proto";
import "zitadel/internal_permission/v2beta/query.proto";
option go_package = "github.com/zitadel/zitadel/pkg/grpc/internal_permission/v2beta;internal_permission";
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
info: {
title: "Internal Permission Service";
version: "2.0-beta";
description: "This API is intended to manage internal permissions in ZITADEL. This service is in beta state. It can AND will continue breaking until a stable version is released.";
contact:{
name: "ZITADEL"
url: "https://zitadel.com"
email: "hi@zitadel.com"
}
license: {
name: "Apache 2.0",
url: "https://github.com/zitadel/zitadel/blob/main/LICENSING.md";
};
};
schemes: HTTPS;
schemes: HTTP;
consumes: "application/json";
consumes: "application/grpc";
produces: "application/json";
produces: "application/grpc";
consumes: "application/grpc-web+proto";
produces: "application/grpc-web+proto";
host: "$CUSTOM-DOMAIN";
base_path: "/";
external_docs: {
description: "Detailed information about ZITADEL",
url: "https://zitadel.com/docs"
}
security_definitions: {
security: {
key: "OAuth2";
value: {
type: TYPE_OAUTH2;
flow: FLOW_ACCESS_CODE;
authorization_url: "$CUSTOM-DOMAIN/oauth/v2/authorize";
token_url: "$CUSTOM-DOMAIN/oauth/v2/token";
scopes: {
scope: {
key: "openid";
value: "openid";
}
scope: {
key: "urn:zitadel:iam:org:project:id:zitadel:aud";
value: "urn:zitadel:iam:org:project:id:zitadel:aud";
}
}
}
}
}
security: {
security_requirement: {
key: "OAuth2";
value: {
scope: "openid";
scope: "urn:zitadel:iam:org:project:id:zitadel:aud";
}
}
}
responses: {
key: "403";
value: {
description: "Returned when the user does not have permission to access the resource.";
schema: {
json_schema: {
ref: "#/definitions/rpcStatus";
}
}
}
}
responses: {
key: "404";
value: {
description: "Returned when the resource does not exist.";
schema: {
json_schema: {
ref: "#/definitions/rpcStatus";
}
}
}
}
};
// InternalPermissionService provides methods to manage permissions for resource
// and their management in ZITADEL itself.
//
// If you want to manage permissions and roles within your project or application,
// please use the AuthorizationsService.
service InternalPermissionService {
// ListAdministrators returns all administrators and its roles matching the request and necessary permissions.
//
// Required permissions depend on the resource type:
// - "iam.member.read" for instance administrators
// - "org.member.read" for organization administrators
// - "project.member.read" for project administrators
// - "project.grant.member.read" for project grant administrators
// - no permissions required for listing own administrator roles
rpc ListAdministrators(ListAdministratorsRequest) returns (ListAdministratorsResponse) {
option (google.api.http) = {
post: "/v2beta/administrators/search",
body: "*"
};
option (zitadel.protoc_gen_zitadel.v2.options) = {
auth_option: {
permission: "authenticated"
}
};
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
responses: {
key: "200";
value: {
description: "A list of all administrators matching the query";
};
};
responses: {
key: "400";
value: {
description: "invalid list query";
};
};
};
}
// CreateAdministrator grants a administrator role to a user for a specific resource.
//
// Note that the roles are specific to the resource type.
// This means that if you want to grant a user the administrator role for an organization and a project,
// you need to create two administrator roles.
//
// Required permissions depend on the resource type:
// - "iam.member.write" for instance administrators
// - "org.member.write" for organization administrators
// - "project.member.write" for project administrators
// - "project.grant.member.write" for project grant administrators
rpc CreateAdministrator(CreateAdministratorRequest) returns (CreateAdministratorResponse) {
option (google.api.http) = {
post: "/v2beta/administrators"
body: "*"
};
option (zitadel.protoc_gen_zitadel.v2.options) = {
auth_option: {
permission: "authenticated"
}
};
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
responses: {
key: "200";
value: {
description: "Administrator created successfully";
};
};
responses: {
key: "409"
value: {
description: "The administrator to create already exists.";
}
};
};
}
// UpdateAdministrator updates the specific administrator role.
//
// Note that any role previously granted to the user and not present in the request will be revoked.
//
// Required permissions depend on the resource type:
// - "iam.member.write" for instance administrators
// - "org.member.write" for organization administrators
// - "project.member.write" for project administrators
// - "project.grant.member.write" for project grant administrators
rpc UpdateAdministrator(UpdateAdministratorRequest) returns (UpdateAdministratorResponse) {
option (google.api.http) = {
post: "/v2beta/administrators/{user_id}"
body: "*"
};
option (zitadel.protoc_gen_zitadel.v2.options) = {
auth_option: {
permission: "authenticated"
}
};
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
responses: {
key: "200";
value: {
description: "Administrator successfully updated or left unchanged";
};
};
responses: {
key: "404"
value: {
description: "The administrator to update does not exist.";
}
};
};
}
// DeleteAdministrator revokes a administrator role from a user.
//
// In case the administrator role is not found, the request will return a successful response as
// the desired state is already achieved.
// You can check the deletion date in the response to verify if the administrator role was deleted during the request.
//
// Required permissions depend on the resource type:
// - "iam.member.delete" for instance administrators
// - "org.member.delete" for organization administrators
// - "project.member.delete" for project administrators
// - "project.grant.member.delete" for project grant administrators
rpc DeleteAdministrator(DeleteAdministratorRequest) returns (DeleteAdministratorResponse) {
option (google.api.http) = {
delete: "/v2beta/administrators/{user_id}"
};
option (zitadel.protoc_gen_zitadel.v2.options) = {
auth_option: {
permission: "authenticated"
}
};
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
responses: {
key: "200";
value: {
description: "Administrator deleted successfully";
};
};
};
}
}
message ListAdministratorsRequest {
// List limitations and ordering.
optional zitadel.filter.v2beta.PaginationRequest pagination = 1;
// The field the result is sorted by. The default is the creation date. Beware that if you change this, your result pagination might be inconsistent.
optional AdministratorFieldName sorting_column = 2 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
default: "\"ADMINISTRATOR_FIELD_NAME_CREATION_DATE\""
}
];
// Filter the administrator roles to be returned.
repeated AdministratorSearchFilter filters = 3;
}
message ListAdministratorsResponse {
zitadel.filter.v2beta.PaginationResponse pagination = 1;
repeated Administrator administrators = 2;
}
message GetAdministratorRequest {
// ID is the unique identifier of the administrator.
string id = 1 [(validate.rules).string = {
min_len: 1
max_len: 200
}];
}
message GetAdministratorResponse {
Administrator administrator = 1;
}
message CreateAdministratorRequest {
// UserID is the ID of the user who should be granted the administrator role.
string user_id = 1 [(validate.rules).string = {
min_len: 1
max_len: 200
}];
// Resource is the type of the resource the administrator roles should be granted for.
ResourceType resource = 2;
// Roles are the roles that should be granted to the user for the specified resource.
// Note that roles are currently specific to the resource type.
// This means that if you want to grant a user the administrator role for an organization and a project,
// you need to create two administrator roles.
repeated string roles = 3 [(validate.rules).repeated = {
unique: true
items: {
string: {
min_len: 1
max_len: 200
}
}
}];
}
message ResourceType {
message ProjectGrant {
// ProjectID is required to grant administrator privileges for a specific project.
string project_id = 1;
// ProjectGrantID is required to grant administrator privileges for a specific project grant.
string project_grant_id = 2;
}
// Resource is the type of the resource the administrator roles should be granted for.
oneof resource {
option (validate.required) = true;
// Instance is the resource type for granting administrator privileges on the instance level.
bool instance = 1 [(validate.rules).bool = {const: true}];
// OrganizationID is required to grant administrator privileges for a specific organization.
string organization_id = 2;
// ProjectID is required to grant administrator privileges for a specific project.
string project_id = 3;
// ProjectGrantID is required to grant administrator privileges for a specific project grant.
ProjectGrant project_grant = 4;
}
}
message CreateAdministratorResponse {
// CreationDate is the timestamp when the administrator role was created.
google.protobuf.Timestamp creation_date = 1;
}
message UpdateAdministratorRequest {
// UserID is the ID of the user who should have his administrator roles update.
string user_id = 1 [(validate.rules).string = {
min_len: 1
max_len: 200
}];
// Resource is the type of the resource the administrator roles should be granted for.
ResourceType resource = 2;
// Roles are the roles that the user should be granted.
// Note that any role previously granted to the user and not present in the list will be revoked.
repeated string roles = 3 [(validate.rules).repeated = {
unique: true
items: {
string: {
min_len: 1
max_len: 200
}
}
}];
}
message UpdateAdministratorResponse {
// ChangeDate is the timestamp when the administrator role was last updated.
google.protobuf.Timestamp change_date = 1;
}
message DeleteAdministratorRequest {
// UserID is the ID of the user who should have his administrator roles removed.
string user_id = 1 [(validate.rules).string = {
min_len: 1
max_len: 200
}];
// Resource is the type of the resource the administrator roles should be removed for.
ResourceType resource = 2;
}
message DeleteAdministratorResponse {
// DeletionDate is the timestamp when the administrator role was deleted.
// Note that the deletion date is only guaranteed to be set if the deletion was successful during the request.
// In case the deletion occurred in a previous request, the deletion date might not be set.
google.protobuf.Timestamp deletion_date = 1;
}

View File

@@ -0,0 +1,166 @@
syntax = "proto3";
import "google/protobuf/timestamp.proto";
import "validate/validate.proto";
import "zitadel/filter/v2beta/filter.proto";
package zitadel.internal_permission.v2beta;
option go_package = "github.com/zitadel/zitadel/pkg/grpc/internal_permission/v2beta;internal_permission";
message Administrator {
// CreationDate is the timestamp when the administrator role was granted.
google.protobuf.Timestamp creation_date = 1;
// ChangeDate is the timestamp when the administrator role was last updated.
// In case the administrator role was not updated, this field is equal to the creation date.
google.protobuf.Timestamp change_date = 2;
// User is the user who was granted the administrator role.
User user = 3;
// Resource is the type of the resource the administrator roles were granted for.
oneof resource {
// Instance is returned if the administrator roles were granted on the instance level.
bool instance = 4;
// Organization provides information about the organization the administrator roles were granted for.
Organization organization = 5;
// Project provides information about the project the administrator roles were granted for.
Project project = 6;
// ProjectGrant provides information about the project grant the administrator roles were granted for.
ProjectGrant project_grant = 7;
}
// Roles are the roles that were granted to the user for the specified resource.
repeated string roles = 8;
}
message User {
// ID is the unique identifier of the user.
string id = 1;
// PreferredLoginName is the preferred login name of the user. This value is unique across the whole instance.
string preferred_login_name = 2;
// DisplayName is the public display name of the user.
// By default it's the user's given name and family name, their username or their email address.
string display_name = 3;
// The organization the user belong to.
string organization_id = 4;
}
message Organization {
// ID is the unique identifier of the organization the user was granted the administrator role for.
string id = 1;
// Name is the name of the organization the user was granted the administrator role for.
string name = 2;
}
message Project {
// ID is the unique identifier of the project the user was granted the administrator role for.
string id = 1;
// Name is the name of the project the user was granted the administrator role for.
string name = 2;
// OrganizationID is the ID of the organization the project belongs to.
string organization_id = 3;
}
message ProjectGrant {
// ID is the unique identifier of the project grant the user was granted the administrator role for.
string id = 1;
// ProjectID is the ID of the project the project grant belongs to.
string project_id = 2;
// ProjectName is the name of the project the project grant belongs to.
string project_name = 3;
// OrganizationID is the ID of the organization the project grant belongs to.
string organization_id = 4;
// OrganizationID is the ID of the organization the project grant belongs to.
string granted_organization_id = 5;
}
message AdministratorSearchFilter{
oneof filter {
option (validate.required) = true;
// Search for administrator roles by their creation date.
zitadel.filter.v2beta.TimestampFilter creation_date = 1;
// Search for administrator roles by their change date.
zitadel.filter.v2beta.TimestampFilter change_date = 2;
// Search for administrators roles by the IDs of the users who was granted the administrator role.
zitadel.filter.v2beta.InIDsFilter in_user_ids_filter = 3;
// Search for administrators roles by the ID of the organization the user is part of.
zitadel.filter.v2beta.IDFilter user_organization_id = 4;
// Search for administrators roles by the preferred login name of the user.
UserPreferredLoginNameFilter user_preferred_login_name = 5;
// Search for administrators roles by the display name of the user.
UserDisplayNameFilter user_display_name = 6;
// Search for administrators roles granted for a specific resource.
ResourceFilter resource = 7;
// Search for administrators roles granted with a specific role.
RoleFilter role = 8;
// Combine multiple authorization queries with an AND operation.
AndFilter and = 9;
// Combine multiple authorization queries with an OR operation.
// For example, to search for authorizations of multiple OrganizationIDs.
OrFilter or = 10;
// Negate an authorization query.
NotFilter not = 11;
}
}
message UserPreferredLoginNameFilter {
// Search for administrators by the preferred login name of the user.
string preferred_login_name = 1 [(validate.rules).string = {
min_len: 1
max_len: 200
}];
// Specify the method to search for the preferred login name. Default is EQUAL.
// For example, to search for all administrator roles of a user with a preferred login name
// containing a specific string, use CONTAINS or CONTAINS_IGNORE_CASE.
zitadel.filter.v2beta.TextFilterMethod method = 2 [(validate.rules).enum.defined_only = true];
}
message UserDisplayNameFilter {
// Search for administrators by the display name of the user.
string display_name = 1 [(validate.rules).string = {
min_len: 1
max_len: 200
}];
// Specify the method to search for the display name. Default is EQUAL.
// For example, to search for all administrator roles of a user with a display name
// containing a specific string, use CONTAINS or CONTAINS_IGNORE_CASE.
zitadel.filter.v2beta.TextFilterMethod method = 2 [(validate.rules).enum.defined_only = true];
}
message ResourceFilter {
// Search for administrators by the granted resource.
oneof resource {
// Search for administrators granted on the instance level.
bool instance = 1;
// Search for administrators granted on a specific organization.
string organization_id = 2;
// Search for administrators granted on a specific project.
string project_id = 3;
// Search for administrators granted on a specific project grant.
string project_grant_id = 4;
}
}
message RoleFilter {
// Search for administrators by the granted role.
string role_key = 1 [(validate.rules).string = {
min_len: 1
max_len: 200
}];
}
message AndFilter {
repeated AdministratorSearchFilter queries = 1;
}
message OrFilter {
repeated AdministratorSearchFilter queries = 1;
}
message NotFilter {
AdministratorSearchFilter query = 1;
}
enum AdministratorFieldName {
ADMINISTRATOR_FIELD_NAME_UNSPECIFIED = 0;
ADMINISTRATOR_FIELD_NAME_USER_ID = 1;
ADMINISTRATOR_FIELD_NAME_CREATION_DATE = 2;
ADMINISTRATOR_FIELD_NAME_CHANGE_DATE = 3;
}

View File

@@ -4177,6 +4177,11 @@ service ManagementService {
};
}
// Get User Grant By ID
//
// Deprecated: [List authorizations](apis/resources/authorization_service_v2/zitadel-authorization-v-2-beta-authorization-service-list-authorizations.api.mdx) and filter by its ID.
//
// Returns a user grant per ID. A user grant is a role a user has for a specific project and organization.
rpc GetUserGrantByID(GetUserGrantByIDRequest) returns (GetUserGrantByIDResponse) {
option (google.api.http) = {
get: "/users/{user_id}/grants/{grant_id}"
@@ -4188,8 +4193,7 @@ service ManagementService {
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
tags: "User Grants";
summary: "User Grant By ID";
description: "Returns a user grant per ID. A user grant is a role a user has for a specific project and organization."
deprecated: true;
parameters: {
headers: {
name: "x-zitadel-orgid";
@@ -4201,6 +4205,11 @@ service ManagementService {
};
}
// Search User Grants
//
// Deprecated: [List authorizations](apis/resources/authorization_service_v2/zitadel-authorization-v-2-beta-authorization-service-list-authorizations.api.mdx) and pass the user ID filter to search for a users grants on owned or granted projects.
//
// Returns a list of user grants that match the search queries. User grants are the roles users have for a specific project and organization.
rpc ListUserGrants(ListUserGrantRequest) returns (ListUserGrantResponse) {
option (google.api.http) = {
post: "/users/grants/_search"
@@ -4213,8 +4222,7 @@ service ManagementService {
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
tags: "User Grants";
summary: "Search User Grants";
description: "Returns a list of user grants that match the search queries. User grants are the roles users have for a specific project and organization."
deprecated: true;
parameters: {
headers: {
name: "x-zitadel-orgid";
@@ -4226,6 +4234,12 @@ service ManagementService {
};
}
// Add User Grant
//
// Deprecated: [Add an authorization](apis/resources/authorization_service_v2/zitadel-authorization-v-2-beta-authorization-service-create-authorization.api.mdx) to grant a user access to an owned or granted project.
//
// Add a user grant for a specific user. User grants are the roles users have for a specific project and organization.
rpc AddUserGrant(AddUserGrantRequest) returns (AddUserGrantResponse) {
option (google.api.http) = {
post: "/users/{user_id}/grants"
@@ -4238,8 +4252,7 @@ service ManagementService {
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
tags: "User Grants";
summary: "Add User Grant";
description: "Add a user grant for a specific user. User grants are the roles users have for a specific project and organization."
deprecated: true;
parameters: {
headers: {
name: "x-zitadel-orgid";
@@ -4251,6 +4264,11 @@ service ManagementService {
};
}
// Update User Grant
//
// Deprecated: [Update an authorization](apis/resources/authorization_service_v2/zitadel-authorization-v-2-beta-authorization-service-update-authorization.api.mdx) to update a user's roles on an owned or granted project.
//
// Update the roles of a user grant. User grants are the roles users have for a specific project and organization.
rpc UpdateUserGrant(UpdateUserGrantRequest) returns (UpdateUserGrantResponse) {
option (google.api.http) = {
put: "/users/{user_id}/grants/{grant_id}"
@@ -4263,8 +4281,7 @@ service ManagementService {
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
tags: "User Grants";
summary: "Update User Grants";
description: "Update the roles of a user grant. User grants are the roles users have for a specific project and organization."
deprecated: true;
parameters: {
headers: {
name: "x-zitadel-orgid";
@@ -4276,6 +4293,11 @@ service ManagementService {
};
}
// Deactivate User Grant
//
// Deprecated: [Deactivate an authorization](apis/resources/authorization_service_v2/zitadel-authorization-v-2-beta-authorization-service-deactivate-authorization.api.mdx) to disable a user's access to an owned or granted project.
//
// Deactivate the user grant. The user will not be able to use the granted project anymore. Also, the roles will not be included in the tokens when requested. An error will be returned if the user grant is already deactivated.
rpc DeactivateUserGrant(DeactivateUserGrantRequest) returns (DeactivateUserGrantResponse) {
option (google.api.http) = {
post: "/users/{user_id}/grants/{grant_id}/_deactivate"
@@ -4288,8 +4310,7 @@ service ManagementService {
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
tags: "User Grants";
summary: "Deactivate User Grant";
description: "Deactivate the user grant. The user will not be able to use the granted project anymore. Also, the roles will not be included in the tokens when requested. An error will be returned if the user grant is already deactivated."
deprecated: true;
parameters: {
headers: {
name: "x-zitadel-orgid";
@@ -4301,6 +4322,11 @@ service ManagementService {
};
}
// Reactivate User Grant
//
// Deprecated: [Activate an authorization](apis/resources/authorization_service_v2/zitadel-authorization-v-2-beta-authorization-service-activate-authorization.api.mdx) to enable a user's access to an owned or granted project.
//
// Reactivate a deactivated user grant. The user will be able to use the granted project again. An error will be returned if the user grant is not deactivated.
rpc ReactivateUserGrant(ReactivateUserGrantRequest) returns (ReactivateUserGrantResponse) {
option (google.api.http) = {
post: "/users/{user_id}/grants/{grant_id}/_reactivate"
@@ -4313,8 +4339,7 @@ service ManagementService {
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
tags: "User Grants";
summary: "Reactivate User Grant";
description: "Reactivate a deactivated user grant. The user will be able to use the granted project again. An error will be returned if the user grant is not deactivated."
deprecated: true;
parameters: {
headers: {
name: "x-zitadel-orgid";
@@ -4326,6 +4351,11 @@ service ManagementService {
};
}
// Remove User Grant
//
// Deprecated: [Delete an authorization](apis/resources/authorization_service_v2/zitadel-authorization-v-2-beta-authorization-service-delete-authorization.api.mdx) to remove a users access to an owned or granted project.
//
// Removes the user grant from the user. The user will not be able to use the granted project anymore. Also, the roles will not be included in the tokens when requested.
rpc RemoveUserGrant(RemoveUserGrantRequest) returns (RemoveUserGrantResponse) {
option (google.api.http) = {
delete: "/users/{user_id}/grants/{grant_id}"
@@ -4337,8 +4367,7 @@ service ManagementService {
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
tags: "User Grants";
summary: "Remove User Grant";
description: "Removes the user grant from the user. The user will not be able to use the granted project anymore. Also, the roles will not be included in the tokens when requested."
deprecated: true;
parameters: {
headers: {
name: "x-zitadel-orgid";
@@ -4350,6 +4379,11 @@ service ManagementService {
};
}
// Bulk Remove User Grants
//
// Deprecated: [Delete authorizations one after the other](apis/resources/authorization_service_v2/zitadel-authorization-v-2-beta-authorization-service-delete-authorization.api.mdx) to remove access for multiple users on multiple owned or granted projects.
//
// Remove a list of user grants. The users will not be able to use the granted project anymore. Also, the roles will not be included in the tokens when requested.
rpc BulkRemoveUserGrant(BulkRemoveUserGrantRequest) returns (BulkRemoveUserGrantResponse) {
option (google.api.http) = {
delete: "/user_grants/_bulk"
@@ -4362,8 +4396,7 @@ service ManagementService {
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
tags: "User Grants";
summary: "Bulk Remove User Grants";
description: "Remove a list of user grants. The users will not be able to use the granted project anymore. Also, the roles will not be included in the tokens when requested."
deprecated: true;
parameters: {
headers: {
name: "x-zitadel-orgid";

View File

@@ -0,0 +1,57 @@
syntax = "proto3";
import "zitadel/filter/v2/filter.proto";
import "protoc-gen-openapiv2/options/annotations.proto";
import "validate/validate.proto";
import "google/protobuf/timestamp.proto";
package zitadel.metadata.v2;
option go_package = "github.com/zitadel/zitadel/pkg/grpc/metadata/v2";
message Metadata {
google.protobuf.Timestamp creation_date = 1 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "\"2025-01-23T10:34:18.051Z\"";
}
];
google.protobuf.Timestamp change_date = 2 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "\"2025-01-23T10:34:18.051Z\"";
}
];
string key = 3 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "metadata key",
example: "\"key1\"";
}
];
bytes value = 4 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "metadata value is base64 encoded, make sure to decode to get the value",
example: "\"VGhpcyBpcyBteSBmaXJzdCB2YWx1ZQ==\"";
}
];
}
message MetadataSearchFilter {
oneof filter {
option (validate.required) = true;
MetadataKeyFilter key_filter = 1;
}
}
message MetadataKeyFilter {
string key = 1 [
(validate.rules).string = {max_len: 200},
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "\"key\""
}
];
zitadel.filter.v2.TextFilterMethod method = 2 [
(validate.rules).enum.defined_only = true,
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "defines which text equality method is used";
}
];
}

View File

@@ -451,7 +451,7 @@ service ProjectService {
// - `project.role.read`
rpc ListProjectRoles (ListProjectRolesRequest) returns (ListProjectRolesResponse) {
option (google.api.http) = {
delete: "/v2beta/projects/{project_id}/roles/search"
post: "/v2beta/projects/{project_id}/roles/search"
};
option (zitadel.protoc_gen_zitadel.v2.options) = {

View File

@@ -22,6 +22,7 @@ import "zitadel/user/v2/key.proto";
import "zitadel/user/v2/pat.proto";
import "zitadel/user/v2/query.proto";
import "zitadel/filter/v2/filter.proto";
import "zitadel/metadata/v2/metadata.proto";
option go_package = "github.com/zitadel/zitadel/pkg/grpc/user/v2;user";
@@ -1793,6 +1794,84 @@ service UserService {
}
};
}
// Set User Metadata
//
// Sets a list of key value pairs. Existing metadata entries with matching keys are overwritten. Existing metadata entries without matching keys are untouched. To remove metadata entries, use [DeleteUserMetadata](apis/resources/user_service_v2/user-service-delete-user-metadata.api.mdx). For HTTP requests, make sure the bytes array value is base64 encoded.
//
// Required permission:
// - `user.write`
rpc SetUserMetadata(SetUserMetadataRequest) returns (SetUserMetadataResponse) {
option (google.api.http) = {
post: "/v2/users/{user_id}/metadata"
body: "*"
};
option (zitadel.protoc_gen_zitadel.v2.options) = {
auth_option: {
permission: "authenticated"
}
};
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
responses: {
key: "200";
};
responses: {
key: "400"
value: {
description: "User not found";
}
};
};
}
// List User Metadata
//
// List metadata of an user filtered by query.
//
// Required permission:
// - `user.read`
rpc ListUserMetadata(ListUserMetadataRequest) returns (ListUserMetadataResponse) {
option (google.api.http) = {
post: "/v2/users/{user_id}/metadata/search"
body: "*"
};
option (zitadel.protoc_gen_zitadel.v2.options) = {auth_option: {
permission: "user.read"
}
};
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
responses: {
key: "200";
};
};
}
// Delete User Metadata
//
// Delete metadata objects from an user with a specific key.
//
// Required permission:
// - `user.write`
rpc DeleteUserMetadata(DeleteUserMetadataRequest) returns (DeleteUserMetadataResponse) {
option (google.api.http) = {
delete: "/v2/users/{user_id}/metadata"
};
option (zitadel.protoc_gen_zitadel.v2.options) = {
auth_option: {
permission: "authenticated"
}
};
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
responses: {
key: "200";
};
};
}
}
message AddHumanUserRequest{
@@ -1890,6 +1969,13 @@ message CreateUserRequest{
example: "\"TJOPWSDYILLHXFV4MLKNNJOWFG7VSDCK\"";
}
];
// Metadata to bet set. The values have to be base64 encoded.
repeated Metadata metadata = 9 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "[{\"key\": \"test1\", \"value\": \"VGhpcyBpcyBteSBmaXJzdCB2YWx1ZQ==\"}, {\"key\": \"test2\", \"value\": \"VGhpcyBpcyBteSBzZWNvbmQgdmFsdWU=\"}]"
}
];
}
message Machine {
// The machine users name is a human readable field that helps identifying the user.
@@ -3456,3 +3542,79 @@ message ListPersonalAccessTokensResponse {
zitadel.filter.v2.PaginationResponse pagination = 1;
repeated PersonalAccessToken result = 2;
}
message Metadata {
// Key in the metadata key/value pair.
string key = 1 [(validate.rules).string = {min_len: 1, max_len: 200}];
// Value in the metadata key/value pair.
bytes value = 2 [(validate.rules).bytes = {min_len: 1, max_len: 500000}];
}
message SetUserMetadataRequest{
// ID of the user under which the metadata gets set.
string user_id = 1 [
(validate.rules).string = {min_len: 1, max_len: 200},
(google.api.field_behavior) = REQUIRED,
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
min_length: 1;
max_length: 200;
example: "\"69629012906488334\"";
}
];
// Metadata to bet set. The values have to be base64 encoded.
repeated Metadata metadata = 2 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "[{\"key\": \"test1\", \"value\": \"VGhpcyBpcyBteSBmaXJzdCB2YWx1ZQ==\"}, {\"key\": \"test2\", \"value\": \"VGhpcyBpcyBteSBzZWNvbmQgdmFsdWU=\"}]"
}
];
}
message SetUserMetadataResponse{
// The timestamp of the update of the user metadata.
google.protobuf.Timestamp set_date = 1 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "\"2025-01-23T10:34:18.051Z\"";
}
];
}
message ListUserMetadataRequest {
// ID of the user under which the metadata is to be listed.
string user_id = 1 [
(validate.rules).string = {min_len: 1, max_len: 200},
(google.api.field_behavior) = REQUIRED,
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
min_length: 1;
max_length: 200;
example: "\"69629012906488334\"";
}
];
// List limitations and ordering.
optional zitadel.filter.v2.PaginationRequest pagination = 2;
// Define the criteria to query for.
repeated zitadel.metadata.v2.MetadataSearchFilter filters = 3;
}
message ListUserMetadataResponse {
// Pagination of the users metadata results.
zitadel.filter.v2.PaginationResponse pagination = 1;
// The user metadata requested.
repeated zitadel.metadata.v2.Metadata metadata = 2;
}
message DeleteUserMetadataRequest {
// ID of the user which metadata is to be deleted is stored on.
string user_id = 1;
// The keys for the user metadata to be deleted.
repeated string keys = 2 [(validate.rules).repeated.items.string = {min_len: 1, max_len: 200}];
}
message DeleteUserMetadataResponse{
// The timestamp of the deletion of the user metadata.
google.protobuf.Timestamp deletion_date = 1 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "\"2025-01-23T10:34:18.051Z\"";
}
];
}