diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
new file mode 100644
index 00000000..d710461c
--- /dev/null
+++ b/.config/dotnet-tools.json
@@ -0,0 +1,12 @@
+{
+ "version": 1,
+ "isRoot": true,
+ "tools": {
+ "dotnet-grpc": {
+ "version": "2.36.0",
+ "commands": [
+ "dotnet-grpc"
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/.github/workflows/dotnet-pack-master.yml b/.github/workflows/dotnet-pack-master.yml
index 66806fb6..b50d9335 100644
--- a/.github/workflows/dotnet-pack-master.yml
+++ b/.github/workflows/dotnet-pack-master.yml
@@ -14,6 +14,8 @@ jobs:
uses: actions/setup-dotnet@v1
with:
dotnet-version: 5.0.100
+ - name: Setup dotnet tools
+ run: dotnet tool restore
- name: Test
run: ./build.sh --target test --no-logo
pack:
@@ -26,6 +28,8 @@ jobs:
uses: actions/setup-dotnet@v1
with:
dotnet-version: 5.0.100
+ - name: Setup dotnet tools
+ run: dotnet tool restore
- name: Pack
run: ./build.sh --no-logo --version 0.0.0-dev.${GITHUB_SHA::8} --release-notes 'This is a package built from master branch.' --target Pack
- uses: actions/upload-artifact@v2
diff --git a/.github/workflows/dotnet-release.yml b/.github/workflows/dotnet-release.yml
index 16b37cc7..f4024def 100644
--- a/.github/workflows/dotnet-release.yml
+++ b/.github/workflows/dotnet-release.yml
@@ -1,6 +1,10 @@
name: .NET Release
-on: [workflow_dispatch]
+on:
+ push:
+ branches:
+ - master
+ - next
jobs:
test:
@@ -11,6 +15,8 @@ jobs:
uses: actions/setup-dotnet@v1
with:
dotnet-version: 5.0.100
+ - name: Setup dotnet tools
+ run: dotnet tool restore
- name: Test
run: ./build.sh --target test --no-logo
semantic-release:
@@ -24,6 +30,8 @@ jobs:
uses: actions/setup-dotnet@v1
with:
dotnet-version: 5.0.100
+ - name: Setup dotnet tools
+ run: dotnet tool restore
- name: Semantic Release
uses: cycjimmy/semantic-release-action@v2
with:
diff --git a/.github/workflows/dotnet-test.yml b/.github/workflows/dotnet-test.yml
index c93011cf..c3e8e77c 100644
--- a/.github/workflows/dotnet-test.yml
+++ b/.github/workflows/dotnet-test.yml
@@ -18,5 +18,7 @@ jobs:
uses: actions/setup-dotnet@v1
with:
dotnet-version: 5.0.100
+ - name: Setup dotnet tools
+ run: dotnet tool restore
- name: Test
run: ./build.sh --target test --no-logo
diff --git a/.github/workflows/security-analysis.yml b/.github/workflows/security-analysis.yml
index 1f43095a..ce6ab271 100644
--- a/.github/workflows/security-analysis.yml
+++ b/.github/workflows/security-analysis.yml
@@ -1,9 +1,6 @@
name: Code Security Testing
on:
- push:
- branches:
- - master
pull_request:
branches:
- master
@@ -39,6 +36,9 @@ jobs:
with:
dotnet-version: 5.0.100
+ - name: Setup dotnet tools
+ run: dotnet tool restore
+
- name: Build
run: ./build.sh --target compile --no-logo
diff --git a/.releaserc.json b/.releaserc.json
index e3a2c8ea..a7cb63b0 100644
--- a/.releaserc.json
+++ b/.releaserc.json
@@ -1,6 +1,12 @@
{
- "verifyConditions": ["@semantic-release/github"],
- "addChannel": ["@semantic-release/github"],
+ "branches": [
+ "master",
+ {
+ "name": "next",
+ "prerelease": "prerelease"
+ }
+ ],
+ "plugins": ["@semantic-release/commit-analyzer", "@semantic-release/release-notes-generator", "@semantic-release/github"],
"prepare": [
[
"@semantic-release/exec",
@@ -13,7 +19,11 @@
[
"@semantic-release/github",
{
- "assets": [{ "path": "artifacts/*.nupkg" }]
+ "assets": [
+ {
+ "path": "artifacts/*.nupkg"
+ }
+ ]
}
],
[
diff --git a/Zitadel.sln b/Zitadel.sln
index 2edb7cd3..9b9148dd 100644
--- a/Zitadel.sln
+++ b/Zitadel.sln
@@ -32,6 +32,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Zitadel.Spa.Dev", "tests\Zi
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Zitadel.Test", "tests\Zitadel.Test\Zitadel.Test.csproj", "{44543DC1-97C5-4525-8EE4-16E5389FDF4E}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Zitadel.Api", "src\Zitadel.Api\Zitadel.Api.csproj", "{0F83D36E-945F-4B70-A6E9-867C21C546EB}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Zitadel.Api.Access.Dev", "tests\Zitadel.Api.Access.Dev\Zitadel.Api.Access.Dev.csproj", "{B51464E4-58A6-4C41-A0BF-35245F0DD862}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -43,6 +47,8 @@ Global
{9AD0581A-82BA-4E96-A1EE-722D579C26D8} = {2462186B-61A8-476C-9674-176570BBEC35}
{23DE9A2C-E9A0-458A-8878-9224C49FFB3B} = {2462186B-61A8-476C-9674-176570BBEC35}
{44543DC1-97C5-4525-8EE4-16E5389FDF4E} = {2462186B-61A8-476C-9674-176570BBEC35}
+ {0F83D36E-945F-4B70-A6E9-867C21C546EB} = {47CEB49C-56A9-4BDF-BC66-54E407391D49}
+ {B51464E4-58A6-4C41-A0BF-35245F0DD862} = {2462186B-61A8-476C-9674-176570BBEC35}
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{BF13C638-6A5C-4BF6-89FF-1BAA3986F86A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
@@ -63,5 +69,13 @@ Global
{44543DC1-97C5-4525-8EE4-16E5389FDF4E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{44543DC1-97C5-4525-8EE4-16E5389FDF4E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{44543DC1-97C5-4525-8EE4-16E5389FDF4E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0F83D36E-945F-4B70-A6E9-867C21C546EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0F83D36E-945F-4B70-A6E9-867C21C546EB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0F83D36E-945F-4B70-A6E9-867C21C546EB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0F83D36E-945F-4B70-A6E9-867C21C546EB}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B51464E4-58A6-4C41-A0BF-35245F0DD862}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B51464E4-58A6-4C41-A0BF-35245F0DD862}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B51464E4-58A6-4C41-A0BF-35245F0DD862}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B51464E4-58A6-4C41-A0BF-35245F0DD862}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
diff --git a/src/Zitadel.Api/ClientOptions.cs b/src/Zitadel.Api/ClientOptions.cs
new file mode 100644
index 00000000..2b34ed6e
--- /dev/null
+++ b/src/Zitadel.Api/ClientOptions.cs
@@ -0,0 +1,49 @@
+using System.Collections.Generic;
+using Zitadel.Authentication;
+using Zitadel.Authentication.Credentials;
+
+namespace Zitadel.Api
+{
+ ///
+ /// Options for an API client.
+ ///
+ public record ClientOptions
+ {
+ ///
+ /// The API endpoint for the client. This will be the base url for the api calls.
+ ///
+ public string Endpoint { get; init; } = ZitadelDefaults.ZitadelApiEndpoint;
+
+ ///
+ /// The organizational context in the API. This essentially defines the "x-zitadel-orgid" header value
+ /// which provides the api with the orgId that the API call will be executed in.
+ /// This may be overwritten for specific calls.
+ ///
+ public string Organization { get; init; } = string.Empty;
+
+ ///
+ /// Authentication token for the client. This field may not be used in conjunction with
+ /// . Use this field to explicitly set the
+ /// Bearer token that will be transmitted to the API. If no authentication method is set,
+ /// each call must attach the authorization header.
+ ///
+ public string? Token { get; init; }
+
+ ///
+ /// Service Account authentication method. If this field is set, the API calls are
+ /// automatically authenticated with a and the corresponding
+ /// . This will renew the access token if it is
+ /// expired.
+ ///
+ public (ServiceAccount Account, ServiceAccount.AuthOptions AuthOptions)? ServiceAccountAuthentication
+ {
+ get;
+ init;
+ }
+
+ ///
+ /// List of additional arbitrary headers that are attached to each call.
+ ///
+ public IDictionary? AdditionalHeaders { get; init; }
+ }
+}
diff --git a/src/Zitadel.Api/Clients.cs b/src/Zitadel.Api/Clients.cs
new file mode 100644
index 00000000..4ebe389c
--- /dev/null
+++ b/src/Zitadel.Api/Clients.cs
@@ -0,0 +1,75 @@
+using System;
+using System.Net.Http;
+using Caos.Zitadel.Admin.Api.V1;
+using Caos.Zitadel.Auth.Api.V1;
+using Caos.Zitadel.Management.Api.V1;
+using Grpc.Core;
+using Grpc.Net.Client;
+using Zitadel.Authentication;
+
+namespace Zitadel.Api
+{
+ ///
+ /// Helper class to instantiate api service clients for the zitadel API with correct settings.
+ ///
+ public static class Clients
+ {
+ ///
+ /// Create a service client for the auth service.
+ ///
+ /// Options for the client like authorization method.
+ /// The .
+ public static AuthService.AuthServiceClient AuthService(ClientOptions options) =>
+ GetClient(options);
+
+ ///
+ /// Create a service client for the admin service.
+ ///
+ /// Options for the client like authorization method.
+ /// The .
+ public static AdminService.AdminServiceClient AdminService(ClientOptions options) =>
+ GetClient(options);
+
+ ///
+ /// Create a service client for the management service.
+ ///
+ /// Options for the client like authorization method.
+ /// The .
+ public static ManagementService.ManagementServiceClient ManagementService(ClientOptions options) =>
+ GetClient(options);
+
+ private static TClient GetClient(ClientOptions options)
+ where TClient : ClientBase
+ {
+ var httpClient = options.Token == null && options.ServiceAccountAuthentication != null
+ ? new HttpClient(
+ new ServiceAccountHttpHandler(
+ options.ServiceAccountAuthentication.Value.Account,
+ options.ServiceAccountAuthentication.Value.AuthOptions))
+ : new HttpClient();
+
+ httpClient.DefaultRequestHeaders.Add(ZitadelDefaults.ZitadelOrgIdHeader, options.Organization);
+
+ if (options.Token != null)
+ {
+ httpClient.DefaultRequestHeaders.Authorization = new("Bearer", options.Token);
+ }
+
+ if (options.AdditionalHeaders != null)
+ {
+ foreach (var (name, value) in options.AdditionalHeaders)
+ {
+ httpClient.DefaultRequestHeaders.Add(name, value);
+ }
+ }
+
+ var channel = GrpcChannel.ForAddress(
+ options.Endpoint,
+ new GrpcChannelOptions { HttpClient = httpClient });
+ var serviceType = typeof(TClient);
+
+ return Activator.CreateInstance(serviceType, channel) as TClient ??
+ throw new($"Could not instantiate type {serviceType}");
+ }
+ }
+}
diff --git a/src/Zitadel.Api/ServiceAccountHttpHandler.cs b/src/Zitadel.Api/ServiceAccountHttpHandler.cs
new file mode 100644
index 00000000..f995afc5
--- /dev/null
+++ b/src/Zitadel.Api/ServiceAccountHttpHandler.cs
@@ -0,0 +1,49 @@
+using System;
+using System.Net.Http;
+using System.Threading;
+using System.Threading.Tasks;
+using Zitadel.Authentication.Credentials;
+
+namespace Zitadel.Api
+{
+ internal class ServiceAccountHttpHandler : DelegatingHandler
+ {
+ private static readonly TimeSpan ServiceTokenLifetime = TimeSpan.FromHours(12);
+
+ private readonly ServiceAccount _account;
+ private readonly ServiceAccount.AuthOptions _options;
+
+ private DateTime _tokenExpiryDate;
+ private string? _token;
+
+ public ServiceAccountHttpHandler(ServiceAccount account, ServiceAccount.AuthOptions options)
+ : base(new HttpClientHandler())
+ {
+ _account = account;
+ _options = options;
+ }
+
+ protected override HttpResponseMessage Send(HttpRequestMessage request, CancellationToken cancellationToken)
+ => SendAsync(request, cancellationToken).Result;
+
+ protected override async Task SendAsync(
+ HttpRequestMessage request,
+ CancellationToken cancellationToken)
+ {
+ if (request.Headers.Authorization != null)
+ {
+ return await base.SendAsync(request, cancellationToken);
+ }
+
+ // When the token is not fetched or it is expired, re-fetch a service account token.
+ if (_token == null || _tokenExpiryDate < DateTime.UtcNow)
+ {
+ _token = await _account.AuthenticateAsync(_options);
+ _tokenExpiryDate = DateTime.UtcNow + ServiceTokenLifetime;
+ }
+
+ request.Headers.Authorization = new("Bearer", _token);
+ return await base.SendAsync(request, cancellationToken);
+ }
+ }
+}
diff --git a/src/Zitadel.Api/Zitadel.Api.csproj b/src/Zitadel.Api/Zitadel.Api.csproj
new file mode 100644
index 00000000..17bd043e
--- /dev/null
+++ b/src/Zitadel.Api/Zitadel.Api.csproj
@@ -0,0 +1,85 @@
+
+
+
+
+ net5.0
+
+
+
+ true
+ Christoph Bühler
+ Zitadel API
+ Zitadel.Api
+ Zitadel;API;gRPC
+ https://github.com/caos/zitadel-net
+
+ The API library for Zitadel. Implemented with gRPC,
+ it allows access to the API of any Zitadel instance (default:
+ https://api.zitadel.ch).
+
+ https://github.com/caos/zitadel-net.git
+ git
+ Apache-2.0
+ icon.png
+
+
+
+
+ true
+ \
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ https://raw.githubusercontent.com/caos/zitadel/master/pkg/grpc/admin/proto/admin.proto
+
+
+ https://raw.githubusercontent.com/caos/zitadel/master/pkg/grpc/auth/proto/auth.proto
+
+
+ https://raw.githubusercontent.com/caos/zitadel/master/pkg/grpc/management/proto/management.proto
+
+
+ https://raw.githubusercontent.com/caos/zitadel/master/pkg/grpc/message/proto/message.proto
+
+
+ https://raw.githubusercontent.com/caos/zitadel/master/internal/protoc/protoc-gen-authoption/authoption/options.proto
+
+
+ https://raw.githubusercontent.com/googleapis/googleapis/master/google/api/annotations.proto
+
+
+ https://raw.githubusercontent.com/googleapis/googleapis/master/google/api/http.proto
+
+
+ https://raw.githubusercontent.com/grpc-ecosystem/grpc-gateway/v1/protoc-gen-swagger/options/annotations.proto
+
+
+ https://raw.githubusercontent.com/grpc-ecosystem/grpc-gateway/v1/protoc-gen-swagger/options/openapiv2.proto
+
+
+ https://raw.githubusercontent.com/envoyproxy/protoc-gen-validate/main/validate/validate.proto
+
+
+
+
+
+
+
+
+
diff --git a/src/Zitadel.Api/authoption/options.proto b/src/Zitadel.Api/authoption/options.proto
new file mode 100644
index 00000000..0d86e810
--- /dev/null
+++ b/src/Zitadel.Api/authoption/options.proto
@@ -0,0 +1,17 @@
+syntax = "proto3";
+
+package caos.zitadel.utils.v1;
+
+import "google/protobuf/descriptor.proto";
+
+option go_package = "github.com/caos/zitadel/internal/protoc/protoc-gen-authoption/authoption";
+
+
+extend google.protobuf.MethodOptions {
+ AuthOption auth_option = 50000;
+}
+
+message AuthOption {
+ string permission = 1;
+ string check_field_name = 2;
+}
\ No newline at end of file
diff --git a/src/Zitadel.Api/google/api/annotations.proto b/src/Zitadel.Api/google/api/annotations.proto
new file mode 100644
index 00000000..85c361b4
--- /dev/null
+++ b/src/Zitadel.Api/google/api/annotations.proto
@@ -0,0 +1,31 @@
+// Copyright (c) 2015, Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+syntax = "proto3";
+
+package google.api;
+
+import "google/api/http.proto";
+import "google/protobuf/descriptor.proto";
+
+option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations";
+option java_multiple_files = true;
+option java_outer_classname = "AnnotationsProto";
+option java_package = "com.google.api";
+option objc_class_prefix = "GAPI";
+
+extend google.protobuf.MethodOptions {
+ // See `HttpRule`.
+ HttpRule http = 72295728;
+}
diff --git a/src/Zitadel.Api/google/api/http.proto b/src/Zitadel.Api/google/api/http.proto
new file mode 100644
index 00000000..69460cf7
--- /dev/null
+++ b/src/Zitadel.Api/google/api/http.proto
@@ -0,0 +1,375 @@
+// Copyright 2020 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+syntax = "proto3";
+
+package google.api;
+
+option cc_enable_arenas = true;
+option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations";
+option java_multiple_files = true;
+option java_outer_classname = "HttpProto";
+option java_package = "com.google.api";
+option objc_class_prefix = "GAPI";
+
+// Defines the HTTP configuration for an API service. It contains a list of
+// [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method
+// to one or more HTTP REST API methods.
+message Http {
+ // A list of HTTP configuration rules that apply to individual API methods.
+ //
+ // **NOTE:** All service configuration rules follow "last one wins" order.
+ repeated HttpRule rules = 1;
+
+ // When set to true, URL path parameters will be fully URI-decoded except in
+ // cases of single segment matches in reserved expansion, where "%2F" will be
+ // left encoded.
+ //
+ // The default behavior is to not decode RFC 6570 reserved characters in multi
+ // segment matches.
+ bool fully_decode_reserved_expansion = 2;
+}
+
+// # gRPC Transcoding
+//
+// gRPC Transcoding is a feature for mapping between a gRPC method and one or
+// more HTTP REST endpoints. It allows developers to build a single API service
+// that supports both gRPC APIs and REST APIs. Many systems, including [Google
+// APIs](https://github.com/googleapis/googleapis),
+// [Cloud Endpoints](https://cloud.google.com/endpoints), [gRPC
+// Gateway](https://github.com/grpc-ecosystem/grpc-gateway),
+// and [Envoy](https://github.com/envoyproxy/envoy) proxy support this feature
+// and use it for large scale production services.
+//
+// `HttpRule` defines the schema of the gRPC/REST mapping. The mapping specifies
+// how different portions of the gRPC request message are mapped to the URL
+// path, URL query parameters, and HTTP request body. It also controls how the
+// gRPC response message is mapped to the HTTP response body. `HttpRule` is
+// typically specified as an `google.api.http` annotation on the gRPC method.
+//
+// Each mapping specifies a URL path template and an HTTP method. The path
+// template may refer to one or more fields in the gRPC request message, as long
+// as each field is a non-repeated field with a primitive (non-message) type.
+// The path template controls how fields of the request message are mapped to
+// the URL path.
+//
+// Example:
+//
+// service Messaging {
+// rpc GetMessage(GetMessageRequest) returns (Message) {
+// option (google.api.http) = {
+// get: "/v1/{name=messages/*}"
+// };
+// }
+// }
+// message GetMessageRequest {
+// string name = 1; // Mapped to URL path.
+// }
+// message Message {
+// string text = 1; // The resource content.
+// }
+//
+// This enables an HTTP REST to gRPC mapping as below:
+//
+// HTTP | gRPC
+// -----|-----
+// `GET /v1/messages/123456` | `GetMessage(name: "messages/123456")`
+//
+// Any fields in the request message which are not bound by the path template
+// automatically become HTTP query parameters if there is no HTTP request body.
+// For example:
+//
+// service Messaging {
+// rpc GetMessage(GetMessageRequest) returns (Message) {
+// option (google.api.http) = {
+// get:"/v1/messages/{message_id}"
+// };
+// }
+// }
+// message GetMessageRequest {
+// message SubMessage {
+// string subfield = 1;
+// }
+// string message_id = 1; // Mapped to URL path.
+// int64 revision = 2; // Mapped to URL query parameter `revision`.
+// SubMessage sub = 3; // Mapped to URL query parameter `sub.subfield`.
+// }
+//
+// This enables a HTTP JSON to RPC mapping as below:
+//
+// HTTP | gRPC
+// -----|-----
+// `GET /v1/messages/123456?revision=2&sub.subfield=foo` |
+// `GetMessage(message_id: "123456" revision: 2 sub: SubMessage(subfield:
+// "foo"))`
+//
+// Note that fields which are mapped to URL query parameters must have a
+// primitive type or a repeated primitive type or a non-repeated message type.
+// In the case of a repeated type, the parameter can be repeated in the URL
+// as `...?param=A¶m=B`. In the case of a message type, each field of the
+// message is mapped to a separate parameter, such as
+// `...?foo.a=A&foo.b=B&foo.c=C`.
+//
+// For HTTP methods that allow a request body, the `body` field
+// specifies the mapping. Consider a REST update method on the
+// message resource collection:
+//
+// service Messaging {
+// rpc UpdateMessage(UpdateMessageRequest) returns (Message) {
+// option (google.api.http) = {
+// patch: "/v1/messages/{message_id}"
+// body: "message"
+// };
+// }
+// }
+// message UpdateMessageRequest {
+// string message_id = 1; // mapped to the URL
+// Message message = 2; // mapped to the body
+// }
+//
+// The following HTTP JSON to RPC mapping is enabled, where the
+// representation of the JSON in the request body is determined by
+// protos JSON encoding:
+//
+// HTTP | gRPC
+// -----|-----
+// `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id:
+// "123456" message { text: "Hi!" })`
+//
+// The special name `*` can be used in the body mapping to define that
+// every field not bound by the path template should be mapped to the
+// request body. This enables the following alternative definition of
+// the update method:
+//
+// service Messaging {
+// rpc UpdateMessage(Message) returns (Message) {
+// option (google.api.http) = {
+// patch: "/v1/messages/{message_id}"
+// body: "*"
+// };
+// }
+// }
+// message Message {
+// string message_id = 1;
+// string text = 2;
+// }
+//
+//
+// The following HTTP JSON to RPC mapping is enabled:
+//
+// HTTP | gRPC
+// -----|-----
+// `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id:
+// "123456" text: "Hi!")`
+//
+// Note that when using `*` in the body mapping, it is not possible to
+// have HTTP parameters, as all fields not bound by the path end in
+// the body. This makes this option more rarely used in practice when
+// defining REST APIs. The common usage of `*` is in custom methods
+// which don't use the URL at all for transferring data.
+//
+// It is possible to define multiple HTTP methods for one RPC by using
+// the `additional_bindings` option. Example:
+//
+// service Messaging {
+// rpc GetMessage(GetMessageRequest) returns (Message) {
+// option (google.api.http) = {
+// get: "/v1/messages/{message_id}"
+// additional_bindings {
+// get: "/v1/users/{user_id}/messages/{message_id}"
+// }
+// };
+// }
+// }
+// message GetMessageRequest {
+// string message_id = 1;
+// string user_id = 2;
+// }
+//
+// This enables the following two alternative HTTP JSON to RPC mappings:
+//
+// HTTP | gRPC
+// -----|-----
+// `GET /v1/messages/123456` | `GetMessage(message_id: "123456")`
+// `GET /v1/users/me/messages/123456` | `GetMessage(user_id: "me" message_id:
+// "123456")`
+//
+// ## Rules for HTTP mapping
+//
+// 1. Leaf request fields (recursive expansion nested messages in the request
+// message) are classified into three categories:
+// - Fields referred by the path template. They are passed via the URL path.
+// - Fields referred by the [HttpRule.body][google.api.HttpRule.body]. They are passed via the HTTP
+// request body.
+// - All other fields are passed via the URL query parameters, and the
+// parameter name is the field path in the request message. A repeated
+// field can be represented as multiple query parameters under the same
+// name.
+// 2. If [HttpRule.body][google.api.HttpRule.body] is "*", there is no URL query parameter, all fields
+// are passed via URL path and HTTP request body.
+// 3. If [HttpRule.body][google.api.HttpRule.body] is omitted, there is no HTTP request body, all
+// fields are passed via URL path and URL query parameters.
+//
+// ### Path template syntax
+//
+// Template = "/" Segments [ Verb ] ;
+// Segments = Segment { "/" Segment } ;
+// Segment = "*" | "**" | LITERAL | Variable ;
+// Variable = "{" FieldPath [ "=" Segments ] "}" ;
+// FieldPath = IDENT { "." IDENT } ;
+// Verb = ":" LITERAL ;
+//
+// The syntax `*` matches a single URL path segment. The syntax `**` matches
+// zero or more URL path segments, which must be the last part of the URL path
+// except the `Verb`.
+//
+// The syntax `Variable` matches part of the URL path as specified by its
+// template. A variable template must not contain other variables. If a variable
+// matches a single path segment, its template may be omitted, e.g. `{var}`
+// is equivalent to `{var=*}`.
+//
+// The syntax `LITERAL` matches literal text in the URL path. If the `LITERAL`
+// contains any reserved character, such characters should be percent-encoded
+// before the matching.
+//
+// If a variable contains exactly one path segment, such as `"{var}"` or
+// `"{var=*}"`, when such a variable is expanded into a URL path on the client
+// side, all characters except `[-_.~0-9a-zA-Z]` are percent-encoded. The
+// server side does the reverse decoding. Such variables show up in the
+// [Discovery
+// Document](https://developers.google.com/discovery/v1/reference/apis) as
+// `{var}`.
+//
+// If a variable contains multiple path segments, such as `"{var=foo/*}"`
+// or `"{var=**}"`, when such a variable is expanded into a URL path on the
+// client side, all characters except `[-_.~/0-9a-zA-Z]` are percent-encoded.
+// The server side does the reverse decoding, except "%2F" and "%2f" are left
+// unchanged. Such variables show up in the
+// [Discovery
+// Document](https://developers.google.com/discovery/v1/reference/apis) as
+// `{+var}`.
+//
+// ## Using gRPC API Service Configuration
+//
+// gRPC API Service Configuration (service config) is a configuration language
+// for configuring a gRPC service to become a user-facing product. The
+// service config is simply the YAML representation of the `google.api.Service`
+// proto message.
+//
+// As an alternative to annotating your proto file, you can configure gRPC
+// transcoding in your service config YAML files. You do this by specifying a
+// `HttpRule` that maps the gRPC method to a REST endpoint, achieving the same
+// effect as the proto annotation. This can be particularly useful if you
+// have a proto that is reused in multiple services. Note that any transcoding
+// specified in the service config will override any matching transcoding
+// configuration in the proto.
+//
+// Example:
+//
+// http:
+// rules:
+// # Selects a gRPC method and applies HttpRule to it.
+// - selector: example.v1.Messaging.GetMessage
+// get: /v1/messages/{message_id}/{sub.subfield}
+//
+// ## Special notes
+//
+// When gRPC Transcoding is used to map a gRPC to JSON REST endpoints, the
+// proto to JSON conversion must follow the [proto3
+// specification](https://developers.google.com/protocol-buffers/docs/proto3#json).
+//
+// While the single segment variable follows the semantics of
+// [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2 Simple String
+// Expansion, the multi segment variable **does not** follow RFC 6570 Section
+// 3.2.3 Reserved Expansion. The reason is that the Reserved Expansion
+// does not expand special characters like `?` and `#`, which would lead
+// to invalid URLs. As the result, gRPC Transcoding uses a custom encoding
+// for multi segment variables.
+//
+// The path variables **must not** refer to any repeated or mapped field,
+// because client libraries are not capable of handling such variable expansion.
+//
+// The path variables **must not** capture the leading "/" character. The reason
+// is that the most common use case "{var}" does not capture the leading "/"
+// character. For consistency, all path variables must share the same behavior.
+//
+// Repeated message fields must not be mapped to URL query parameters, because
+// no client library can support such complicated mapping.
+//
+// If an API needs to use a JSON array for request or response body, it can map
+// the request or response body to a repeated field. However, some gRPC
+// Transcoding implementations may not support this feature.
+message HttpRule {
+ // Selects a method to which this rule applies.
+ //
+ // Refer to [selector][google.api.DocumentationRule.selector] for syntax details.
+ string selector = 1;
+
+ // Determines the URL pattern is matched by this rules. This pattern can be
+ // used with any of the {get|put|post|delete|patch} methods. A custom method
+ // can be defined using the 'custom' field.
+ oneof pattern {
+ // Maps to HTTP GET. Used for listing and getting information about
+ // resources.
+ string get = 2;
+
+ // Maps to HTTP PUT. Used for replacing a resource.
+ string put = 3;
+
+ // Maps to HTTP POST. Used for creating a resource or performing an action.
+ string post = 4;
+
+ // Maps to HTTP DELETE. Used for deleting a resource.
+ string delete = 5;
+
+ // Maps to HTTP PATCH. Used for updating a resource.
+ string patch = 6;
+
+ // The custom pattern is used for specifying an HTTP method that is not
+ // included in the `pattern` field, such as HEAD, or "*" to leave the
+ // HTTP method unspecified for this rule. The wild-card rule is useful
+ // for services that provide content to Web (HTML) clients.
+ CustomHttpPattern custom = 8;
+ }
+
+ // The name of the request field whose value is mapped to the HTTP request
+ // body, or `*` for mapping all request fields not captured by the path
+ // pattern to the HTTP body, or omitted for not having any HTTP request body.
+ //
+ // NOTE: the referred field must be present at the top-level of the request
+ // message type.
+ string body = 7;
+
+ // Optional. The name of the response field whose value is mapped to the HTTP
+ // response body. When omitted, the entire response message will be used
+ // as the HTTP response body.
+ //
+ // NOTE: The referred field must be present at the top-level of the response
+ // message type.
+ string response_body = 12;
+
+ // Additional HTTP bindings for the selector. Nested bindings must
+ // not contain an `additional_bindings` field themselves (that is,
+ // the nesting may only be one level deep).
+ repeated HttpRule additional_bindings = 11;
+}
+
+// A custom pattern is used for defining custom HTTP verb.
+message CustomHttpPattern {
+ // The name of this custom HTTP verb.
+ string kind = 1;
+
+ // The path matched by this custom verb.
+ string path = 2;
+}
diff --git a/src/Zitadel.Api/icon.png b/src/Zitadel.Api/icon.png
new file mode 100644
index 00000000..ac29f398
Binary files /dev/null and b/src/Zitadel.Api/icon.png differ
diff --git a/src/Zitadel.Api/proto/admin.proto b/src/Zitadel.Api/proto/admin.proto
new file mode 100644
index 00000000..5908f9fb
--- /dev/null
+++ b/src/Zitadel.Api/proto/admin.proto
@@ -0,0 +1,1251 @@
+
+syntax = "proto3";
+
+import "google/api/annotations.proto";
+import "google/protobuf/empty.proto";
+import "google/protobuf/timestamp.proto";
+import "validate/validate.proto";
+import "protoc-gen-swagger/options/annotations.proto";
+import "authoption/options.proto";
+
+package caos.zitadel.admin.api.v1;
+
+option go_package ="github.com/caos/zitadel/pkg/grpc/admin";
+
+option (grpc.gateway.protoc_gen_swagger.options.openapiv2_swagger) = {
+ info: {
+ title: "admin service";
+ version: "0.1";
+ contact:{
+ url: "https://github.com/caos/zitadel/pkg/admin"
+ };
+ };
+
+ schemes: HTTPS;
+
+ consumes: "application/json";
+ consumes: "application/grpc";
+
+ produces: "application/json";
+ produces: "application/grpc";
+};
+
+service AdminService {
+ // ---------
+ // Probes
+ // ---------
+
+ // Healthz returns status OK as soon as the service started
+ rpc Healthz(google.protobuf.Empty) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ get: "/healthz"
+ };
+ }
+
+//ORG
+ rpc IsOrgUnique(UniqueOrgRequest) returns (UniqueOrgResponse) {
+ option (google.api.http) = {
+ get: "/orgs/_isunique"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "iam.read"
+ };
+ }
+
+ rpc GetOrgByID(OrgID) returns (Org) {
+ option (google.api.http) = {
+ get: "/orgs/{id}"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "iam.read"
+ };
+ }
+
+ rpc SearchOrgs(OrgSearchRequest) returns (OrgSearchResponse) {
+ option (google.api.http) = {
+ post: "/orgs/_search"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "iam.read"
+ };
+ }
+
+ rpc SetUpOrg(OrgSetUpRequest) returns (OrgSetUpResponse) {
+ option (google.api.http) = {
+ post: "/orgs/_setup"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "iam.write"
+ };
+ }
+
+ //ORG_IAM_POLICY
+ rpc GetDefaultOrgIamPolicy(google.protobuf.Empty) returns (OrgIamPolicyView) {
+ option (google.api.http) = {
+ get: "/orgs/default/policies/orgiam"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "iam.policy.read"
+ };
+ }
+
+ rpc UpdateDefaultOrgIamPolicy(OrgIamPolicyRequest) returns (OrgIamPolicy) {
+ option (google.api.http) = {
+ put: "/orgs/default/policies/orgiam"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "iam.policy.write"
+ };
+ }
+
+ rpc GetOrgIamPolicy(OrgIamPolicyID) returns (OrgIamPolicyView) {
+ option (google.api.http) = {
+ get: "/orgs/{org_id}/policies/orgiam"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "iam.policy.read"
+ };
+ }
+
+ rpc CreateOrgIamPolicy(OrgIamPolicyRequest) returns (OrgIamPolicy) {
+ option (google.api.http) = {
+ post: "/orgs/{org_id}/policies/orgiam"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "iam.policy.write"
+ };
+ }
+
+ rpc UpdateOrgIamPolicy(OrgIamPolicyRequest) returns (OrgIamPolicy) {
+ option (google.api.http) = {
+ put: "/orgs/{org_id}/policies/orgiam"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "iam.policy.write"
+ };
+ }
+
+ rpc RemoveOrgIamPolicy(OrgIamPolicyID) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ delete: "/orgs/{org_id}/policies/orgiam"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "iam.policy.delete"
+ };
+ }
+
+ rpc GetIamMemberRoles(google.protobuf.Empty) returns (IamMemberRoles) {
+ option (google.api.http) = {
+ get: "/members/roles"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "iam.member.read"
+ };
+ }
+
+ rpc AddIamMember(AddIamMemberRequest) returns (IamMember) {
+ option (google.api.http) = {
+ post: "/members"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "iam.member.write"
+ };
+ }
+
+ rpc ChangeIamMember(ChangeIamMemberRequest) returns (IamMember) {
+ option (google.api.http) = {
+ put: "/members/{user_id}"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "iam.member.write"
+ };
+ }
+
+ rpc RemoveIamMember(RemoveIamMemberRequest) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ delete: "/members/{user_id}"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "iam.member.delete"
+ };
+ }
+
+ rpc SearchIamMembers(IamMemberSearchRequest) returns (IamMemberSearchResponse) {
+ option (google.api.http) = {
+ post: "/members/_search"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "iam.member.read"
+ };
+ }
+
+ rpc GetViews(google.protobuf.Empty) returns (Views) {
+ option (google.api.http) = {
+ get: "/views"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "iam.read"
+ };
+ }
+
+ rpc ClearView(ViewID) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ post: "/views/{database}/{view_name}"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "iam.write"
+ };
+ }
+
+ rpc GetFailedEvents(google.protobuf.Empty) returns (FailedEvents) {
+ option (google.api.http) = {
+ get: "/failedevents"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "iam.read"
+ };
+ }
+
+ rpc RemoveFailedEvent(FailedEventID) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ delete: "/failedevents/{database}/{view_name}/{failed_sequence}"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "iam.write"
+ };
+ }
+
+ rpc IdpByID(IdpID) returns (IdpView) {
+ option (google.api.http) = {
+ get: "/idps/{id}"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "iam.idp.read"
+ };
+ }
+
+ rpc CreateOidcIdp(OidcIdpConfigCreate) returns (Idp) {
+ option (google.api.http) = {
+ post: "/idps/oidc"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "iam.idp.write"
+ };
+ }
+
+ rpc UpdateIdpConfig(IdpUpdate) returns (Idp) {
+ option (google.api.http) = {
+ put: "/idps/{id}"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "iam.idp.write"
+ };
+ }
+
+ rpc DeactivateIdpConfig(IdpID) returns (Idp) {
+ option (google.api.http) = {
+ put: "/idps/{id}/_deactivate"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "iam.idp.write"
+ };
+ }
+
+ rpc ReactivateIdpConfig(IdpID) returns (Idp) {
+ option (google.api.http) = {
+ put: "/idps/{id}/_reactivate"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "iam.idp.write"
+ };
+ }
+
+ rpc RemoveIdpConfig(IdpID) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ delete: "/idps/{id}"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "iam.idp.write"
+ };
+ }
+
+ rpc UpdateOidcIdpConfig(OidcIdpConfigUpdate) returns (OidcIdpConfig) {
+ option (google.api.http) = {
+ put: "/idps/{idp_id}/oidcconfig"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "iam.idp.write"
+ };
+ }
+
+ rpc SearchIdps(IdpSearchRequest) returns (IdpSearchResponse) {
+ option (google.api.http) = {
+ post: "/idps/_search"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "iam.idp.read"
+ };
+ }
+
+ rpc GetDefaultLabelPolicy(google.protobuf.Empty) returns (DefaultLabelPolicyView) {
+ option (google.api.http) = {
+ get: "/policies/label"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "iam.policy.read"
+ };
+ }
+
+ rpc UpdateDefaultLabelPolicy(DefaultLabelPolicyUpdate) returns (DefaultLabelPolicy) {
+ option (google.api.http) = {
+ put: "/policies/label"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "iam.policy.write"
+ };
+ }
+
+ rpc GetDefaultMailTemplate(google.protobuf.Empty) returns (DefaultMailTemplateView) {
+ option (google.api.http) = {
+ get: "/policies/mailtemplate"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "iam.policy.read"
+ };
+ }
+
+ rpc UpdateDefaultMailTemplate(DefaultMailTemplateUpdate) returns (DefaultMailTemplate) {
+ option (google.api.http) = {
+ put: "/policies/mailtemplate"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "iam.policy.write"
+ };
+ }
+
+ rpc GetDefaultMailTexts(google.protobuf.Empty) returns (DefaultMailTextsView) {
+ option (google.api.http) = {
+ get: "/policies/mailtexts"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "iam.policy.read"
+ };
+ }
+
+ rpc UpdateDefaultMailText(DefaultMailTextUpdate) returns (DefaultMailText) {
+ option (google.api.http) = {
+ put: "/policies/mailtext"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "iam.policy.write"
+ };
+ }
+
+ rpc GetDefaultLoginPolicy(google.protobuf.Empty) returns (DefaultLoginPolicyView) {
+ option (google.api.http) = {
+ get: "/policies/login"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "iam.policy.read"
+ };
+ }
+
+ rpc UpdateDefaultLoginPolicy(DefaultLoginPolicyRequest) returns (DefaultLoginPolicy) {
+ option (google.api.http) = {
+ put: "/policies/login"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "iam.policy.write"
+ };
+ }
+
+ rpc GetDefaultLoginPolicyIdpProviders(IdpProviderSearchRequest) returns (IdpProviderSearchResponse) {
+ option (google.api.http) = {
+ post: "/policies/login/idpproviders/_search"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "iam.policy.read"
+ };
+ }
+
+ rpc AddIdpProviderToDefaultLoginPolicy(IdpProviderID) returns (IdpProviderID) {
+ option (google.api.http) = {
+ post: "/policies/login/idpproviders"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "iam.policy.write"
+ };
+ }
+
+ rpc RemoveIdpProviderFromDefaultLoginPolicy(IdpProviderID) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ delete: "/policies/login/idpproviders/{idp_config_id}"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "iam.policy.write"
+ };
+ }
+
+ rpc GetDefaultLoginPolicySecondFactors(google.protobuf.Empty) returns (SecondFactorsResult) {
+ option (google.api.http) = {
+ get: "/policies/login/secondfactors/_search"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "iam.policy.read"
+ };
+ }
+
+ rpc AddSecondFactorToDefaultLoginPolicy(SecondFactor) returns (SecondFactor) {
+ option (google.api.http) = {
+ post: "/policies/login/secondfactors"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "iam.policy.write"
+ };
+ }
+
+ rpc RemoveSecondFactorFromDefaultLoginPolicy(SecondFactor) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ delete: "/policies/login/secondfactors/{second_factor}"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "iam.policy.write"
+ };
+ }
+
+ rpc GetDefaultLoginPolicyMultiFactors(google.protobuf.Empty) returns (MultiFactorsResult) {
+ option (google.api.http) = {
+ get: "/policies/login/multifactors/_search"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "iam.policy.read"
+ };
+ }
+
+ rpc AddMultiFactorToDefaultLoginPolicy(MultiFactor) returns (MultiFactor) {
+ option (google.api.http) = {
+ post: "/policies/login/multifactors"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "iam.policy.write"
+ };
+ }
+
+ rpc RemoveMultiFactorFromDefaultLoginPolicy(MultiFactor) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ delete: "/policies/login/multifactors/{multi_factor}"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "iam.policy.write"
+ };
+ }
+
+ rpc GetDefaultPasswordComplexityPolicy(google.protobuf.Empty) returns (DefaultPasswordComplexityPolicyView) {
+ option (google.api.http) = {
+ get: "/policies/password/complexity"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "iam.policy.read"
+ };
+ }
+
+ rpc UpdateDefaultPasswordComplexityPolicy(DefaultPasswordComplexityPolicyRequest) returns (DefaultPasswordComplexityPolicy) {
+ option (google.api.http) = {
+ put: "/policies/password/complexity"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "iam.policy.write"
+ };
+ }
+
+ rpc GetDefaultPasswordAgePolicy(google.protobuf.Empty) returns (DefaultPasswordAgePolicyView) {
+ option (google.api.http) = {
+ get: "/policies/password/age"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "iam.policy.read"
+ };
+ }
+
+ rpc UpdateDefaultPasswordAgePolicy(DefaultPasswordAgePolicyRequest) returns (DefaultPasswordAgePolicy) {
+ option (google.api.http) = {
+ put: "/policies/password/age"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "iam.policy.write"
+ };
+ }
+
+ rpc GetDefaultPasswordLockoutPolicy(google.protobuf.Empty) returns (DefaultPasswordLockoutPolicyView) {
+ option (google.api.http) = {
+ get: "/policies/password/lockout"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "iam.policy.read"
+ };
+ }
+
+ rpc UpdateDefaultPasswordLockoutPolicy(DefaultPasswordLockoutPolicyRequest) returns (DefaultPasswordLockoutPolicy) {
+ option (google.api.http) = {
+ put: "/policies/password/lockout"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "iam.policy.write"
+ };
+ }
+}
+
+message OrgID {
+ string id = 1 [(validate.rules).string = {min_len: 1}];
+}
+
+message UniqueOrgRequest {
+ string name = 1 [(validate.rules).string.min_len = 1];
+ string domain = 2 [(validate.rules).string.min_len = 1];
+}
+
+message UniqueOrgResponse {
+ bool is_unique = 1;
+}
+
+message Org {
+ string id = 1;
+ OrgState state = 2;
+ google.protobuf.Timestamp creation_date = 3;
+ google.protobuf.Timestamp change_date = 4;
+ string name = 5;
+ string domain = 6;
+}
+
+enum OrgState {
+ ORGSTATE_UNSPECIFIED = 0;
+ ORGSTATE_ACTIVE = 1;
+ ORGSTATE_INACTIVE = 2;
+}
+
+message OrgSearchRequest {
+ uint64 offset = 1;
+ uint64 limit = 2;
+ OrgSearchKey sorting_column = 3 [(validate.rules).enum = {not_in: [0]}];;
+ bool asc = 4;
+ repeated OrgSearchQuery queries = 5;
+}
+
+message OrgSearchQuery {
+ OrgSearchKey key = 1 [(validate.rules).enum = {not_in: [0]}];;
+ OrgSearchMethod method = 2;
+ string value = 3;
+}
+
+enum OrgSearchKey {
+ ORGSEARCHKEY_UNSPECIFIED = 0;
+ ORGSEARCHKEY_NAME = 1;
+ ORGSEARCHKEY_DOMAIN = 2;
+ ORGSEARCHKEY_STATE = 3;
+}
+
+message OrgSearchResponse {
+ uint64 offset = 1;
+ uint64 limit = 2;
+ uint64 total_result = 3;
+ repeated Org result = 4;
+ uint64 processed_sequence = 5;
+ google.protobuf.Timestamp view_timestamp = 6;
+}
+
+enum OrgSearchMethod {
+ ORGSEARCHMETHOD_EQUALS = 0;
+ ORGSEARCHMETHOD_STARTS_WITH = 1;
+ ORGSEARCHMETHOD_CONTAINS = 2;
+}
+
+message OrgSetUpRequest {
+ CreateOrgRequest org = 1 [(validate.rules).message.required = true];
+ CreateUserRequest user = 2 [(validate.rules).message.required = true];
+}
+
+message OrgSetUpResponse {
+ Org org = 1;
+ UserResponse user = 2;
+}
+
+message CreateUserRequest {
+ string user_name = 1 [(validate.rules).string.pattern = "^[^[:space:]]{1,200}$"];
+
+ oneof user {
+ option (validate.required) = true;
+
+ CreateHumanRequest human = 2;
+ CreateMachineRequest machine = 3;
+ }
+}
+
+message CreateHumanRequest {
+ string first_name = 1 [(validate.rules).string = {min_len: 1, max_len: 200}];
+ string last_name = 2 [(validate.rules).string = {min_len: 1, max_len: 200}];
+ string nick_name = 3 [(validate.rules).string = {max_len: 200}];
+ string preferred_language = 4 [(validate.rules).string = {max_len: 200}];
+ Gender gender = 5;
+ string email = 6 [(validate.rules).string = {min_len: 1, max_len: 200, email: true}];
+ bool is_email_verified = 7;
+ string phone = 8 [(validate.rules).string = {max_len: 20}];
+ bool is_phone_verified = 9;
+ string country = 10 [(validate.rules).string = {max_len: 200}];
+ string locality = 11 [(validate.rules).string = {max_len: 200}];
+ string postal_code = 12 [(validate.rules).string = {max_len: 200}];
+ string region = 13 [(validate.rules).string = {max_len: 200}];
+ string street_address = 14 [(validate.rules).string = {max_len: 200}];
+ string password = 15 [(validate.rules).string = {max_len: 72}];
+}
+
+message CreateMachineRequest {
+ string name = 1 [(validate.rules).string = {min_len: 1, max_len: 200}];
+ string description = 2 [(validate.rules).string = {max_len: 500}];
+ }
+
+message UserResponse {
+ string id = 1;
+ UserState state = 2;
+ google.protobuf.Timestamp creation_date = 3;
+ google.protobuf.Timestamp change_date = 4;
+ uint64 sequence = 5;
+ string user_name = 6;
+
+ oneof user {
+ option (validate.required) = true;
+
+ HumanResponse human = 7;
+ MachineResponse machine = 8;
+ }
+}
+
+enum UserState {
+ USERSTATE_UNSPECIFIED = 0;
+ USERSTATE_ACTIVE = 1;
+ USERSTATE_INACTIVE = 2;
+ USERSTATE_DELETED = 3;
+ USERSTATE_LOCKED = 4;
+ USERSTATE_SUSPEND = 5;
+ USERSTATE_INITIAL= 6;
+}
+
+enum Gender {
+ GENDER_UNSPECIFIED = 0;
+ GENDER_FEMALE = 1;
+ GENDER_MALE = 2;
+ GENDER_DIVERSE = 3;
+}
+
+message HumanResponse {
+ string first_name = 1;
+ string last_name = 2;
+ string display_name = 3;
+ string nick_name = 4;
+ string preferred_language = 5;
+ Gender gender = 6;
+ string email = 7;
+ bool is_email_verified = 8;
+ string phone = 9;
+ bool is_phone_verified = 10;
+ string country = 11;
+ string locality = 12;
+ string postal_code = 13;
+ string region = 14;
+ string street_address = 15;
+ }
+
+ message MachineResponse {
+ string name = 1;
+ string description = 2;
+ repeated MachineKeyResponse keys = 3;
+ }
+
+ message MachineKeyResponse {
+ string id = 1;
+ MachineKeyType type = 2;
+ uint64 sequence = 3;
+
+ google.protobuf.Timestamp creation_date = 4;
+ google.protobuf.Timestamp expiration_date = 5;
+ }
+
+ enum MachineKeyType {
+ MACHINEKEY_UNSPECIFIED = 0;
+ MACHINEKEY_JSON = 1;
+ }
+
+message CreateOrgRequest {
+ string name = 1 [(validate.rules).string.min_len = 1];
+ string domain = 2;
+}
+
+message OrgIamPolicy {
+ string org_id = 1;
+ bool user_login_must_be_domain = 2;
+ bool default = 3;
+ uint64 sequence = 4;
+ google.protobuf.Timestamp creation_date = 5;
+ google.protobuf.Timestamp change_date = 6;
+}
+
+message OrgIamPolicyView {
+ string org_id = 1;
+ bool user_login_must_be_domain = 2;
+ bool default = 3;
+ uint64 sequence = 4;
+ google.protobuf.Timestamp creation_date = 5;
+ google.protobuf.Timestamp change_date = 6;
+}
+
+message OrgIamPolicyRequest {
+ string org_id = 1 [(validate.rules).string = {min_len: 1}];
+ string description = 2;
+ bool user_login_must_be_domain = 3;
+}
+
+message OrgIamPolicyID {
+ string org_id = 1 [(validate.rules).string = {min_len: 1}];
+}
+
+message IamMemberRoles {
+ repeated string roles = 1;
+}
+
+message IamMember {
+ string user_id = 1;
+ repeated string roles = 2;
+ google.protobuf.Timestamp change_date = 3;
+ google.protobuf.Timestamp creation_date = 4;
+ uint64 sequence = 5;
+}
+
+message AddIamMemberRequest {
+ string user_id = 1 [(validate.rules).string = {min_len: 1}];
+ repeated string roles = 2;
+}
+
+message ChangeIamMemberRequest {
+ string user_id = 1 [(validate.rules).string = {min_len: 1}];
+ repeated string roles = 2;
+}
+
+message RemoveIamMemberRequest {
+ string user_id = 1 [(validate.rules).string = {min_len: 1}];
+}
+
+message IamMemberSearchResponse {
+ uint64 offset = 1;
+ uint64 limit = 2;
+ uint64 total_result = 3;
+ repeated IamMemberView result = 4;
+ uint64 processed_sequence = 5;
+ google.protobuf.Timestamp view_timestamp = 6;
+}
+
+message IamMemberView {
+ string user_id = 1;
+ repeated string roles = 2;
+ google.protobuf.Timestamp change_date = 3;
+ google.protobuf.Timestamp creation_date = 4;
+ uint64 sequence = 5;
+ string user_name = 6;
+ string email = 7;
+ string first_name = 8;
+ string last_name = 9;
+ string display_name = 10;
+}
+
+message IamMemberSearchRequest {
+ uint64 offset = 1;
+ uint64 limit = 2;
+ repeated IamMemberSearchQuery queries = 3;
+}
+
+message IamMemberSearchQuery {
+ IamMemberSearchKey key = 1 [(validate.rules).enum = {not_in: [0]}];
+ SearchMethod method = 2;
+ string value = 3;
+}
+
+enum IamMemberSearchKey {
+ IAMMEMBERSEARCHKEY_UNSPECIFIED = 0;
+ IAMMEMBERSEARCHKEY_FIRST_NAME = 1;
+ IAMMEMBERSEARCHKEY_LAST_NAME = 2;
+ IAMMEMBERSEARCHKEY_EMAIL = 3;
+ IAMMEMBERSEARCHKEY_USER_ID = 4;
+}
+
+enum SearchMethod {
+ SEARCHMETHOD_EQUALS = 0;
+ SEARCHMETHOD_STARTS_WITH = 1;
+ SEARCHMETHOD_CONTAINS = 2;
+ SEARCHMETHOD_EQUALS_IGNORE_CASE = 3;
+ SEARCHMETHOD_STARTS_WITH_IGNORE_CASE = 4;
+ SEARCHMETHOD_CONTAINS_IGNORE_CASE = 5;
+ SEARCHMETHOD_NOT_EQUALS = 6;
+ SEARCHMETHOD_GREATER_THAN = 7;
+ SEARCHMETHOD_LESS_THAN = 8;
+ SEARCHMETHOD_IS_ONE_OF = 9;
+ SEARCHMETHOD_LIST_CONTAINS = 10;
+}
+
+message FailedEventID {
+ string database = 1 [(validate.rules).string = {min_len: 1}];
+ string view_name = 2 [(validate.rules).string = {min_len: 1}];
+ uint64 failed_sequence = 3;
+}
+
+message FailedEvents {
+ repeated FailedEvent failed_events = 1;
+}
+
+message FailedEvent {
+ string database = 1;
+ string view_name = 2;
+ uint64 failed_sequence = 3;
+ uint64 failure_count = 4;
+ string error_message = 5;
+}
+
+message ViewID {
+ string database = 1 [(validate.rules).string = {min_len: 1}];
+ string view_name = 2 [(validate.rules).string = {min_len: 1}];
+}
+
+message Views {
+ repeated View views = 1;
+}
+
+message View {
+ string database = 1;
+ string view_name = 2;
+ uint64 processed_sequence = 3;
+ google.protobuf.Timestamp event_timestamp = 4;
+ google.protobuf.Timestamp last_successful_spooler_run = 5;
+}
+
+message IdpID {
+ string id = 1 [(validate.rules).string = {min_len: 1}];
+}
+
+message Idp {
+ string id = 1;
+ IdpState state = 2;
+ google.protobuf.Timestamp creation_date = 3;
+ google.protobuf.Timestamp change_date = 4;
+ string name = 5;
+ IdpStylingType styling_type = 6;
+ oneof idp_config {
+ OidcIdpConfig oidc_config = 7;
+ }
+ uint64 sequence = 8;
+}
+
+message IdpUpdate {
+ string id = 1 [(validate.rules).string = {min_len: 1}];
+ string name = 2;
+ IdpStylingType styling_type = 3;
+}
+
+message OidcIdpConfig {
+ string client_id = 1;
+ string client_secret = 2;
+ string issuer = 3;
+ repeated string scopes = 4;
+}
+
+enum IdpStylingType {
+ IDPSTYLINGTYPE_UNSPECIFIED = 0;
+ IDPSTYLINGTYPE_GOOGLE = 1;
+}
+
+enum IdpState {
+ IDPCONFIGSTATE_UNSPECIFIED = 0;
+ IDPCONFIGSTATE_ACTIVE = 1;
+ IDPCONFIGSTATE_INACTIVE = 2;
+}
+
+enum OIDCMappingField {
+ OIDCMAPPINGFIELD_UNSPECIFIED = 0;
+ OIDCMAPPINGFIELD_PREFERRED_USERNAME = 1;
+ OIDCMAPPINGFIELD_EMAIL = 2;
+}
+
+message OidcIdpConfigCreate {
+ string name = 1 [(validate.rules).string = {min_len: 1, max_len: 200}];
+ IdpStylingType styling_type = 2;
+ string client_id = 3 [(validate.rules).string = {min_len: 1, max_len: 200}];
+ string client_secret = 4 [(validate.rules).string = {min_len: 1, max_len: 200}];
+ string issuer = 5 [(validate.rules).string = {min_len: 1, max_len: 200}];
+ repeated string scopes = 6;
+ OIDCMappingField idp_display_name_mapping = 7;
+ OIDCMappingField username_mapping = 8;
+}
+
+message OidcIdpConfigUpdate {
+ string idp_id = 1 [(validate.rules).string = {min_len: 1}];
+ string client_id = 2 [(validate.rules).string = {min_len: 1, max_len: 200}];
+ string client_secret = 3;
+ string issuer = 4 [(validate.rules).string = {min_len: 1, max_len: 200}];
+ repeated string scopes = 5;
+ OIDCMappingField idp_display_name_mapping = 6;
+ OIDCMappingField username_mapping = 7;
+}
+
+message IdpSearchResponse {
+ uint64 offset = 1;
+ uint64 limit = 2;
+ uint64 total_result = 3;
+ repeated IdpView result = 4;
+ uint64 processed_sequence = 5;
+ google.protobuf.Timestamp view_timestamp = 6;
+}
+
+message IdpView {
+ string id = 1;
+ IdpState state = 2;
+ google.protobuf.Timestamp creation_date = 3;
+ google.protobuf.Timestamp change_date = 4;
+ string name = 5;
+ IdpStylingType styling_type = 6;
+ oneof idp_config_view {
+ OidcIdpConfigView oidc_config = 7;
+ }
+ uint64 sequence = 8;
+}
+
+message OidcIdpConfigView {
+ string client_id = 1;
+ string issuer = 2;
+ repeated string scopes = 3;
+ OIDCMappingField idp_display_name_mapping = 4;
+ OIDCMappingField username_mapping = 5;
+}
+
+message IdpSearchRequest {
+ uint64 offset = 1;
+ uint64 limit = 2;
+ repeated IdpSearchQuery queries = 3;
+}
+
+message IdpSearchQuery {
+ IdpSearchKey key = 1 [(validate.rules).enum = {not_in: [0]}];
+ SearchMethod method = 2;
+ string value = 3;
+}
+
+enum IdpSearchKey {
+ IDPSEARCHKEY_UNSPECIFIED = 0;
+ IDPSEARCHKEY_IDP_CONFIG_ID = 1;
+ IDPSEARCHKEY_NAME = 2;
+}
+
+message DefaultLabelPolicy {
+ string primary_color = 1;
+ string secondary_color = 2;
+ google.protobuf.Timestamp creation_date = 3;
+ google.protobuf.Timestamp change_date = 4;
+ bool hide_login_name_suffix = 5;
+}
+
+message DefaultLabelPolicyUpdate {
+ string primary_color = 1;
+ string secondary_color = 2;
+ bool hide_login_name_suffix = 3;
+}
+
+message DefaultLabelPolicyView {
+ string primary_color = 1;
+ string secondary_color = 2;
+ google.protobuf.Timestamp creation_date = 3;
+ google.protobuf.Timestamp change_date = 4;
+ bool hide_login_name_suffix = 5;
+}
+
+message DefaultMailTemplate {
+ bytes template = 1;
+ google.protobuf.Timestamp creation_date = 2;
+ google.protobuf.Timestamp change_date = 3;
+}
+
+message DefaultMailTemplateUpdate {
+ bytes template = 1;
+}
+
+message DefaultMailTemplateView {
+ bytes template = 1;
+ google.protobuf.Timestamp creation_date = 2;
+ google.protobuf.Timestamp change_date = 3;
+}
+
+message DefaultMailText {
+ string mail_text_type = 1;
+ string language = 2;
+ string title = 3;
+ string pre_header = 4;
+ string subject = 5;
+ string greeting = 6;
+ string text = 7;
+ string button_text = 8;
+ google.protobuf.Timestamp creation_date = 9;
+ google.protobuf.Timestamp change_date = 10;
+}
+
+message DefaultMailTextUpdate {
+ string mail_text_type = 1;
+ string language = 2;
+ string title = 3;
+ string pre_header = 4;
+ string subject = 5;
+ string greeting = 6;
+ string text = 7;
+ string button_text = 8;
+}
+
+message DefaultMailTextsView{
+ repeated DefaultMailTextView texts = 1;
+}
+
+message DefaultMailTextView {
+ string mail_text_type = 1;
+ string language = 2;
+ string title = 3;
+ string pre_header = 4;
+ string subject = 5;
+ string greeting = 6;
+ string text = 7;
+ string button_text = 8;
+ google.protobuf.Timestamp creation_date = 9;
+ google.protobuf.Timestamp change_date = 10;
+}
+
+message DefaultLoginPolicy {
+ bool allow_username_password = 1;
+ bool allow_register = 2;
+ bool allow_external_idp = 3;
+ google.protobuf.Timestamp creation_date = 4;
+ google.protobuf.Timestamp change_date = 5;
+ bool force_mfa = 6;
+ PasswordlessType passwordless_type = 7;
+}
+
+message DefaultLoginPolicyRequest {
+ bool allow_username_password = 1;
+ bool allow_register = 2;
+ bool allow_external_idp = 3;
+ bool force_mfa = 4;
+ PasswordlessType passwordless_type = 5;
+}
+
+enum PasswordlessType {
+ PASSWORDLESSTYPE_NOT_ALLOWED = 0;
+ PASSWORDLESSTYPE_ALLOWED = 1;
+}
+
+message IdpProviderID {
+ string idp_config_id = 1 [(validate.rules).string = {min_len: 1}];
+}
+
+message DefaultLoginPolicyView {
+ bool allow_username_password = 1;
+ bool allow_register = 2;
+ bool allow_external_idp = 3;
+ google.protobuf.Timestamp creation_date = 4;
+ google.protobuf.Timestamp change_date = 5;
+ bool force_mfa = 6;
+ PasswordlessType passwordless_type = 7;
+}
+
+message IdpProviderView {
+ string idp_config_id = 1;
+ string name = 2;
+ IdpType type = 3;
+}
+
+enum IdpType {
+ IDPTYPE_UNSPECIFIED = 0;
+ IDPTYPE_OIDC = 1;
+ IDPTYPE_SAML = 2;
+}
+
+message IdpProviderSearchResponse {
+ uint64 offset = 1;
+ uint64 limit = 2;
+ uint64 total_result = 3;
+ repeated IdpProviderView result = 4;
+ uint64 processed_sequence = 5;
+ google.protobuf.Timestamp view_timestamp = 6;
+}
+
+message IdpProviderSearchRequest {
+ uint64 offset = 1;
+ uint64 limit = 2;
+}
+
+message SecondFactorsResult {
+ repeated SecondFactorType second_factors = 1;
+}
+
+message SecondFactor {
+ SecondFactorType second_factor = 1;
+}
+
+enum SecondFactorType {
+ SECONDFACTORTYPE_UNSPECIFIED = 0;
+ SECONDFACTORTYPE_OTP = 1;
+ SECONDFACTORTYPE_U2F = 2;
+}
+
+message MultiFactorsResult {
+ repeated MultiFactorType multi_factors = 1;
+}
+
+message MultiFactor {
+ MultiFactorType multi_factor = 1;
+}
+
+enum MultiFactorType {
+ MULTIFACTORTYPE_UNSPECIFIED = 0;
+ MULTIFACTORTYPE_U2F_WITH_PIN = 1;
+}
+
+message DefaultPasswordComplexityPolicy {
+ uint64 min_length = 1;
+ bool has_uppercase = 2;
+ bool has_lowercase = 3;
+ bool has_number = 4;
+ bool has_symbol = 5;
+ google.protobuf.Timestamp creation_date = 6;
+ google.protobuf.Timestamp change_date = 7;
+}
+
+message DefaultPasswordComplexityPolicyRequest {
+ uint64 min_length = 1;
+ bool has_uppercase = 2;
+ bool has_lowercase = 3;
+ bool has_number = 4;
+ bool has_symbol = 5;
+}
+
+message DefaultPasswordComplexityPolicyView {
+ uint64 min_length = 1;
+ bool has_uppercase = 2;
+ bool has_lowercase = 3;
+ bool has_number = 4;
+ bool has_symbol = 5;
+ google.protobuf.Timestamp creation_date = 6;
+ google.protobuf.Timestamp change_date = 7;
+}
+
+message DefaultPasswordAgePolicy {
+ uint64 max_age_days = 1;
+ uint64 expire_warn_days = 2;
+ google.protobuf.Timestamp creation_date = 3;
+ google.protobuf.Timestamp change_date = 4;
+}
+
+message DefaultPasswordAgePolicyRequest {
+ uint64 max_age_days = 1;
+ uint64 expire_warn_days = 2;
+}
+
+message DefaultPasswordAgePolicyView {
+ uint64 max_age_days = 1;
+ uint64 expire_warn_days = 2;
+ google.protobuf.Timestamp creation_date = 3;
+ google.protobuf.Timestamp change_date = 4;
+}
+
+message DefaultPasswordLockoutPolicy {
+ uint64 max_attempts = 1;
+ bool show_lockout_failure = 2;
+ google.protobuf.Timestamp creation_date = 3;
+ google.protobuf.Timestamp change_date = 4;
+}
+
+message DefaultPasswordLockoutPolicyRequest {
+ uint64 max_attempts = 1;
+ bool show_lockout_failure = 2;
+}
+
+message DefaultPasswordLockoutPolicyView {
+ uint64 max_attempts = 1;
+ bool show_lockout_failure = 2;
+ google.protobuf.Timestamp creation_date = 3;
+ google.protobuf.Timestamp change_date = 4;
+}
\ No newline at end of file
diff --git a/src/Zitadel.Api/proto/auth.proto b/src/Zitadel.Api/proto/auth.proto
new file mode 100644
index 00000000..bb5ca291
--- /dev/null
+++ b/src/Zitadel.Api/proto/auth.proto
@@ -0,0 +1,918 @@
+syntax = "proto3";
+
+import "google/api/annotations.proto";
+import "google/protobuf/empty.proto";
+import "google/protobuf/struct.proto";
+import "google/protobuf/timestamp.proto";
+import "validate/validate.proto";
+import "protoc-gen-swagger/options/annotations.proto";
+import "authoption/options.proto";
+import "proto/message.proto";
+
+package caos.zitadel.auth.api.v1;
+
+option go_package = "github.com/caos/zitadel/pkg/grpc/auth";
+
+option (grpc.gateway.protoc_gen_swagger.options.openapiv2_swagger) = {
+ info: {
+ title: "Auth API";
+ version: "0.1";
+ contact:{
+ url: "https://github.com/caos/zitadel/pkg/auth"
+ };
+ };
+
+ schemes: HTTPS;
+
+ consumes: "application/json";
+ consumes: "application/grpc";
+
+ produces: "application/json";
+ produces: "application/grpc";
+};
+
+service AuthService {
+ // Readiness
+ rpc Healthz(google.protobuf.Empty) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ get: "/healthz"
+ };
+ }
+
+ // Authorization
+ rpc GetMyUserSessions(google.protobuf.Empty) returns (UserSessionViews) {
+ option (google.api.http) = {
+ get: "/users/me/sessions"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "authenticated"
+ };
+ }
+
+ //User
+ rpc GetMyUser(google.protobuf.Empty) returns (UserView) {
+ option (google.api.http) = {
+ get: "/users/me"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "authenticated"
+ };
+ }
+
+ rpc GetMyUserProfile(google.protobuf.Empty) returns (UserProfileView) {
+ option (google.api.http) = {
+ get: "/users/me/profile"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "authenticated"
+ };
+ }
+
+ rpc UpdateMyUserProfile(UpdateUserProfileRequest) returns (UserProfile) {
+ option (google.api.http) = {
+ put: "/users/me/profile"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "authenticated"
+ };
+ }
+
+ rpc ChangeMyUserName(ChangeUserNameRequest) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ put: "/users/me/username"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "authenticated"
+ };
+ }
+
+ rpc GetMyUserEmail(google.protobuf.Empty) returns (UserEmailView) {
+ option (google.api.http) = {
+ get: "/users/me/email"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "authenticated"
+ };
+ }
+
+ rpc ChangeMyUserEmail(UpdateUserEmailRequest) returns (UserEmail) {
+ option (google.api.http) = {
+ put: "/users/me/email"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "authenticated"
+ };
+ }
+
+ rpc VerifyMyUserEmail(VerifyMyUserEmailRequest) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ post: "/users/me/email/_verify"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "authenticated"
+ };
+ }
+
+ rpc ResendMyEmailVerificationMail(google.protobuf.Empty) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ post: "/users/me/email/_resendverification"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "authenticated"
+ };
+ }
+
+ rpc GetMyUserPhone(google.protobuf.Empty) returns (UserPhoneView) {
+ option (google.api.http) = {
+ get: "/users/me/phone"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "authenticated"
+ };
+ }
+
+ rpc ChangeMyUserPhone(UpdateUserPhoneRequest) returns (UserPhone) {
+ option (google.api.http) = {
+ put: "/users/me/phone"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "authenticated"
+ };
+ }
+
+ rpc RemoveMyUserPhone(google.protobuf.Empty) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ delete: "/users/me/phone"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "authenticated"
+ };
+ }
+
+ rpc VerifyMyUserPhone(VerifyUserPhoneRequest) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ post: "/users/me/phone/_verify"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "authenticated"
+ };
+ }
+
+ rpc ResendMyPhoneVerificationCode(google.protobuf.Empty) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ post: "/users/me/phone/_resendverification"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "authenticated"
+ };
+ }
+
+ rpc GetMyUserAddress(google.protobuf.Empty) returns (UserAddressView) {
+ option (google.api.http) = {
+ get: "/users/me/address"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "authenticated"
+ };
+ }
+
+ rpc GetMyUserChanges(ChangesRequest) returns (Changes) {
+ option (google.api.http) = {
+ get: "/users/me/changes"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "authenticated"
+ };
+ }
+
+ rpc UpdateMyUserAddress(UpdateUserAddressRequest) returns (UserAddress) {
+ option (google.api.http) = {
+ put: "/users/me/address"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "authenticated"
+ };
+ }
+
+ rpc GetMyMfas(google.protobuf.Empty) returns (MultiFactors) {
+ option (google.api.http) = {
+ get: "/users/me/mfas"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "authenticated"
+ };
+ }
+
+ //Password
+ rpc ChangeMyPassword(PasswordChange) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ put: "/users/me/passwords/_change"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "authenticated"
+ };
+ }
+
+ rpc GetMyPasswordComplexityPolicy(google.protobuf.Empty) returns (PasswordComplexityPolicy) {
+ option (google.api.http) = {
+ get: "/policies/passwords/complexity"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "authenticated"
+ };
+ }
+
+ //ExternalIDP
+ rpc SearchMyExternalIDPs(ExternalIDPSearchRequest) returns (ExternalIDPSearchResponse) {
+ option (google.api.http) = {
+ post: "/users/me/externalidps/_search"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "authenticated"
+ };
+ }
+
+ rpc RemoveMyExternalIDP(ExternalIDPRemoveRequest) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ delete: "/users/me/externalidps/{idp_config_id}/{external_user_id}"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "authenticated"
+ };
+ }
+
+ // MFA
+ rpc AddMfaOTP(google.protobuf.Empty) returns (MfaOtpResponse) {
+ option (google.api.http) = {
+ post: "/users/me/mfas/otp"
+ body: "*"
+ };
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "authenticated"
+ };
+ }
+
+ rpc VerifyMfaOTP(VerifyMfaOtp) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ put: "/users/me/mfas/otp/_verify"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "authenticated"
+ };
+ }
+
+ rpc RemoveMfaOTP(google.protobuf.Empty) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ delete: "/users/me/mfas/otp"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "authenticated"
+ };
+ }
+
+ rpc AddMyMfaU2F(google.protobuf.Empty) returns (WebAuthNResponse) {
+ option (google.api.http) = {
+ post: "/users/me/mfas/u2f"
+ body: "*"
+ };
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "authenticated"
+ };
+ }
+
+ rpc VerifyMyMfaU2F(VerifyWebAuthN) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ put: "/users/me/mfas/u2f/_verify"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "authenticated"
+ };
+ }
+
+ rpc RemoveMyMfaU2F(WebAuthNTokenID) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ delete: "/users/me/mfas/u2f/{id}"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "authenticated"
+ };
+ }
+
+ rpc GetMyPasswordless(google.protobuf.Empty) returns (WebAuthNTokens) {
+ option (google.api.http) = {
+ get: "/users/me/passwordless"
+ };
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "authenticated"
+ };
+ }
+
+ rpc AddMyPasswordless(google.protobuf.Empty) returns (WebAuthNResponse) {
+ option (google.api.http) = {
+ post: "/users/me/passwordless"
+ body: "*"
+ };
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "authenticated"
+ };
+ }
+
+ rpc VerifyMyPasswordless(VerifyWebAuthN) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ put: "/users/me/passwordless/_verify"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "authenticated"
+ };
+ }
+
+ rpc RemoveMyPasswordless(WebAuthNTokenID) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ delete: "/users/me/passwordless/{id}"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "authenticated"
+ };
+ }
+
+ rpc SearchMyUserGrant(UserGrantSearchRequest) returns (UserGrantSearchResponse) {
+ option (google.api.http) = {
+ post: "/usergrants/me/_search"
+ body: "*"
+ };
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "authenticated"
+ };
+ }
+
+ rpc SearchMyProjectOrgs(MyProjectOrgSearchRequest) returns (MyProjectOrgSearchResponse) {
+ option (google.api.http) = {
+ post: "/global/projectorgs/_search"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "authenticated"
+ };
+ }
+
+ //Permission
+ rpc GetMyZitadelPermissions(google.protobuf.Empty) returns (MyPermissions) {
+ option (google.api.http) = {
+ get: "/permissions/zitadel/me"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "authenticated"
+ };
+ }
+
+ rpc GetMyProjectPermissions(google.protobuf.Empty) returns (MyPermissions) {
+ option (google.api.http) = {
+ get: "/permissions/me"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "authenticated"
+ };
+ }
+
+ rpc SearchMyUserMemberships(UserMembershipSearchRequest) returns (UserMembershipSearchResponse) {
+ option (google.api.http) = {
+ post: "/users/me/memberships/_search"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "authenticated"
+ };
+ }
+}
+
+message UserSessionViews {
+ repeated UserSessionView user_sessions = 1;
+}
+
+message UserSessionView {
+ string id = 1;
+ string agent_id = 2;
+ UserSessionState auth_state = 3;
+ string user_id = 4;
+ string user_name = 5;
+ uint64 sequence = 6;
+ string login_name = 7;
+ string display_name = 8;
+}
+
+enum UserSessionState {
+ USERSESSIONSTATE_UNSPECIFIED = 0;
+ USERSESSIONSTATE_ACTIVE = 1;
+ USERSESSIONSTATE_TERMINATED = 2;
+}
+
+message UserView {
+ string id = 1;
+ UserState state = 2;
+ google.protobuf.Timestamp creation_date = 3;
+ google.protobuf.Timestamp change_date = 4;
+ uint64 sequence = 5;
+ repeated string login_names = 6;
+ string preferred_login_name = 7;
+ google.protobuf.Timestamp last_login = 8;
+ string resource_owner = 9;
+ string user_name = 10;
+
+ oneof user {
+ option (validate.required) = true;
+
+ HumanView human = 11;
+ MachineView machine = 12;
+ }
+}
+
+message MachineView {
+ google.protobuf.Timestamp last_key_added = 1;
+
+ string name = 2;
+ string description = 3;
+}
+
+message MachineKeyView {
+ string id = 1;
+ MachineKeyType type = 2;
+ uint64 sequence = 3;
+
+ google.protobuf.Timestamp creation_date = 4;
+ google.protobuf.Timestamp expiration_date = 5;
+}
+
+enum MachineKeyType {
+ MACHINEKEY_UNSPECIFIED = 0;
+ MACHINEKEY_JSON = 1;
+}
+
+message HumanView {
+ google.protobuf.Timestamp password_changed = 1;
+ string first_name = 2;
+ string last_name = 3;
+ string display_name = 4;
+ string nick_name = 5;
+ string preferred_language = 6;
+ Gender gender = 7;
+ string email = 8;
+ bool is_email_verified = 9;
+ string phone = 10;
+ bool is_phone_verified = 11;
+ string country = 12;
+ string locality = 13;
+ string postal_code = 14;
+ string region = 15;
+ string street_address = 16;
+}
+
+enum UserState {
+ USERSTATE_UNSPECIFIED = 0;
+ USERSTATE_ACTIVE = 1;
+ USERSTATE_INACTIVE = 2;
+ USERSTATE_DELETED = 3;
+ USERSTATE_LOCKED = 4;
+ USERSTATE_SUSPEND = 5;
+ USERSTATE_INITIAL = 6;
+}
+
+enum Gender {
+ GENDER_UNSPECIFIED = 0;
+ GENDER_FEMALE = 1;
+ GENDER_MALE = 2;
+ GENDER_DIVERSE = 3;
+}
+
+message UserProfile {
+ string id = 1;
+ string first_name = 2;
+ string last_name = 3;
+ string nick_name = 4;
+ string display_name = 5;
+ string preferred_language = 6;
+ Gender gender = 7;
+ uint64 sequence = 8;
+ google.protobuf.Timestamp creation_date = 9;
+ google.protobuf.Timestamp change_date = 10;
+}
+
+message UserProfileView {
+ string id = 1;
+ string first_name = 2;
+ string last_name = 3;
+ string nick_name = 4;
+ string display_name = 5;
+ string preferred_language = 6;
+ Gender gender = 7;
+ uint64 sequence = 8;
+ google.protobuf.Timestamp creation_date = 9;
+ google.protobuf.Timestamp change_date = 10;
+ repeated string login_names = 11;
+ string preferred_login_name = 12;
+}
+
+message UpdateUserProfileRequest {
+ string first_name = 1 [(validate.rules).string = {min_len: 1, max_len: 200}];
+ string last_name = 2 [(validate.rules).string = {min_len: 1, max_len: 200}];
+ string nick_name = 3 [(validate.rules).string.max_len = 200];
+ string preferred_language = 4 [(validate.rules).string = {min_len: 1, max_len: 200}];
+ Gender gender = 5;
+}
+
+message ChangeUserNameRequest {
+ string user_name = 1 [(validate.rules).string.pattern = "^[^[:space:]]{1,200}$"];
+}
+
+message UserEmail {
+ string id = 1;
+ string email = 2;
+ bool isEmailVerified = 3;
+ uint64 sequence = 4;
+ google.protobuf.Timestamp creation_date = 5;
+ google.protobuf.Timestamp change_date = 6;
+}
+
+message UserEmailView {
+ string id = 1;
+ string email = 2;
+ bool isEmailVerified = 3;
+ uint64 sequence = 4;
+ google.protobuf.Timestamp creation_date = 5;
+ google.protobuf.Timestamp change_date = 6;
+}
+
+message VerifyMyUserEmailRequest {
+ string code = 1 [(validate.rules).string = {min_len: 1, max_len: 200}];
+}
+
+message UpdateUserEmailRequest {
+ string email = 1 [(validate.rules).string = {min_len: 1, max_len: 200}];
+}
+
+message UserPhone {
+ string id = 1;
+ string phone = 2;
+ bool is_phone_verified = 3;
+ uint64 sequence = 4;
+ google.protobuf.Timestamp creation_date = 5;
+ google.protobuf.Timestamp change_date = 6;
+}
+
+message UserPhoneView {
+ string id = 1;
+ string phone = 2;
+ bool is_phone_verified = 3;
+ uint64 sequence = 4;
+ google.protobuf.Timestamp creation_date = 5;
+ google.protobuf.Timestamp change_date = 6;
+}
+
+message UpdateUserPhoneRequest {
+ string phone = 1 [(validate.rules).string = {min_len: 1, max_len: 20}];
+}
+
+message VerifyUserPhoneRequest {
+ string code = 1 [(validate.rules).string = {min_len: 1, max_len: 200}];
+}
+
+message UserAddress {
+ string id = 1;
+ string country = 2;
+ string locality = 3;
+ string postal_code = 4;
+ string region = 5;
+ string street_address = 6;
+ uint64 sequence = 7;
+ google.protobuf.Timestamp creation_date = 8;
+ google.protobuf.Timestamp change_date = 9;
+}
+
+message UserAddressView {
+ string id = 1;
+ string country = 2;
+ string locality = 3;
+ string postal_code = 4;
+ string region = 5;
+ string street_address = 6;
+ uint64 sequence = 7;
+ google.protobuf.Timestamp creation_date = 8;
+ google.protobuf.Timestamp change_date = 9;
+}
+
+message UpdateUserAddressRequest {
+ string country = 1 [(validate.rules).string = {max_len: 200}];
+ string locality = 2 [(validate.rules).string = {max_len: 200}];
+ string postal_code = 3 [(validate.rules).string = {max_len: 200}];
+ string region = 4 [(validate.rules).string = {max_len: 200}];
+ string street_address = 5 [(validate.rules).string = {max_len: 200}];
+}
+
+message PasswordChange {
+ string old_password = 1 [(validate.rules).string = {min_len: 1, max_len: 72}];
+ string new_password = 2 [(validate.rules).string = {min_len: 1, max_len: 72}];
+}
+
+enum MfaType {
+ MFATYPE_UNSPECIFIED = 0;
+ MFATYPE_OTP = 1;
+ MFATYPE_U2F = 2;
+}
+
+message VerifyMfaOtp {
+ string code = 1 [(validate.rules).string = {min_len: 1}];
+}
+
+message MultiFactors {
+ repeated MultiFactor mfas = 1;
+}
+
+message MultiFactor {
+ MfaType type = 1;
+ MFAState state = 2;
+ string attribute = 3;
+ string id = 4;
+}
+
+message MfaOtpResponse {
+ string user_id = 1;
+ string url = 2;
+ string secret = 3;
+ MFAState state = 4;
+}
+
+message WebAuthNTokens {
+ repeated WebAuthNToken tokens = 1;
+}
+
+message WebAuthNToken {
+ string id = 1;
+ string name = 2;
+ MFAState state = 3;
+}
+
+message WebAuthNResponse {
+ string id = 1;
+ bytes public_key = 2;
+ MFAState state = 3;
+}
+
+message VerifyWebAuthN {
+ bytes public_key_credential = 1;
+ string token_name = 2;
+}
+
+message WebAuthNTokenID {
+ string id = 1;
+}
+
+enum MFAState {
+ MFASTATE_UNSPECIFIED = 0;
+ MFASTATE_NOT_READY = 1;
+ MFASTATE_READY = 2;
+ MFASTATE_REMOVED = 3;
+}
+
+message UserGrantSearchRequest {
+ uint64 offset = 1;
+ uint64 limit = 2;
+ UserGrantSearchKey sorting_column = 3 [(validate.rules).enum = {not_in: [0]}];;
+ bool asc = 4;
+ repeated UserGrantSearchQuery queries = 5;
+}
+
+message UserGrantSearchQuery {
+ UserGrantSearchKey key = 1 [(validate.rules).enum = {not_in: [0]}];;
+ SearchMethod method = 2;
+ string value = 3;
+}
+
+enum UserGrantSearchKey {
+ UserGrantSearchKey_UNKNOWN = 0;
+ UserGrantSearchKey_ORG_ID = 1;
+ UserGrantSearchKey_PROJECT_ID = 2;
+}
+
+message UserGrantSearchResponse {
+ uint64 offset = 1;
+ uint64 limit = 2;
+ uint64 total_result = 3;
+ repeated UserGrantView result = 4;
+ uint64 processed_sequence = 5;
+ google.protobuf.Timestamp view_timestamp = 6;
+}
+
+message UserGrantView {
+ string OrgId = 1;
+ string ProjectId = 2;
+ string UserId = 3;
+ repeated string Roles = 4;
+ string OrgName = 5;
+ string GrantId = 6;
+}
+
+message MyProjectOrgSearchRequest {
+ uint64 offset = 1;
+ uint64 limit = 2;
+ bool asc = 4;
+ repeated MyProjectOrgSearchQuery queries = 5;
+}
+
+message MyProjectOrgSearchQuery {
+ MyProjectOrgSearchKey key = 1 [(validate.rules).enum = {not_in: [0]}];;
+ SearchMethod method = 2;
+ string value = 3;
+}
+
+enum MyProjectOrgSearchKey {
+ MYPROJECTORGSEARCHKEY_UNSPECIFIED = 0;
+ MYPROJECTORGSEARCHKEY_ORG_NAME = 1;
+}
+
+message MyProjectOrgSearchResponse {
+ uint64 offset = 1;
+ uint64 limit = 2;
+ uint64 total_result = 3;
+ repeated Org result = 4;
+}
+
+message Org {
+ string id = 1;
+ string name = 2;
+}
+
+message MyPermissions {
+ repeated string permissions = 1;
+}
+
+enum SearchMethod {
+ SEARCHMETHOD_EQUALS = 0;
+ SEARCHMETHOD_STARTS_WITH = 1;
+ SEARCHMETHOD_CONTAINS = 2;
+ SEARCHMETHOD_EQUALS_IGNORE_CASE = 3;
+ SEARCHMETHOD_STARTS_WITH_IGNORE_CASE = 4;
+ SEARCHMETHOD_CONTAINS_IGNORE_CASE = 5;
+}
+
+message ChangesRequest {
+ uint64 limit = 1;
+ uint64 sequence_offset = 2;
+ bool asc = 3;
+}
+
+message Changes {
+ repeated Change changes = 1;
+ uint64 offset = 2;
+ uint64 limit = 3;
+}
+
+message Change {
+ google.protobuf.Timestamp change_date = 1;
+ caos.zitadel.api.v1.LocalizedMessage event_type = 2;
+ uint64 sequence = 3;
+ string editor_id = 4;
+ string editor = 5;
+ google.protobuf.Struct data = 6;
+}
+
+message PasswordComplexityPolicy {
+ string id = 1;
+ string description = 2;
+ google.protobuf.Timestamp creation_date = 3;
+ google.protobuf.Timestamp change_date = 4;
+ uint64 min_length = 5;
+ bool has_lowercase = 6;
+ bool has_uppercase = 7;
+ bool has_number = 8;
+ bool has_symbol = 9;
+ uint64 sequence = 10;
+ bool is_default = 11;
+}
+
+message ExternalIDPResponse {
+ string idp_config_id = 1;
+ string user_id = 2;
+ string display_name = 3;
+}
+
+message ExternalIDPRemoveRequest {
+ string idp_config_id = 1;
+ string external_user_id = 2;
+}
+
+message ExternalIDPSearchRequest {
+ uint64 offset = 1;
+ uint64 limit = 2;
+}
+
+message ExternalIDPSearchResponse {
+ uint64 offset = 1;
+ uint64 limit = 2;
+ uint64 total_result = 3;
+ repeated ExternalIDPView result = 4;
+ uint64 processed_sequence = 5;
+ google.protobuf.Timestamp view_timestamp = 6;
+}
+
+message ExternalIDPView {
+ string user_id = 1;
+ string idp_config_id = 2;
+ string external_user_id = 3;
+ string idp_name = 4;
+ string external_user_display_name = 5;
+ google.protobuf.Timestamp creation_date = 6;
+ google.protobuf.Timestamp change_date = 7;
+}
+
+
+message UserMembershipSearchResponse {
+ uint64 offset = 1;
+ uint64 limit = 2;
+ uint64 total_result = 3;
+ repeated UserMembershipView result = 4;
+ uint64 processed_sequence = 5;
+ google.protobuf.Timestamp view_timestamp = 6;
+}
+
+message UserMembershipSearchRequest {
+ uint64 offset = 1;
+ uint64 limit = 2;
+ repeated UserMembershipSearchQuery queries = 3;
+}
+
+message UserMembershipSearchQuery {
+ UserMembershipSearchKey key = 1 [(validate.rules).enum = {not_in: [0]}];
+ SearchMethod method = 2 [(validate.rules).enum = {in: [0]}];
+ string value = 3;
+}
+
+enum UserMembershipSearchKey {
+ USERMEMBERSHIPSEARCHKEY_UNSPECIFIED = 0;
+ USERMEMBERSHIPSEARCHKEY_TYPE = 1;
+ USERMEMBERSHIPSEARCHKEY_OBJECT_ID = 2;
+}
+
+message UserMembershipView {
+ string user_id = 1;
+ MemberType member_type = 2;
+ string aggregate_id = 3;
+ string object_id = 4;
+ repeated string roles = 5;
+ string display_name = 6;
+ google.protobuf.Timestamp creation_date = 7;
+ google.protobuf.Timestamp change_date = 8;
+ uint64 sequence = 9;
+ string resource_owner = 10;
+}
+
+enum MemberType {
+ MEMBERTYPE_UNSPECIFIED = 0;
+ MEMBERTYPE_ORGANISATION = 1;
+ MEMBERTYPE_PROJECT = 2;
+ MEMBERTYPE_PROJECT_GRANT = 3;
+}
diff --git a/src/Zitadel.Api/proto/management.proto b/src/Zitadel.Api/proto/management.proto
new file mode 100644
index 00000000..f96c1598
--- /dev/null
+++ b/src/Zitadel.Api/proto/management.proto
@@ -0,0 +1,3767 @@
+syntax = "proto3";
+
+import "google/api/annotations.proto";
+import "google/protobuf/empty.proto";
+import "google/protobuf/struct.proto";
+import "google/protobuf/timestamp.proto";
+import "google/protobuf/duration.proto";
+import "protoc-gen-swagger/options/annotations.proto";
+import "validate/validate.proto";
+import "authoption/options.proto";
+import "proto/message.proto";
+
+package caos.zitadel.management.api.v1;
+
+option go_package = "github.com/caos/zitadel/pkg/grpc/management";
+
+option (grpc.gateway.protoc_gen_swagger.options.openapiv2_swagger) = {
+ info: {
+ title: "Management API";
+ version: "0.1";
+ contact:{
+ url: "https://github.com/caos/zitadel/pkg/management"
+ };
+ };
+
+ schemes: HTTPS;
+
+ consumes: "application/json";
+ consumes: "application/grpc";
+
+ produces: "application/json";
+ produces: "application/grpc";
+};
+
+// All requests are based on your context if nothing other is specified
+// Requests which have /me in the url get the parameter from the context
+service ManagementService {
+
+ //READINESS
+ rpc Healthz(google.protobuf.Empty) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ get: "/healthz"
+ };
+ }
+
+ rpc GetZitadelDocs(google.protobuf.Empty) returns (ZitadelDocs) {
+ option (google.api.http) = {
+ get: "/zitadel/docs"
+ };
+ }
+
+ // GetIam returns some needed settings of the iam (Global Organisation ID, Zitadel Project ID)
+ rpc GetIam(google.protobuf.Empty) returns (Iam) {
+ option (google.api.http) = {
+ get: "/iam"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "authenticated"
+ };
+ }
+
+ rpc IsUserUnique(UniqueUserRequest) returns (UniqueUserResponse) {
+ option (google.api.http) = {
+ get: "/users/_isunique"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "user.read"
+ };
+ }
+
+ rpc GetUserByID(UserID) returns (UserView) {
+ option (google.api.http) = {
+ get: "/users/{id}"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "user.read"
+ };
+ }
+
+ // GetUserByLoginNameGlobal returns User, global search is overall organisations
+ rpc GetUserByLoginNameGlobal(LoginName) returns (UserView) {
+ option (google.api.http) = {
+ get: "/global/users/_byloginname"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "user.global.read"
+ };
+ }
+
+ // Limit should always be set, there is a default limit set by the service
+ rpc SearchUsers(UserSearchRequest) returns (UserSearchResponse) {
+ option (google.api.http) = {
+ post: "/users/_search"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "user.read"
+ };
+ }
+
+ rpc CreateUser(CreateUserRequest) returns (UserResponse) {
+ option (google.api.http) = {
+ post: "/users"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "user.write"
+ };
+ }
+
+ rpc ImportHuman(ImportHumanRequest) returns (UserResponse) {
+ option (google.api.http) = {
+ post: "/users/humans/_import"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "user.write"
+ };
+ }
+
+ rpc DeactivateUser(UserID) returns (UserResponse) {
+ option (google.api.http) = {
+ put: "/users/{id}/_deactivate"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "user.write"
+ };
+ }
+
+ rpc ReactivateUser(UserID) returns (UserResponse) {
+ option (google.api.http) = {
+ put: "/users/{id}/_reactivate"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "user.write"
+ };
+ }
+
+ rpc LockUser(UserID) returns (UserResponse) {
+ option (google.api.http) = {
+ put: "/users/{id}/_lock"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "user.write"
+ };
+ }
+
+ rpc UnlockUser(UserID) returns (UserResponse) {
+ option (google.api.http) = {
+ put: "/users/{id}/_unlock"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "user.write"
+ };
+ }
+
+ rpc DeleteUser(UserID) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ delete: "/users/{id}"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "user.delete"
+ };
+ }
+
+ // UserChanges returns the event stream of the user object
+ rpc UserChanges(ChangeRequest) returns (Changes) {
+ option (google.api.http) = {
+ get: "/users/{id}/changes"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "user.read"
+ };
+ }
+
+ rpc AddMachineKey(AddMachineKeyRequest) returns (AddMachineKeyResponse) {
+ option (google.api.http) = {
+ post: "/users/{user_id}/keys"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "user.write"
+ };
+ }
+
+ rpc DeleteMachineKey(MachineKeyIDRequest) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ delete: "/users/{user_id}/keys/{key_id}"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "user.write"
+ };
+ }
+
+ rpc SearchMachineKeys(MachineKeySearchRequest) returns (MachineKeySearchResponse) {
+ option (google.api.http) = {
+ post: "/users/{user_id}/keys/_search"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "user.read"
+ };
+ }
+
+ rpc GetMachineKey(MachineKeyIDRequest) returns (MachineKeyView) {
+ option (google.api.http) = {
+ get: "/users/{user_id}/keys/{key_id}"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "user.read"
+ };
+ }
+
+ rpc GetUserProfile(UserID) returns (UserProfileView) {
+ option (google.api.http) = {
+ get: "/users/{id}/profile"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "user.read"
+ };
+ }
+
+ rpc UpdateUserProfile(UpdateUserProfileRequest) returns (UserProfile) {
+ option (google.api.http) = {
+ put: "/users/{id}/profile"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "user.write"
+ };
+ }
+
+ rpc GetUserEmail(UserID) returns (UserEmailView) {
+ option (google.api.http) = {
+ get: "/users/{id}/email"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "user.read"
+ };
+ }
+
+ rpc ChangeUserUserName(UpdateUserUserNameRequest) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ get: "/users/{id}/username"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "user.write"
+ };
+ }
+
+ rpc ChangeUserEmail(UpdateUserEmailRequest) returns (UserEmail) {
+ option (google.api.http) = {
+ put: "/users/{id}/email"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "user.write"
+ };
+ }
+
+ rpc ResendEmailVerificationMail(UserID) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ post: "/users/{id}/email/_resendverification"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "user.write"
+ };
+ }
+
+ rpc GetUserPhone(UserID) returns (UserPhoneView) {
+ option (google.api.http) = {
+ get: "/users/{id}/phone"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "user.read"
+ };
+ }
+
+ rpc ChangeUserPhone(UpdateUserPhoneRequest) returns (UserPhone) {
+ option (google.api.http) = {
+ put: "/users/{id}/phone"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "user.write"
+ };
+ }
+
+ rpc RemoveUserPhone(UserID) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ delete: "/users/{id}/phone"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "user.write"
+ };
+ }
+
+ rpc ResendPhoneVerificationCode(UserID) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ post: "/users/{id}/phone/_resendverification"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "user.write"
+ };
+ }
+
+ rpc GetUserAddress(UserID) returns (UserAddressView) {
+ option (google.api.http) = {
+ get: "/users/{id}/address"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "user.read"
+ };
+ }
+
+ rpc UpdateUserAddress(UpdateUserAddressRequest) returns (UserAddress) {
+ option (google.api.http) = {
+ put: "/users/{id}/address"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "user.write"
+ };
+ }
+
+ rpc UpdateUserMachine(UpdateMachineRequest) returns (MachineResponse) {
+ option (google.api.http) = {
+ put: "/users/{id}/machine"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "user.write"
+ };
+ }
+
+ rpc SearchUserExternalIDPs(ExternalIDPSearchRequest) returns (ExternalIDPSearchResponse) {
+ option (google.api.http) = {
+ post: "/users/{user_id}/externalidps/_search"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "user.read"
+ };
+ }
+
+ rpc RemoveExternalIDP(ExternalIDPRemoveRequest) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ delete: "/users/{user_id}/externalidps/{idp_config_id}/{external_user_id}"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "user.write"
+ };
+ }
+
+ rpc GetUserMfas(UserID) returns (UserMultiFactors) {
+ option (google.api.http) = {
+ get: "/users/{id}/mfas"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "user.read"
+ };
+ }
+
+ rpc RemoveMfaOTP(UserID) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ delete: "/users/{id}/mfas/otp"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "user.write"
+ };
+ }
+
+ rpc RemoveMfaU2F(WebAuthNTokenID) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ delete: "/users/{user_id}/mfas/u2f/{id}"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "user.write"
+ };
+ }
+
+ rpc GetPasswordless(UserID) returns (WebAuthNTokens) {
+ option (google.api.http) = {
+ get: "/users/{id}/passwordless"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "user.read"
+ };
+ }
+
+ rpc RemovePasswordless(WebAuthNTokenID) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ delete: "/users/{user_id}/passwordless"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "user.write"
+ };
+ }
+
+ // Sends an Notification (Email/SMS) with a password reset Link
+ rpc SendSetPasswordNotification(SetPasswordNotificationRequest) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ post: "/users/{id}/password/_sendsetnotification"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "user.write"
+ };
+ }
+
+ // A Manager is only allowed to set an initial password, on the next login the user has to change his password
+ rpc SetInitialPassword(PasswordRequest) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ post: "/users/{id}/password/_initialize"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "user.write"
+ };
+ }
+
+ rpc ResendInitialMail(InitialMailRequest) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ post: "/users/{id}/_resendinitialisation"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "user.write"
+ };
+ }
+
+ rpc SearchUserMemberships(UserMembershipSearchRequest) returns (UserMembershipSearchResponse) {
+ option (google.api.http) = {
+ post: "/users/{user_id}/memberships/_search"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "user.membership.read"
+ };
+ }
+
+ rpc CreateOrg(OrgCreateRequest) returns (Org) {
+ option (google.api.http) = {
+ post: "/orgs"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "org.create"
+ };
+ }
+
+ // OrgChanges returns the event stream of the org object
+ rpc OrgChanges(ChangeRequest) returns (Changes) {
+ option (google.api.http) = {
+ get: "/orgs/{id}/changes"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "org.read"
+ };
+ }
+
+ rpc GetMyOrg(google.protobuf.Empty) returns (OrgView) {
+ option (google.api.http) = {
+ get: "/orgs/me"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "org.read"
+ };
+ }
+
+ // search a organisation by its domain overall organisations
+ rpc GetOrgByDomainGlobal(Domain) returns (OrgView) {
+ option (google.api.http) = {
+ get: "/global/orgs/_bydomain"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "org.global.read"
+ };
+ }
+
+ rpc DeactivateMyOrg(google.protobuf.Empty) returns (Org) {
+ option (google.api.http) = {
+ put: "/orgs/me/_deactivate"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "org.write"
+ };
+ }
+
+ rpc ReactivateMyOrg(google.protobuf.Empty) returns (Org) {
+ option (google.api.http) = {
+ put: "/orgs/me/_reactivate"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "org.write"
+ };
+ }
+
+ rpc SearchMyOrgDomains(OrgDomainSearchRequest) returns (OrgDomainSearchResponse) {
+ option (google.api.http) = {
+ post: "/orgs/me/domains/_search"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "org.read"
+ };
+ }
+
+ rpc AddMyOrgDomain(AddOrgDomainRequest) returns (OrgDomain) {
+ option (google.api.http) = {
+ post: "/orgs/me/domains"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "org.write"
+ };
+ }
+
+ rpc GenerateMyOrgDomainValidation(OrgDomainValidationRequest) returns (OrgDomainValidationResponse) {
+ option (google.api.http) = {
+ post: "/orgs/me/domains/{domain}/validation/create"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "org.write"
+ };
+ }
+
+ rpc ValidateMyOrgDomain(ValidateOrgDomainRequest) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ post: "/orgs/me/domains/{domain}/validation/check"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "org.write"
+ };
+ }
+
+ rpc SetMyPrimaryOrgDomain(PrimaryOrgDomainRequest) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ post: "/orgs/me/domains/{domain}/_primary"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "org.write"
+ };
+ }
+
+ rpc RemoveMyOrgDomain(RemoveOrgDomainRequest) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ delete: "/orgs/me/domains/{domain}"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "org.write"
+ };
+ }
+
+ rpc GetMyOrgIamPolicy(google.protobuf.Empty) returns (OrgIamPolicyView) {
+ option (google.api.http) = {
+ get: "/orgs/me/iampolicy"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "authenticated"
+ };
+ }
+
+ rpc GetOrgMemberRoles(google.protobuf.Empty) returns (OrgMemberRoles) {
+ option (google.api.http) = {
+ get: "/orgs/members/roles"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "org.member.read"
+ };
+ }
+
+ rpc AddMyOrgMember(AddOrgMemberRequest) returns (OrgMember) {
+ option (google.api.http) = {
+ post: "/orgs/me/members"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "org.member.write"
+ };
+ }
+
+ rpc ChangeMyOrgMember(ChangeOrgMemberRequest) returns (OrgMember) {
+ option (google.api.http) = {
+ put: "/orgs/me/members/{user_id}"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "org.member.write"
+ };
+ }
+
+ rpc RemoveMyOrgMember(RemoveOrgMemberRequest) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ delete: "/orgs/me/members/{user_id}"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "org.member.delete"
+ };
+ }
+
+ rpc SearchMyOrgMembers(OrgMemberSearchRequest) returns (OrgMemberSearchResponse) {
+ option (google.api.http) = {
+ post: "/orgs/me/members/_search"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "org.member.read"
+ };
+ }
+
+ // ProjectChanges returns the event stream of the project object
+ rpc ProjectChanges(ChangeRequest) returns (Changes) {
+ option (google.api.http) = {
+ get: "/projects/{id}/changes"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "project.read"
+ };
+ }
+
+ rpc SearchProjects(ProjectSearchRequest) returns (ProjectSearchResponse) {
+ option (google.api.http) = {
+ post: "/projects/_search"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "project.read"
+ };
+ }
+
+ rpc ProjectByID(ProjectID) returns (ProjectView) {
+ option (google.api.http) = {
+ get: "/projects/{id}"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "project.read"
+ check_field_name: "Id"
+ };
+ }
+
+ rpc CreateProject(ProjectCreateRequest) returns (Project) {
+ option (google.api.http) = {
+ post: "/projects"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "project.create"
+ };
+ }
+
+ rpc UpdateProject(ProjectUpdateRequest) returns (Project) {
+ option (google.api.http) = {
+ put: "/projects/{id}"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "project.write"
+ check_field_name: "Id"
+ };
+ }
+
+ rpc DeactivateProject(ProjectID) returns (Project) {
+ option (google.api.http) = {
+ put: "/projects/{id}/_deactivate"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "project.write"
+ check_field_name: "Id"
+ };
+ }
+
+ rpc ReactivateProject(ProjectID) returns (Project) {
+ option (google.api.http) = {
+ put: "/projects/{id}/_reactivate"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "project.write"
+ check_field_name: "Id"
+ };
+ }
+
+ rpc RemoveProject(ProjectID) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ delete: "/projects/{id}"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "project.delete"
+ check_field_name: "Id"
+ };
+ }
+
+ // returns all projects my organisation got granted from another organisation
+ rpc SearchGrantedProjects(GrantedProjectSearchRequest) returns (ProjectGrantSearchResponse) {
+ option (google.api.http) = {
+ post: "/grantedprojects/_search"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "project.read"
+ };
+ }
+
+ // returns a project my organisation got granted from another organisation
+ rpc GetGrantedProjectByID(ProjectGrantID) returns (ProjectGrantView) {
+ option (google.api.http) = {
+ get: "/grantedprojects/{project_id}/grants/{id}"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "project.read"
+ check_field_name: "Id"
+ };
+ }
+
+ rpc GetProjectMemberRoles(google.protobuf.Empty) returns (ProjectMemberRoles) {
+ option (google.api.http) = {
+ get: "/projects/members/roles"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "project.member.read"
+ };
+ }
+
+ rpc SearchProjectMembers(ProjectMemberSearchRequest) returns (ProjectMemberSearchResponse) {
+ option (google.api.http) = {
+ post: "/projects/{project_id}/members/_search"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "project.member.read"
+ check_field_name: "ProjectId"
+ };
+ }
+
+ rpc AddProjectMember(ProjectMemberAdd) returns (ProjectMember) {
+ option (google.api.http) = {
+ post: "/projects/{id}/members"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "project.member.write"
+ check_field_name: "Id"
+ };
+ }
+
+ rpc ChangeProjectMember(ProjectMemberChange) returns (ProjectMember) {
+ option (google.api.http) = {
+ put: "/projects/{id}/members/{user_id}"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "project.member.write"
+ check_field_name: "Id"
+ };
+ }
+
+ rpc RemoveProjectMember(ProjectMemberRemove) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ delete: "/projects/{id}/members/{user_id}"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "project.member.delete"
+ check_field_name: "Id"
+ };
+ }
+
+ rpc SearchProjectRoles(ProjectRoleSearchRequest) returns (ProjectRoleSearchResponse) {
+ option (google.api.http) = {
+ post: "/projects/{project_id}/roles/_search"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "project.role.read"
+ check_field_name: "ProjectId"
+ };
+ }
+
+ rpc AddProjectRole(ProjectRoleAdd) returns (ProjectRole) {
+ option (google.api.http) = {
+ post: "/projects/{id}/roles"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "project.role.write"
+ check_field_name: "Id"
+ };
+ }
+
+ // add a list of project roles in one request
+ rpc BulkAddProjectRole(ProjectRoleAddBulk) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ post: "/projects/{id}/roles/_bulk"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "project.role.write"
+ check_field_name: "Id"
+ };
+ }
+
+ rpc ChangeProjectRole(ProjectRoleChange) returns (ProjectRole) {
+ option (google.api.http) = {
+ put: "/projects/{id}/roles/{key}"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "project.role.write"
+ check_field_name: "Id"
+ };
+ }
+
+ // RemoveProjectRole removes role from UserGrants, ProjectGrants and from Project
+ rpc RemoveProjectRole(ProjectRoleRemove) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ delete: "/projects/{id}/roles/{key}"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "project.role.delete"
+ check_field_name: "Id"
+ };
+ }
+
+ rpc SearchApplications(ApplicationSearchRequest) returns (ApplicationSearchResponse) {
+ option (google.api.http) = {
+ post: "/projects/{project_id}/applications/_search"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "project.app.read"
+ check_field_name: "ProjectId"
+ };
+ }
+
+ rpc ApplicationByID(ApplicationID) returns (ApplicationView) {
+ option (google.api.http) = {
+ get: "/projects/{project_id}/applications/{id}"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "project.app.read"
+ check_field_name: "ProjectId"
+ };
+ }
+
+ // ApplicationChanges returns the event stream of the application object
+ rpc ApplicationChanges(ChangeRequest) returns (Changes) {
+ option (google.api.http) = {
+ get: "/projects/{id}/applications/{sec_id}/changes"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "project.app.read"
+ };
+ }
+
+ rpc CreateOIDCApplication(OIDCApplicationCreate) returns (Application) {
+ option (google.api.http) = {
+ post: "/projects/{project_id}/applications/oidc"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "project.app.write"
+ check_field_name: "ProjectId"
+ };
+ }
+
+ rpc CreateAPIApplication(APIApplicationCreate) returns (Application) {
+ option (google.api.http) = {
+ post: "/projects/{project_id}/applications/api"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "project.app.write"
+ check_field_name: "ProjectId"
+ };
+ }
+
+ rpc UpdateApplication(ApplicationUpdate) returns (Application) {
+ option (google.api.http) = {
+ put: "/projects/{project_id}/applications/{id}"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "project.app.write"
+ check_field_name: "ProjectId"
+ };
+ }
+
+ rpc DeactivateApplication(ApplicationID) returns (Application) {
+ option (google.api.http) = {
+ put: "/projects/{project_id}/applications/{id}/_deactivate"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "project.app.write"
+ check_field_name: "ProjectId"
+ };
+ }
+
+ rpc ReactivateApplication(ApplicationID) returns (Application) {
+ option (google.api.http) = {
+ put: "/projects/{project_id}/applications/{id}/_reactivate"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "project.app.write"
+ check_field_name: "ProjectId"
+ };
+ }
+
+ rpc RemoveApplication(ApplicationID) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ delete: "/projects/{project_id}/applications/{id}"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "project.app.delete"
+ check_field_name: "ProjectId"
+ };
+ }
+
+ rpc UpdateApplicationOIDCConfig(OIDCConfigUpdate) returns (OIDCConfig) {
+ option (google.api.http) = {
+ put: "/projects/{project_id}/applications/{application_id}/oidcconfig"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "project.app.write"
+ check_field_name: "ProjectId"
+ };
+ }
+
+ rpc RegenerateOIDCClientSecret(ApplicationID) returns (ClientSecret) {
+ option (google.api.http) = {
+ put: "/projects/{project_id}/applications/{id}/oidcconfig/_changeclientsecret"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "project.app.write"
+ check_field_name: "ProjectId"
+ };
+ }
+
+ rpc UpdateApplicationAPIConfig(APIConfigUpdate) returns (APIConfig) {
+ option (google.api.http) = {
+ put: "/projects/{project_id}/applications/{application_id}/apiconfig"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "project.app.write"
+ check_field_name: "ProjectId"
+ };
+ }
+
+ rpc RegenerateAPIClientSecret(ApplicationID) returns (ClientSecret) {
+ option (google.api.http) = {
+ put: "/projects/{project_id}/applications/{id}/apiconfig/_changeclientsecret"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "project.app.write"
+ check_field_name: "ProjectId"
+ };
+ }
+
+ rpc AddClientKey(AddClientKeyRequest) returns (AddClientKeyResponse){
+ option (google.api.http) = {
+ post: "/projects/{project_id}/applications/{application_id}/keys"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "project.app.write"
+ check_field_name: "ProjectId"
+ };
+ }
+
+ rpc DeleteClientKey(ClientKeyIDRequest) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ delete: "/projects/{project_id}/applications/{application_id}/keys/{key_id}"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "project.app.write"
+ check_field_name: "ProjectId"
+ };
+ }
+
+ rpc SearchClientKeys(ClientKeySearchRequest) returns (ClientKeySearchResponse) {
+ option (google.api.http) = {
+ post: "/projects/{project_id}/applications/{application_id}/keys/_search"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "project.app.read"
+ check_field_name: "ProjectId"
+ };
+ }
+
+ rpc GetClientKey(ClientKeyIDRequest) returns (ClientKeyView) {
+ option (google.api.http) = {
+ get: "/projects/{project_id}/applications/{application_id}/keys/{key_id}"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "project.app.read"
+ check_field_name: "ProjectId"
+ };
+ }
+
+ rpc SearchProjectGrants(ProjectGrantSearchRequest) returns (ProjectGrantSearchResponse) {
+ option (google.api.http) = {
+ post: "/projects/{project_id}/grants/_search"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "project.grant.read"
+ check_field_name: "ProjectId"
+ };
+ }
+
+ rpc ProjectGrantByID(ProjectGrantID) returns (ProjectGrantView) {
+ option (google.api.http) = {
+ get: "/projects/{project_id}/grants/{id}"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "project.grant.read"
+ };
+ }
+
+ rpc CreateProjectGrant(ProjectGrantCreate) returns (ProjectGrant) {
+ option (google.api.http) = {
+ post: "/projects/{project_id}/grants"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "project.grant.write"
+ };
+ }
+
+ rpc UpdateProjectGrant(ProjectGrantUpdate) returns (ProjectGrant) {
+ option (google.api.http) = {
+ put: "/projects/{project_id}/grants/{id}"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "project.grant.write"
+ };
+ }
+
+ rpc DeactivateProjectGrant(ProjectGrantID) returns (ProjectGrant) {
+ option (google.api.http) = {
+ put: "/projects/{project_id}/grants/{id}/_deactivate"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "project.grant.write"
+ };
+ }
+
+ rpc ReactivateProjectGrant(ProjectGrantID) returns (ProjectGrant) {
+ option (google.api.http) = {
+ put: "/projects/{project_id}/grants/{id}/_reactivate"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "project.grant.write"
+ };
+ }
+
+ // RemoveProjectGrant removes project grant and all user grants for this project grant
+ rpc RemoveProjectGrant(ProjectGrantID) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ delete: "/projects/{project_id}/grants/{id}"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "project.grant.delete"
+ };
+ }
+
+ rpc GetProjectGrantMemberRoles(google.protobuf.Empty) returns (ProjectGrantMemberRoles) {
+ option (google.api.http) = {
+ get: "/projects/grants/members/roles"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "project.grant.member.read"
+ };
+ }
+
+ rpc SearchProjectGrantMembers(ProjectGrantMemberSearchRequest) returns (ProjectGrantMemberSearchResponse) {
+ option (google.api.http) = {
+ post: "/projects/{project_id}/grants/{grant_id}/members/_search"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "project.grant.member.read"
+ };
+ }
+
+ rpc AddProjectGrantMember(ProjectGrantMemberAdd) returns (ProjectGrantMember) {
+ option (google.api.http) = {
+ post: "/projects/{project_id}/grants/{grant_id}/members"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "project.grant.member.write"
+ };
+ }
+
+ rpc ChangeProjectGrantMember(ProjectGrantMemberChange) returns (ProjectGrantMember) {
+ option (google.api.http) = {
+ put: "/projects/{project_id}/grants/{grant_id}/members/{user_id}"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "project.grant.member.write"
+ };
+ }
+
+ rpc RemoveProjectGrantMember(ProjectGrantMemberRemove) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ delete: "/projects/{project_id}/grants/{grant_id}/members/{user_id}"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "project.grant.member.delete"
+ };
+ }
+
+ rpc SearchUserGrants(UserGrantSearchRequest) returns (UserGrantSearchResponse) {
+ option (google.api.http) = {
+ post: "/users/grants/_search"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "user.grant.read"
+ };
+ }
+
+ rpc UserGrantByID(UserGrantID) returns (UserGrantView) {
+ option (google.api.http) = {
+ get: "/users/{user_id}/grants/{id}"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "user.grant.read"
+ };
+ }
+
+ rpc CreateUserGrant(UserGrantCreate) returns (UserGrant) {
+ option (google.api.http) = {
+ post: "/users/{user_id}/grants"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "user.grant.write"
+ };
+ }
+
+ rpc UpdateUserGrant(UserGrantUpdate) returns (UserGrant) {
+ option (google.api.http) = {
+ put: "/users/{user_id}/grants/{id}"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "user.grant.write"
+ };
+ }
+
+ rpc DeactivateUserGrant(UserGrantID) returns (UserGrant) {
+ option (google.api.http) = {
+ put: "/users/{user_id}/grants/{id}/_deactivate"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "user.grant.write"
+ };
+ }
+
+ rpc ReactivateUserGrant(UserGrantID) returns (UserGrant) {
+ option (google.api.http) = {
+ put: "/users/{user_id}/grants/{id}/_reactivate"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "user.grant.write"
+ };
+ }
+
+ rpc RemoveUserGrant(UserGrantID) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ delete: "/users/{user_id}/grants/{id}"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "user.grant.delete"
+ };
+ }
+
+ // remove a list of user grants in one request
+ rpc BulkRemoveUserGrant(UserGrantRemoveBulk) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ delete: "/usersgrants/_bulk"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "user.grant.delete"
+ };
+ }
+
+ rpc IdpByID(IdpID) returns (IdpView) {
+ option (google.api.http) = {
+ get: "/orgs/me/idps/{id}"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "org.idp.read"
+ };
+ }
+
+ rpc CreateOidcIdp(OidcIdpConfigCreate) returns (Idp) {
+ option (google.api.http) = {
+ post: "/orgs/me/idps/oidc"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "org.idp.write"
+ };
+ }
+
+ rpc UpdateIdpConfig(IdpUpdate) returns (Idp) {
+ option (google.api.http) = {
+ put: "/orgs/me/idps/{id}"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "org.idp.write"
+ };
+ }
+
+ rpc DeactivateIdpConfig(IdpID) returns (Idp) {
+ option (google.api.http) = {
+ put: "/orgs/me/idps/{id}/_deactivate"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "org.idp.write"
+ };
+ }
+
+ rpc ReactivateIdpConfig(IdpID) returns (Idp) {
+ option (google.api.http) = {
+ put: "/orgs/me/idps/{id}/_reactivate"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "org.idp.write"
+ };
+ }
+
+ rpc RemoveIdpConfig(IdpID) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ delete: "/orgs/me/idps/{id}"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "org.idp.write"
+ };
+ }
+
+ rpc UpdateOidcIdpConfig(OidcIdpConfigUpdate) returns (OidcIdpConfig) {
+ option (google.api.http) = {
+ put: "/orgs/me/idps/{idp_id}/oidcconfig"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "org.idp.write"
+ };
+ }
+
+ rpc SearchIdps(IdpSearchRequest) returns (IdpSearchResponse) {
+ option (google.api.http) = {
+ post: "/orgs/me/idps/_search"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "org.idp.read"
+ };
+ }
+
+ rpc GetLoginPolicy(google.protobuf.Empty) returns (LoginPolicyView) {
+ option (google.api.http) = {
+ get: "/orgs/me/policies/login"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "policy.read"
+ };
+ }
+
+ rpc GetDefaultLoginPolicy(google.protobuf.Empty) returns (LoginPolicyView) {
+ option (google.api.http) = {
+ get: "/orgs/default/policies/login"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "policy.read"
+ };
+ }
+
+ rpc CreateLoginPolicy(LoginPolicyRequest) returns (LoginPolicy) {
+ option (google.api.http) = {
+ post: "/orgs/me/policies/login"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "policy.write"
+ };
+ }
+
+ rpc UpdateLoginPolicy(LoginPolicyRequest) returns (LoginPolicy) {
+ option (google.api.http) = {
+ put: "/orgs/me/policies/login"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "policy.write"
+ };
+ }
+
+ rpc RemoveLoginPolicy(google.protobuf.Empty) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ delete: "/orgs/me/policies/login"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "policy.delete"
+ };
+ }
+
+ rpc GetLoginPolicyIdpProviders(IdpProviderSearchRequest) returns (IdpProviderSearchResponse) {
+ option (google.api.http) = {
+ post: "/orgs/me/policies/login/idpproviders/_search"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "policy.read"
+ };
+ }
+
+ rpc AddIdpProviderToLoginPolicy(IdpProviderAdd) returns (IdpProvider) {
+ option (google.api.http) = {
+ post: "/orgs/me/policies/login/idpproviders"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "policy.write"
+ };
+ }
+
+ rpc RemoveIdpProviderFromLoginPolicy(IdpProviderID) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ delete: "/orgs/me/policies/login/idpproviders/{idp_config_id}"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "policy.write"
+ };
+ }
+
+ rpc GetLoginPolicySecondFactors(google.protobuf.Empty) returns (SecondFactorsResult) {
+ option (google.api.http) = {
+ get: "/orgs/me/policies/login/secondfactors/_search"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "policy.read"
+ };
+ }
+
+ rpc AddSecondFactorToLoginPolicy(SecondFactor) returns (SecondFactor) {
+ option (google.api.http) = {
+ post: "/orgs/me/policies/login/secondfactors"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "policy.write"
+ };
+ }
+
+ rpc RemoveSecondFactorFromLoginPolicy(SecondFactor) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ delete: "/orgs/me/policies/login/secondfactors/{second_factor}"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "policy.write"
+ };
+ }
+
+ rpc GetLoginPolicyMultiFactors(google.protobuf.Empty) returns (MultiFactorsResult) {
+ option (google.api.http) = {
+ get: "/orgs/me/policies/login/multifactors/_search"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "policy.read"
+ };
+ }
+
+ rpc AddMultiFactorToLoginPolicy(MultiFactor) returns (MultiFactor) {
+ option (google.api.http) = {
+ post: "/orgs/me/policies/login/multifactors"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "policy.write"
+ };
+ }
+
+ rpc RemoveMultiFactorFromLoginPolicy(MultiFactor) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ delete: "/orgs/me/policies/login/multifactors/{multi_factor}"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "policy.write"
+ };
+ }
+
+ rpc GetPasswordComplexityPolicy(google.protobuf.Empty) returns (PasswordComplexityPolicyView) {
+ option (google.api.http) = {
+ get: "/orgs/me/policies/password/complexity"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "policy.read"
+ };
+ }
+
+ rpc GetDefaultPasswordComplexityPolicy(google.protobuf.Empty) returns (PasswordComplexityPolicyView) {
+ option (google.api.http) = {
+ get: "/orgs/default/policies/password/complexity"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "policy.read"
+ };
+ }
+
+ rpc CreatePasswordComplexityPolicy(PasswordComplexityPolicyRequest) returns (PasswordComplexityPolicy) {
+ option (google.api.http) = {
+ post: "/orgs/me/policies/password/complexity"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "policy.write"
+ };
+ }
+
+ rpc UpdatePasswordComplexityPolicy(PasswordComplexityPolicyRequest) returns (PasswordComplexityPolicy) {
+ option (google.api.http) = {
+ put: "/orgs/me/policies/password/complexity"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "policy.write"
+ };
+ }
+
+ rpc RemovePasswordComplexityPolicy(google.protobuf.Empty) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ delete: "/orgs/me/policies/password/complexity"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "policy.delete"
+ };
+ }
+
+ rpc GetPasswordAgePolicy(google.protobuf.Empty) returns (PasswordAgePolicyView) {
+ option (google.api.http) = {
+ get: "/orgs/me/policies/password/age"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "policy.read"
+ };
+ }
+
+ rpc GetDefaultPasswordAgePolicy(google.protobuf.Empty) returns (PasswordAgePolicyView) {
+ option (google.api.http) = {
+ get: "/orgs/default/policies/password/age"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "policy.read"
+ };
+ }
+
+ rpc CreatePasswordAgePolicy(PasswordAgePolicyRequest) returns (PasswordAgePolicy) {
+ option (google.api.http) = {
+ post: "/orgs/me/policies/password/age"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "policy.write"
+ };
+ }
+
+ rpc UpdatePasswordAgePolicy(PasswordAgePolicyRequest) returns (PasswordAgePolicy) {
+ option (google.api.http) = {
+ put: "/orgs/me/policies/password/age"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "policy.write"
+ };
+ }
+
+ rpc RemovePasswordAgePolicy(google.protobuf.Empty) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ delete: "/orgs/me/policies/password/age"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "policy.delete"
+ };
+ }
+
+ rpc GetPasswordLockoutPolicy(google.protobuf.Empty) returns (PasswordLockoutPolicyView) {
+ option (google.api.http) = {
+ get: "/orgs/me/policies/password/lockout"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "policy.read"
+ };
+ }
+
+ rpc GetDefaultPasswordLockoutPolicy(google.protobuf.Empty) returns (PasswordLockoutPolicyView) {
+ option (google.api.http) = {
+ get: "/orgs/default/policies/password/lockout"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "policy.read"
+ };
+ }
+
+ rpc CreatePasswordLockoutPolicy(PasswordLockoutPolicyRequest) returns (PasswordLockoutPolicy) {
+ option (google.api.http) = {
+ post: "/orgs/me/policies/password/lockout"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "policy.write"
+ };
+ }
+
+ rpc UpdatePasswordLockoutPolicy(PasswordLockoutPolicyRequest) returns (PasswordLockoutPolicy) {
+ option (google.api.http) = {
+ put: "/orgs/me/policies/password/lockout"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "policy.write"
+ };
+ }
+
+ rpc RemovePasswordLockoutPolicy(google.protobuf.Empty) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ delete: "/orgs/me/policies/password/lockout"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "policy.delete"
+ };
+ }
+
+ rpc GetMailTemplate(google.protobuf.Empty) returns (MailTemplateView) {
+ option (google.api.http) = {
+ get: "/orgs/me/policies/mailtemplate"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "policy.read"
+ };
+ }
+
+ rpc GetDefaultMailTemplate(google.protobuf.Empty) returns (MailTemplateView) {
+ option (google.api.http) = {
+ get: "/orgs/default/policies/mailtemplate"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "policy.read"
+ };
+ }
+
+ rpc CreateMailTemplate(MailTemplateUpdate) returns (MailTemplate) {
+ option (google.api.http) = {
+ post: "/orgs/me/policies/mailtemplate"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "policy.write"
+ };
+ }
+
+ rpc UpdateMailTemplate(MailTemplateUpdate) returns (MailTemplate) {
+ option (google.api.http) = {
+ put: "/orgs/me/policies/mailtemplate"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "policy.write"
+ };
+ }
+
+ rpc RemoveMailTemplate(google.protobuf.Empty) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ delete: "/orgs/me/policies/mailtemplate"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "policy.delete"
+ };
+ }
+
+
+ rpc GetMailTexts(google.protobuf.Empty) returns (MailTextsView) {
+ option (google.api.http) = {
+ get: "/orgs/me/policies/mailtexts"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "policy.read"
+ };
+ }
+
+ rpc GetDefaultMailTexts(google.protobuf.Empty) returns (MailTextsView) {
+ option (google.api.http) = {
+ get: "/orgs/default/policies/mailtexts"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "policy.read"
+ };
+ }
+
+ rpc CreateMailText(MailTextUpdate) returns (MailText) {
+ option (google.api.http) = {
+ post: "/orgs/me/policies/mailtext"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "policy.write"
+ };
+ }
+
+ rpc UpdateMailText(MailTextUpdate) returns (MailText) {
+ option (google.api.http) = {
+ put: "/orgs/me/policies/mailtext"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "policy.write"
+ };
+ }
+
+ rpc RemoveMailText(MailTextRemove) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ delete: "/orgs/me/policies/mailtext/type/{mail_text_type}/language/{language}"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "policy.delete"
+ };
+ }
+
+ rpc GetLabelPolicy(google.protobuf.Empty) returns (LabelPolicyView) {
+ option (google.api.http) = {
+ get: "/orgs/me/policies/label"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "policy.read"
+ };
+ }
+
+ rpc GetDefaultLabelPolicy(google.protobuf.Empty) returns (LabelPolicyView) {
+ option (google.api.http) = {
+ get: "/orgs/default/policies/label"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "policy.read"
+ };
+ }
+
+ rpc CreateLabelPolicy(LabelPolicyRequest) returns (LabelPolicy) {
+ option (google.api.http) = {
+ post: "/orgs/me/policies/label"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "policy.write"
+ };
+ }
+
+ rpc UpdateLabelPolicy(LabelPolicyRequest) returns (LabelPolicy) {
+ option (google.api.http) = {
+ put: "/orgs/me/policies/label"
+ body: "*"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "policy.write"
+ };
+ }
+
+ rpc RemoveLabelPolicy(google.protobuf.Empty) returns (google.protobuf.Empty) {
+ option (google.api.http) = {
+ delete: "/orgs/me/policies/label"
+ };
+
+ option (caos.zitadel.utils.v1.auth_option) = {
+ permission: "policy.delete"
+ };
+ }
+
+}
+
+message ZitadelDocs {
+ string issuer = 1;
+ string discovery_endpoint = 2;
+}
+
+message Iam {
+ string global_org_id = 1;
+ string iam_project_id = 2;
+ IamSetupStep set_up_done = 3;
+ IamSetupStep set_up_started = 4;
+}
+
+enum IamSetupStep {
+ iam_setup_step_UNDEFINED = 0;
+ iam_setup_step_1 = 1;
+ iam_setup_step_2 = 2;
+}
+
+message ChangeRequest {
+ string id = 1;
+ string sec_id = 2;
+ uint64 limit = 3;
+ uint64 sequence_offset = 4;
+ bool asc = 5;
+}
+
+message Changes {
+ repeated Change changes = 1;
+ uint64 offset = 2;
+ uint64 limit = 3;
+}
+
+message Change {
+ google.protobuf.Timestamp change_date = 1;
+ caos.zitadel.api.v1.LocalizedMessage event_type = 2;
+ uint64 sequence = 3;
+ string editor_id = 4;
+ string editor = 5;
+ google.protobuf.Struct data = 6;
+}
+
+message ApplicationID {
+ string id = 1 [(validate.rules).string.min_len = 1];
+ string project_id = 2 [(validate.rules).string.min_len = 1];
+}
+
+message ProjectID {
+ string id = 1 [(validate.rules).string.min_len = 1];
+}
+
+message UserID {
+ string id = 1 [(validate.rules).string.min_len = 1];
+}
+
+message WebAuthNTokens {
+ repeated WebAuthNToken tokens = 1;
+}
+
+message WebAuthNToken {
+ string id = 1;
+ string name = 2;
+ MFAState state = 3;
+}
+
+message WebAuthNTokenID {
+ string user_id = 1 [(validate.rules).string.min_len = 1];
+ string id = 2 [(validate.rules).string.min_len = 1];
+}
+
+message LoginName {
+ string login_name = 1 [(validate.rules).string.min_len = 1];
+}
+
+message UniqueUserRequest {
+ string user_name = 1 [(validate.rules).string.pattern = "^[^[:space:]]{1,200}$"];
+ string email = 2 [(validate.rules).string = {min_len: 1, max_len: 200}];
+}
+
+message UniqueUserResponse {
+ bool is_unique = 1;
+}
+
+message CreateUserRequest {
+ string user_name = 1 [(validate.rules).string.pattern = "^[^[:space:]]{1,200}$"];
+
+ oneof user {
+ option (validate.required) = true;
+
+ CreateHumanRequest human = 2;
+ CreateMachineRequest machine = 3;
+ }
+}
+
+message ImportHumanRequest {
+ string user_name = 1 [(validate.rules).string.pattern = "^[^[:space:]]{1,200}$"];
+ string first_name = 2 [(validate.rules).string = {min_len: 1, max_len: 200}];
+ string last_name = 3 [(validate.rules).string = {min_len: 1, max_len: 200}];
+ string nick_name = 4 [(validate.rules).string = {max_len: 200}];
+ string preferred_language = 5 [(validate.rules).string = {max_len: 200}];
+ Gender gender = 6;
+ string email = 7 [(validate.rules).string = {min_len: 1, max_len: 200, email: true}];
+ bool is_email_verified = 8;
+ string phone = 9 [(validate.rules).string = {max_len: 20}];
+ bool is_phone_verified = 10;
+ string country = 11 [(validate.rules).string = {max_len: 200}];
+ string locality = 12 [(validate.rules).string = {max_len: 200}];
+ string postal_code = 13 [(validate.rules).string = {max_len: 200}];
+ string region = 14 [(validate.rules).string = {max_len: 200}];
+ string street_address = 15 [(validate.rules).string = {max_len: 200}];
+ string password = 16 [(validate.rules).string = {max_len: 72}];
+ bool password_change_required = 17;
+}
+
+message CreateHumanRequest {
+ string first_name = 1 [(validate.rules).string = {min_len: 1, max_len: 200}];
+ string last_name = 2 [(validate.rules).string = {min_len: 1, max_len: 200}];
+ string nick_name = 3 [(validate.rules).string = {max_len: 200}];
+ string preferred_language = 4 [(validate.rules).string = {max_len: 200}];
+ Gender gender = 5;
+ string email = 6 [(validate.rules).string = {min_len: 1, max_len: 200, email: true}];
+ bool is_email_verified = 7;
+ string phone = 8 [(validate.rules).string = {max_len: 20}];
+ bool is_phone_verified = 9;
+ string country = 10 [(validate.rules).string = {max_len: 200}];
+ string locality = 11 [(validate.rules).string = {max_len: 200}];
+ string postal_code = 12 [(validate.rules).string = {max_len: 200}];
+ string region = 13 [(validate.rules).string = {max_len: 200}];
+ string street_address = 14 [(validate.rules).string = {max_len: 200}];
+ string password = 15 [(validate.rules).string = {max_len: 72}];
+}
+
+message CreateMachineRequest {
+ string name = 1 [(validate.rules).string = {min_len: 1, max_len: 200}];
+ string description = 2 [(validate.rules).string.max_len = 500];
+}
+
+message UserResponse {
+ string id = 1;
+ UserState state = 2;
+ google.protobuf.Timestamp creation_date = 3;
+ google.protobuf.Timestamp change_date = 4;
+ uint64 sequence = 5;
+ string user_name = 6;
+
+ oneof user {
+ option (validate.required) = true;
+
+ HumanResponse human = 7;
+ MachineResponse machine = 8;
+ }
+}
+
+enum UserState {
+ USERSTATE_UNSPECIFIED = 0;
+ USERSTATE_ACTIVE = 1;
+ USERSTATE_INACTIVE = 2;
+ USERSTATE_DELETED = 3;
+ USERSTATE_LOCKED = 4;
+ USERSTATE_SUSPEND = 5;
+ USERSTATE_INITIAL = 6;
+}
+
+enum Gender {
+ GENDER_UNSPECIFIED = 0;
+ GENDER_FEMALE = 1;
+ GENDER_MALE = 2;
+ GENDER_DIVERSE = 3;
+}
+
+message UserView {
+ string id = 1;
+ UserState state = 2;
+ google.protobuf.Timestamp creation_date = 3;
+ google.protobuf.Timestamp change_date = 4;
+ uint64 sequence = 5;
+ repeated string login_names = 6;
+ string preferred_login_name = 7;
+ google.protobuf.Timestamp last_login = 8;
+ string resource_owner = 9;
+ string user_name = 10;
+
+ oneof user {
+ option (validate.required) = true;
+
+ HumanView human = 11;
+ MachineView machine = 12;
+ }
+}
+
+message HumanResponse {
+ string first_name = 1;
+ string last_name = 2;
+ string display_name = 3;
+ string nick_name = 4;
+ string preferred_language = 5;
+ Gender gender = 6;
+ string email = 7;
+ bool is_email_verified = 8;
+ string phone = 9;
+ bool is_phone_verified = 10;
+ string country = 11;
+ string locality = 12;
+ string postal_code = 13;
+ string region = 14;
+ string street_address = 15;
+}
+
+message HumanView {
+ google.protobuf.Timestamp password_changed = 1;
+ string first_name = 2;
+ string last_name = 3;
+ string display_name = 4;
+ string nick_name = 5;
+ string preferred_language = 6;
+ Gender gender = 7;
+ string email = 8;
+ bool is_email_verified = 9;
+ string phone = 10;
+ bool is_phone_verified = 11;
+ string country = 12;
+ string locality = 13;
+ string postal_code = 14;
+ string region = 15;
+ string street_address = 16;
+}
+
+message MachineResponse {
+ string name = 1;
+ string description = 2;
+}
+
+message MachineView {
+ google.protobuf.Timestamp last_key_added = 1;
+ string name = 2;
+ string description = 3;
+}
+
+message UpdateMachineRequest {
+ string id = 1 [(validate.rules).string.min_len = 1];
+ string description = 2 [(validate.rules).string.max_len = 500];
+}
+
+message AddMachineKeyRequest {
+ string user_id = 1 [(validate.rules).string.min_len = 1];
+ MachineKeyType type = 2 [(validate.rules).enum = {not_in: [0]}];
+ google.protobuf.Timestamp expiration_date = 3;
+}
+
+message AddMachineKeyResponse {
+ string id = 1;
+ google.protobuf.Timestamp creation_date = 2;
+ uint64 sequence = 3;
+
+ MachineKeyType type = 4;
+ google.protobuf.Timestamp expiration_date = 5;
+ bytes key_details = 6;
+}
+
+message MachineKeyIDRequest {
+ string user_id = 1 [(validate.rules).string.min_len = 1];
+ string key_id = 2 [(validate.rules).string.min_len = 1];
+}
+
+message MachineKeyView {
+ string id = 1;
+ MachineKeyType type = 2;
+ uint64 sequence = 3;
+
+ google.protobuf.Timestamp creation_date = 4;
+ google.protobuf.Timestamp expiration_date = 5;
+}
+
+enum MachineKeyType {
+ MACHINEKEY_UNSPECIFIED = 0;
+ MACHINEKEY_JSON = 1;
+}
+
+message MachineKeySearchRequest {
+ uint64 offset = 1;
+ uint64 limit = 2;
+ bool asc = 3;
+ string user_id = 4 [(validate.rules).string.min_len = 1];
+}
+
+message MachineKeySearchResponse {
+ uint64 offset = 1;
+ uint64 limit = 2;
+ uint64 total_result = 3;
+ repeated MachineKeyView result = 4;
+ uint64 processed_sequence = 5;
+ google.protobuf.Timestamp view_timestamp = 6;
+}
+
+message UserSearchRequest {
+ uint64 offset = 1;
+ uint64 limit = 2;
+ UserSearchKey sorting_column = 3;
+ bool asc = 4;
+ repeated UserSearchQuery queries = 5;
+}
+
+message UserSearchQuery {
+ UserSearchKey key = 1 [(validate.rules).enum = {not_in: [0]}];
+ SearchMethod method = 2;
+ string value = 3;
+}
+
+enum UserSearchKey {
+ USERSEARCHKEY_UNSPECIFIED = 0;
+ USERSEARCHKEY_USER_NAME = 1;
+ USERSEARCHKEY_FIRST_NAME = 2;
+ USERSEARCHKEY_LAST_NAME = 3;
+ USERSEARCHKEY_NICK_NAME = 4;
+ USERSEARCHKEY_DISPLAY_NAME = 5;
+ USERSEARCHKEY_EMAIL = 6;
+ USERSEARCHKEY_STATE = 7;
+ USERSEARCHKEY_TYPE = 8;
+}
+
+message UserSearchResponse {
+ uint64 offset = 1;
+ uint64 limit = 2;
+ uint64 total_result = 3;
+ repeated UserView result = 4;
+ uint64 processed_sequence = 5;
+ google.protobuf.Timestamp view_timestamp = 6;
+}
+
+enum SearchMethod {
+ SEARCHMETHOD_EQUALS = 0;
+ SEARCHMETHOD_STARTS_WITH = 1;
+ SEARCHMETHOD_CONTAINS = 2;
+ SEARCHMETHOD_EQUALS_IGNORE_CASE = 3;
+ SEARCHMETHOD_STARTS_WITH_IGNORE_CASE = 4;
+ SEARCHMETHOD_CONTAINS_IGNORE_CASE = 5;
+ SEARCHMETHOD_NOT_EQUALS = 6;
+ SEARCHMETHOD_GREATER_THAN = 7;
+ SEARCHMETHOD_LESS_THAN = 8;
+ SEARCHMETHOD_IS_ONE_OF = 9;
+ SEARCHMETHOD_LIST_CONTAINS = 10;
+}
+
+message UserProfile {
+ string id = 1;
+ string first_name = 2;
+ string last_name = 3;
+ string nick_name = 4;
+ string display_name = 5;
+ string preferred_language = 6;
+ Gender gender = 7;
+ uint64 sequence = 8;
+ google.protobuf.Timestamp creation_date = 9;
+ google.protobuf.Timestamp change_date = 10;
+}
+
+message UserProfileView {
+ string id = 1;
+ string first_name = 2;
+ string last_name = 3;
+ string nick_name = 4;
+ string display_name = 5;
+ string preferred_language = 6;
+ Gender gender = 7;
+ uint64 sequence = 8;
+ google.protobuf.Timestamp creation_date = 9;
+ google.protobuf.Timestamp change_date = 10;
+ repeated string login_names = 11;
+ string preferred_login_name = 12;
+}
+
+message UpdateUserProfileRequest {
+ string id = 1;
+ string first_name = 2 [(validate.rules).string = {min_len: 1, max_len: 200}];
+ string last_name = 3 [(validate.rules).string = {min_len: 1, max_len: 200}];
+ string nick_name = 4 [(validate.rules).string = {max_len: 200}];
+ string preferred_language = 5 [(validate.rules).string = {max_len: 200}];
+ Gender gender = 6;
+}
+
+message UpdateUserUserNameRequest {
+ string id = 1;
+ string user_name = 2 [(validate.rules).string.pattern = "^[^[:space:]]{1,200}$"];
+}
+
+message UserEmail {
+ string id = 1;
+ string email = 2;
+ bool is_email_verified = 3;
+ uint64 sequence = 4;
+ google.protobuf.Timestamp creation_date = 5;
+ google.protobuf.Timestamp change_date = 6;
+}
+
+message UserEmailView {
+ string id = 1;
+ string email = 2;
+ bool is_email_verified = 3;
+ uint64 sequence = 4;
+ google.protobuf.Timestamp creation_date = 5;
+ google.protobuf.Timestamp change_date = 6;
+}
+
+message UpdateUserEmailRequest {
+ string id = 1;
+ string email = 2 [(validate.rules).string = {min_len: 1, max_len: 200}];
+ bool is_email_verified = 3;
+}
+
+message UserPhone {
+ string id = 1;
+ string phone = 2;
+ bool is_phone_verified = 3;
+ uint64 sequence = 5;
+ google.protobuf.Timestamp creation_date = 6;
+ google.protobuf.Timestamp change_date = 7;
+}
+
+message UserPhoneView {
+ string id = 1;
+ string phone = 2;
+ bool is_phone_verified = 3;
+ uint64 sequence = 5;
+ google.protobuf.Timestamp creation_date = 6;
+ google.protobuf.Timestamp change_date = 7;
+}
+
+message UpdateUserPhoneRequest {
+ string id = 1 [(validate.rules).string.min_len = 1];
+ string phone = 2 [(validate.rules).string = {min_len: 1, max_len: 20}];
+ bool is_phone_verified = 3;
+}
+
+message UserAddress {
+ string id = 1;
+ string country = 2;
+ string locality = 3;
+ string postal_code = 4;
+ string region = 5;
+ string street_address = 6;
+ uint64 sequence = 7;
+ google.protobuf.Timestamp creation_date = 8;
+ google.protobuf.Timestamp change_date = 9;
+}
+
+message UserAddressView {
+ string id = 1;
+ string country = 2;
+ string locality = 3;
+ string postal_code = 4;
+ string region = 5;
+ string street_address = 6;
+ uint64 sequence = 7;
+ google.protobuf.Timestamp creation_date = 8;
+ google.protobuf.Timestamp change_date = 9;
+}
+
+message UpdateUserAddressRequest {
+ string id = 1 [(validate.rules).string.min_len = 1];
+ string country = 2 [(validate.rules).string = {max_len: 200}];
+ string locality = 3 [(validate.rules).string = {max_len: 200}];
+ string postal_code = 4 [(validate.rules).string = {max_len: 200}];
+ string region = 5 [(validate.rules).string = {max_len: 200}];
+ string street_address = 6 [(validate.rules).string = {max_len: 200}];
+}
+
+message UserMultiFactors {
+ repeated UserMultiFactor mfas = 1;
+}
+
+message UserMultiFactor {
+ MfaType type = 1;
+ MFAState state = 2;
+ string attribute = 3;
+ string id = 4;
+}
+
+enum MfaType {
+ MFATYPE_UNSPECIFIED = 0;
+ MFATYPE_OTP = 1;
+ MFATYPE_U2F = 2;
+}
+
+enum MFAState {
+ MFASTATE_UNSPECIFIED = 0;
+ MFASTATE_NOT_READY = 1;
+ MFASTATE_READY = 2;
+ MFASTATE_REMOVED = 3;
+}
+
+message PasswordRequest {
+ string id = 1 [(validate.rules).string.min_len = 1];
+ string password = 2 [(validate.rules).string = {min_len: 1, max_len: 72}];
+}
+
+message SetPasswordNotificationRequest {
+ string id = 1 [(validate.rules).string.min_len = 1];
+ NotificationType type = 2;
+}
+
+enum NotificationType {
+ NOTIFICATIONTYPE_EMAIL = 0;
+ NOTIFICATIONTYPE_SMS = 1;
+}
+
+message InitialMailRequest {
+ string id = 1 [(validate.rules).string.min_len = 1];
+ string email = 2;
+}
+
+enum PolicyState {
+ POLICYSTATE_UNSPECIFIED = 0;
+ POLICYSTATE_ACTIVE = 1;
+ POLICYSTATE_INACTIVE = 2;
+ POLICYSTATE_DELETED = 3;
+}
+
+message OrgIamPolicyView {
+ bool user_login_must_be_domain = 1;
+ bool default = 2;
+}
+
+message OrgCreateRequest {
+ string name = 1 [(validate.rules).string = {min_len: 1, max_len: 200}];
+}
+
+message Org {
+ string id = 1;
+ OrgState state = 2;
+ google.protobuf.Timestamp creation_date = 3;
+ google.protobuf.Timestamp change_date = 4;
+ string name = 5;
+ uint64 sequence = 6;
+}
+
+message OrgView {
+ string id = 1;
+ OrgState state = 2;
+ google.protobuf.Timestamp creation_date = 3;
+ google.protobuf.Timestamp change_date = 4;
+ string name = 5;
+ uint64 sequence = 6;
+}
+
+enum OrgState {
+ ORGSTATE_UNSPECIFIED = 0;
+ ORGSTATE_ACTIVE = 1;
+ ORGSTATE_INACTIVE = 2;
+}
+
+message Domain {
+ string domain = 1 [(validate.rules).string = {min_len: 1}];
+}
+
+message OrgDomain {
+ string org_id = 1;
+ google.protobuf.Timestamp creation_date = 2;
+ google.protobuf.Timestamp change_date = 3;
+ string domain = 4;
+ bool verified = 5;
+ bool primary = 6;
+ uint64 sequence = 7;
+}
+
+message OrgDomainView {
+ string org_id = 1;
+ google.protobuf.Timestamp creation_date = 2;
+ google.protobuf.Timestamp change_date = 3;
+ string domain = 4;
+ bool verified = 5;
+ bool primary = 6;
+ uint64 sequence = 7;
+ OrgDomainValidationType validation_type = 8;
+}
+
+message AddOrgDomainRequest {
+ string domain = 1 [(validate.rules).string = {min_len: 1, max_len: 200}];
+}
+
+message OrgDomainValidationRequest {
+ string domain = 1 [(validate.rules).string = {min_len: 1, max_len: 200}];
+ OrgDomainValidationType type = 2 [(validate.rules).enum = {not_in: [0]}];
+}
+
+enum OrgDomainValidationType {
+ ORGDOMAINVALIDATIONTYPE_UNSPECIFIED = 0;
+ ORGDOMAINVALIDATIONTYPE_HTTP = 1;
+ ORGDOMAINVALIDATIONTYPE_DNS = 2;
+}
+
+message OrgDomainValidationResponse {
+ string token = 1;
+ string url = 2;
+}
+
+message ValidateOrgDomainRequest {
+ string domain = 1 [(validate.rules).string = {min_len: 1, max_len: 200}];
+}
+
+message PrimaryOrgDomainRequest {
+ string domain = 1 [(validate.rules).string = {min_len: 1}];
+}
+
+message RemoveOrgDomainRequest {
+ string domain = 1 [(validate.rules).string = {min_len: 1}];
+}
+
+message OrgDomainSearchResponse {
+ uint64 offset = 1;
+ uint64 limit = 2;
+ uint64 total_result = 3;
+ repeated OrgDomainView result = 4;
+ uint64 processed_sequence = 5;
+ google.protobuf.Timestamp view_timestamp = 6;
+}
+
+message OrgDomainSearchRequest {
+ uint64 offset = 1;
+ uint64 limit = 2;
+ repeated OrgDomainSearchQuery queries = 3;
+}
+
+message OrgDomainSearchQuery {
+ OrgDomainSearchKey key = 1 [(validate.rules).enum = {not_in: [0]}];
+ SearchMethod method = 2;
+ string value = 3;
+}
+
+enum OrgDomainSearchKey {
+ ORGDOMAINSEARCHKEY_UNSPECIFIED = 0;
+ ORGDOMAINSEARCHKEY_DOMAIN = 1;
+}
+
+message OrgMemberRoles {
+ repeated string roles = 1;
+}
+
+message OrgMember {
+ string user_id = 1;
+ repeated string roles = 2;
+ google.protobuf.Timestamp change_date = 3;
+ google.protobuf.Timestamp creation_date = 4;
+ uint64 sequence = 5;
+}
+
+message AddOrgMemberRequest {
+ string user_id = 1 [(validate.rules).string = {min_len: 1}];
+ repeated string roles = 2;
+}
+
+message ChangeOrgMemberRequest {
+ string user_id = 1 [(validate.rules).string = {min_len: 1}];
+ repeated string roles = 2;
+}
+
+message RemoveOrgMemberRequest {
+ string user_id = 1 [(validate.rules).string = {min_len: 1}];
+}
+
+message OrgMemberSearchResponse {
+ uint64 offset = 1;
+ uint64 limit = 2;
+ uint64 total_result = 3;
+ repeated OrgMemberView result = 4;
+ uint64 processed_sequence = 5;
+ google.protobuf.Timestamp view_timestamp = 6;
+}
+
+message OrgMemberView {
+ string user_id = 1;
+ repeated string roles = 2;
+ google.protobuf.Timestamp change_date = 3;
+ google.protobuf.Timestamp creation_date = 4;
+ uint64 sequence = 5;
+ string user_name = 6;
+ string email = 7;
+ string first_name = 8;
+ string last_name = 9;
+ string display_name = 10;
+}
+
+message OrgMemberSearchRequest {
+ uint64 offset = 1;
+ uint64 limit = 2;
+ repeated OrgMemberSearchQuery queries = 3;
+}
+
+message OrgMemberSearchQuery {
+ OrgMemberSearchKey key = 1 [(validate.rules).enum = {not_in: [0]}];
+ SearchMethod method = 2;
+ string value = 3;
+}
+
+enum OrgMemberSearchKey {
+ ORGMEMBERSEARCHKEY_UNSPECIFIED = 0;
+ ORGMEMBERSEARCHKEY_FIRST_NAME = 1;
+ ORGMEMBERSEARCHKEY_LAST_NAME = 2;
+ ORGMEMBERSEARCHKEY_EMAIL = 3;
+ ORGMEMBERSEARCHKEY_USER_ID = 4;
+}
+
+message ProjectCreateRequest {
+ string name = 1 [(validate.rules).string = {min_len: 1, max_len: 200}];
+ bool project_role_assertion = 2;
+ bool project_role_check = 3;
+}
+
+message ProjectUpdateRequest {
+ string id = 1 [(validate.rules).string = {min_len: 1}];
+ string name = 2 [(validate.rules).string = {min_len: 1, max_len: 200}];
+ bool project_role_assertion = 3;
+ bool project_role_check = 4;
+}
+
+message ProjectSearchResponse {
+ uint64 offset = 1;
+ uint64 limit = 2;
+ uint64 total_result = 3;
+ repeated ProjectView result = 4;
+ uint64 processed_sequence = 5;
+ google.protobuf.Timestamp view_timestamp = 6;
+}
+
+message ProjectView {
+ string project_id = 1;
+ string name = 2;
+ ProjectState state = 3;
+ google.protobuf.Timestamp change_date = 4;
+ google.protobuf.Timestamp creation_date = 5;
+ string resource_owner = 6;
+ uint64 sequence = 7;
+ bool project_role_assertion = 8;
+ bool project_role_check = 9;
+}
+
+message ProjectSearchRequest {
+ uint64 offset = 1;
+ uint64 limit = 2;
+ repeated ProjectSearchQuery queries = 3;
+}
+
+message ProjectSearchQuery {
+ ProjectSearchKey key = 1 [(validate.rules).enum = {not_in: [0]}];
+ SearchMethod method = 2;
+ string value = 3;
+}
+
+enum ProjectSearchKey {
+ PROJECTSEARCHKEY_UNSPECIFIED = 0;
+ PROJECTSEARCHKEY_PROJECT_NAME = 1;
+}
+
+message Projects {
+ repeated Project projects = 1;
+}
+
+message Project {
+ string id = 1;
+ string name = 2;
+ ProjectState state = 3;
+ google.protobuf.Timestamp change_date = 4;
+ google.protobuf.Timestamp creation_date = 5;
+ uint64 sequence = 6;
+ bool project_role_assertion = 7;
+ bool project_role_check = 8;
+}
+
+enum ProjectState {
+ PROJECTSTATE_UNSPECIFIED = 0;
+ PROJECTSTATE_ACTIVE = 1;
+ PROJECTSTATE_INACTIVE = 2;
+}
+
+message ProjectMemberRoles {
+ repeated string roles = 1;
+}
+
+message ProjectMember {
+ string user_id = 1;
+ repeated string roles = 2;
+ google.protobuf.Timestamp change_date = 3;
+ google.protobuf.Timestamp creation_date = 4;
+ uint64 sequence = 5;
+}
+
+message ProjectMemberAdd {
+ string id = 1 [(validate.rules).string = {min_len: 1}];
+ string user_id = 2 [(validate.rules).string = {min_len: 1}];
+ repeated string roles = 3;
+}
+
+message ProjectMemberChange {
+ string id = 1 [(validate.rules).string = {min_len: 1}];
+ string user_id = 2 [(validate.rules).string = {min_len: 1}];
+ repeated string roles = 3;
+}
+
+message ProjectMemberRemove {
+ string id = 1 [(validate.rules).string = {min_len: 1}];
+ string user_id = 2 [(validate.rules).string = {min_len: 1}];
+}
+
+message ProjectRoleAdd {
+ string id = 1 [(validate.rules).string = {min_len: 1}];
+ string key = 2;
+ string display_name = 3;
+ string group = 4;
+}
+
+message ProjectRoleAddBulk {
+ string id = 1 [(validate.rules).string = {min_len: 1}];
+ repeated ProjectRoleAdd project_roles = 2;
+}
+
+message ProjectRoleChange {
+ string id = 1 [(validate.rules).string = {min_len: 1}];
+ string key = 2 [(validate.rules).string = {min_len: 1}];
+ string display_name = 3;
+ string group = 4;
+}
+
+message ProjectRole {
+ string project_id = 1;
+ string key = 2;
+ string display_name = 3;
+ google.protobuf.Timestamp creation_date = 4;
+ google.protobuf.Timestamp change_date = 5;
+ string group = 6;
+ uint64 sequence = 7;
+}
+
+message ProjectRoleView {
+ string project_id = 1;
+ string key = 2;
+ string display_name = 3;
+ google.protobuf.Timestamp creation_date = 4;
+ google.protobuf.Timestamp change_date = 5;
+ string group = 6;
+ uint64 sequence = 7;
+}
+
+message ProjectRoleRemove {
+ string id = 1 [(validate.rules).string = {min_len: 1}];
+ string key = 2 [(validate.rules).string = {min_len: 1}];
+}
+
+message ProjectRoleSearchResponse {
+ uint64 offset = 1;
+ uint64 limit = 2;
+ uint64 total_result = 3;
+ repeated ProjectRoleView result = 4;
+ uint64 processed_sequence = 5;
+ google.protobuf.Timestamp view_timestamp = 6;
+}
+
+message ProjectRoleSearchRequest {
+ string project_id = 1 [(validate.rules).string = {min_len: 1}];
+ uint64 offset = 2;
+ uint64 limit = 3;
+ repeated ProjectRoleSearchQuery queries = 4;
+}
+
+message ProjectRoleSearchQuery {
+ ProjectRoleSearchKey key = 1 [(validate.rules).enum = {not_in: [0]}];
+ SearchMethod method = 2;
+ string value = 3;
+}
+
+enum ProjectRoleSearchKey {
+ PROJECTROLESEARCHKEY_UNSPECIFIED = 0;
+ PROJECTROLESEARCHKEY_KEY = 1;
+ PROJECTROLESEARCHKEY_DISPLAY_NAME = 2;
+}
+
+message ProjectMemberView {
+ string user_id = 1;
+ string user_name = 2;
+ string email = 3;
+ string first_name = 4;
+ string last_name = 5;
+ repeated string roles = 6;
+ google.protobuf.Timestamp change_date = 7;
+ google.protobuf.Timestamp creation_date = 8;
+ uint64 sequence = 10;
+ string display_name = 11;
+}
+
+message ProjectMemberSearchResponse {
+ uint64 offset = 1;
+ uint64 limit = 2;
+ uint64 total_result = 3;
+ repeated ProjectMemberView result = 4;
+ uint64 processed_sequence = 5;
+ google.protobuf.Timestamp view_timestamp = 6;
+}
+
+message ProjectMemberSearchRequest {
+ string project_id = 1 [(validate.rules).string = {min_len: 1}];
+ uint64 offset = 2;
+ uint64 limit = 3;
+ repeated ProjectMemberSearchQuery queries = 4;
+}
+
+message ProjectMemberSearchQuery {
+ ProjectMemberSearchKey key = 1 [(validate.rules).enum = {not_in: [0]}];
+ SearchMethod method = 2;
+ string value = 3;
+}
+
+enum ProjectMemberSearchKey {
+ PROJECTMEMBERSEARCHKEY_UNSPECIFIED = 0;
+ PROJECTMEMBERSEARCHKEY_FIRST_NAME = 1;
+ PROJECTMEMBERSEARCHKEY_LAST_NAME = 2;
+ PROJECTMEMBERSEARCHKEY_EMAIL = 3;
+ PROJECTMEMBERSEARCHKEY_USER_ID = 4;
+ PROJECTMEMBERSEARCHKEY_USER_NAME = 5;
+}
+
+enum AppState {
+ APPSTATE_UNSPECIFIED = 0;
+ APPSTATE_ACTIVE = 1;
+ APPSTATE_INACTIVE = 2;
+}
+
+message Application {
+ string id = 1;
+ AppState state = 2;
+ google.protobuf.Timestamp creation_date = 3;
+ google.protobuf.Timestamp change_date = 4;
+ string name = 5;
+ oneof app_config {
+ OIDCConfig oidc_config = 8;
+ APIConfig api_config = 10;
+ }
+ uint64 sequence = 9;
+}
+
+message ApplicationUpdate {
+ string project_id = 1 [(validate.rules).string = {min_len: 1}];
+ string id = 2 [(validate.rules).string = {min_len: 1}];
+ string name = 5 [(validate.rules).string = {min_len: 1, max_len: 200}];
+}
+
+message OIDCConfig {
+ repeated string redirect_uris = 1;
+ repeated OIDCResponseType response_types = 2;
+ repeated OIDCGrantType grant_types = 3;
+ OIDCApplicationType application_type = 4;
+ string client_id = 5;
+ string client_secret = 6;
+ OIDCAuthMethodType auth_method_type = 7;
+ repeated string post_logout_redirect_uris = 8;
+ OIDCVersion version = 9;
+ bool none_compliant = 10;
+ repeated caos.zitadel.api.v1.LocalizedMessage compliance_problems = 11;
+ bool dev_mode = 12;
+ OIDCTokenType access_token_type = 13;
+ bool access_token_role_assertion = 14;
+ bool id_token_role_assertion = 15;
+ bool id_token_userinfo_assertion = 16;
+ google.protobuf.Duration clock_skew = 17;
+}
+
+message OIDCApplicationCreate {
+ string project_id = 1 [(validate.rules).string = {min_len: 1}];
+ string name = 2 [(validate.rules).string = {min_len: 1, max_len: 200}];
+ repeated string redirect_uris = 3;
+ repeated OIDCResponseType response_types = 4;
+ repeated OIDCGrantType grant_types = 5;
+ OIDCApplicationType application_type = 6;
+ OIDCAuthMethodType auth_method_type = 7;
+ repeated string post_logout_redirect_uris = 8;
+ OIDCVersion version = 9;
+ bool dev_mode = 10;
+ OIDCTokenType access_token_type = 11;
+ bool access_token_role_assertion = 12;
+ bool id_token_role_assertion = 13;
+ bool id_token_userinfo_assertion = 14;
+ google.protobuf.Duration clock_skew = 15 [(validate.rules).duration = {gte: {}, lte: {seconds: 5}}];
+}
+
+message APIApplicationCreate {
+ string project_id = 1 [(validate.rules).string = {min_len: 1}];
+ string name = 2 [(validate.rules).string = {min_len: 1, max_len: 200}];
+ APIAuthMethodType auth_method_type = 3;
+}
+
+message APIConfig {
+ string client_id = 1;
+ string client_secret = 2;
+ APIAuthMethodType auth_method_type = 3;
+}
+
+enum OIDCVersion {
+ OIDCV1_0 = 0;
+}
+
+enum OIDCTokenType {
+ OIDCTokenType_Bearer = 0;
+ OIDCTokenType_JWT = 1;
+}
+
+message OIDCConfigUpdate {
+ string project_id = 1 [(validate.rules).string = {min_len: 1}];
+ string application_id = 2 [(validate.rules).string = {min_len: 1}];
+ repeated string redirect_uris = 3;
+ repeated OIDCResponseType response_types = 4;
+ repeated OIDCGrantType grant_types = 5;
+ OIDCApplicationType application_type = 6;
+ OIDCAuthMethodType auth_method_type = 7;
+ repeated string post_logout_redirect_uris = 8;
+ bool dev_mode = 9;
+ OIDCTokenType access_token_type = 10;
+ bool access_token_role_assertion = 11;
+ bool id_token_role_assertion = 12;
+ bool id_token_userinfo_assertion = 13;
+ google.protobuf.Duration clock_skew = 14 [(validate.rules).duration = {gte: {}, lte: {seconds: 5}}];
+}
+
+message APIConfigUpdate {
+ string project_id = 1 [(validate.rules).string = {min_len: 1}];
+ string application_id = 2 [(validate.rules).string = {min_len: 1}];
+ APIAuthMethodType auth_method_type = 7;
+}
+
+enum OIDCResponseType {
+ OIDCRESPONSETYPE_CODE = 0;
+ OIDCRESPONSETYPE_ID_TOKEN = 1;
+ OIDCRESPONSETYPE_ID_TOKEN_TOKEN = 2;
+}
+
+enum OIDCGrantType {
+ OIDCGRANTTYPE_AUTHORIZATION_CODE = 0;
+ OIDCGRANTTYPE_IMPLICIT = 1;
+ OIDCGRANTTYPE_REFRESH_TOKEN = 2;
+}
+
+enum OIDCApplicationType {
+ OIDCAPPLICATIONTYPE_WEB = 0;
+ OIDCAPPLICATIONTYPE_USER_AGENT = 1;
+ OIDCAPPLICATIONTYPE_NATIVE = 2;
+}
+
+enum OIDCAuthMethodType {
+ OIDCAUTHMETHODTYPE_BASIC = 0;
+ OIDCAUTHMETHODTYPE_POST = 1;
+ OIDCAUTHMETHODTYPE_NONE = 2;
+ OIDCAUTHMETHODTYPE_PRIVATE_KEY_JWT = 3;
+}
+
+enum APIAuthMethodType {
+ APIAUTHMETHODTYPE_BASIC = 0;
+ APIAUTHMETHODTYPE_PRIVATE_KEY_JWT = 1;
+}
+
+message ClientSecret {
+ string client_secret = 1;
+}
+
+message ApplicationView {
+ string id = 1;
+ AppState state = 2;
+ google.protobuf.Timestamp creation_date = 3;
+ google.protobuf.Timestamp change_date = 4;
+ string name = 5;
+ oneof app_config {
+ OIDCConfig oidc_config = 8;
+ APIConfig api_config = 10;
+ }
+
+ uint64 sequence = 9;
+}
+
+message ApplicationSearchResponse {
+ uint64 offset = 1;
+ uint64 limit = 2;
+ uint64 total_result = 3;
+ repeated ApplicationView result = 4;
+ uint64 processed_sequence = 5;
+ google.protobuf.Timestamp view_timestamp = 6;
+}
+
+message ApplicationSearchRequest {
+ string project_id = 1 [(validate.rules).string = {min_len: 1}];
+ uint64 offset = 2;
+ uint64 limit = 3;
+ repeated ApplicationSearchQuery queries = 4;
+}
+
+message ApplicationSearchQuery {
+ ApplicationSearchKey key = 1 [(validate.rules).enum = {not_in: [0]}];
+ SearchMethod method = 2;
+ string value = 3;
+}
+
+enum ApplicationSearchKey {
+ APPLICATIONSERACHKEY_UNSPECIFIED = 0;
+ APPLICATIONSEARCHKEY_APP_NAME = 1;
+}
+
+message AddClientKeyRequest {
+ string project_id = 1 [(validate.rules).string.min_len = 1];
+ string application_id = 2 [(validate.rules).string.min_len = 1];
+ AuthNKeyType type = 3 [(validate.rules).enum = {not_in: [0]}];
+ google.protobuf.Timestamp expiration_date = 4;
+}
+
+message AddClientKeyResponse {
+ string id = 1;
+ google.protobuf.Timestamp creation_date = 2;
+ uint64 sequence = 3;
+
+ AuthNKeyType type = 4;
+ google.protobuf.Timestamp expiration_date = 5;
+ bytes key_details = 6;
+}
+
+message ClientKeyIDRequest {
+ string project_id = 1 [(validate.rules).string.min_len = 1];
+ string application_id = 2 [(validate.rules).string.min_len = 1];
+ string key_id = 3 [(validate.rules).string.min_len = 1];
+}
+
+message ClientKeyView {
+ string id = 1;
+ AuthNKeyType type = 2;
+ uint64 sequence = 3;
+
+ google.protobuf.Timestamp creation_date = 4;
+ google.protobuf.Timestamp expiration_date = 5;
+}
+
+enum AuthNKeyType {
+ AUTHNKEY_UNSPECIFIED = 0;
+ AUTHNKEY_JSON = 1;
+}
+
+message ClientKeySearchRequest {
+ uint64 offset = 1;
+ uint64 limit = 2;
+ bool asc = 3;
+ string project_id = 4 [(validate.rules).string.min_len = 1];
+ string application_id = 5 [(validate.rules).string.min_len = 1];
+}
+
+message ClientKeySearchResponse {
+ uint64 offset = 1;
+ uint64 limit = 2;
+ uint64 total_result = 3;
+ repeated ClientKeyView result = 4;
+ uint64 processed_sequence = 5;
+ google.protobuf.Timestamp view_timestamp = 6;
+}
+
+message ProjectGrant {
+ string id = 1;
+ string project_id = 2;
+ string granted_org_id = 3;
+ repeated string role_keys = 4;
+ ProjectGrantState state = 5;
+ google.protobuf.Timestamp creation_date = 6;
+ google.protobuf.Timestamp change_date = 7;
+ uint64 sequence = 9;
+}
+
+message ProjectGrantCreate {
+ string project_id = 1 [(validate.rules).string = {min_len: 1}];
+ string granted_org_id = 2 [(validate.rules).string = {min_len: 1}];
+ repeated string role_keys = 3;
+}
+
+message ProjectGrantUpdate {
+ string project_id = 1 [(validate.rules).string = {min_len: 1}];
+ string id = 2 [(validate.rules).string = {min_len: 1}];
+ repeated string role_keys = 3;
+}
+
+message ProjectGrantID {
+ string project_id = 1 [(validate.rules).string = {min_len: 1}];
+ string id = 2 [(validate.rules).string = {min_len: 1}];
+}
+
+enum ProjectGrantState {
+ PROJECTGRANTSTATE_UNSPECIFIED = 0;
+ PROJECTGRANTSTATE_ACTIVE = 1;
+ PROJECTGRANTSTATE_INACTIVE = 2;
+}
+
+message ProjectGrantView {
+ string id = 1;
+ string project_id = 2;
+ string granted_org_id = 3;
+ string granted_org_name = 4;
+ repeated string role_keys = 5;
+ ProjectGrantState state = 6;
+ google.protobuf.Timestamp creation_date = 7;
+ google.protobuf.Timestamp change_date = 8;
+ string project_name = 9;
+ uint64 sequence = 10;
+ string resource_owner = 11;
+ string resource_owner_name = 12;
+}
+
+message ProjectGrantSearchResponse {
+ uint64 offset = 1;
+ uint64 limit = 2;
+ uint64 total_result = 3;
+ repeated ProjectGrantView result = 4;
+ uint64 processed_sequence = 5;
+ google.protobuf.Timestamp view_timestamp = 6;
+}
+
+message GrantedProjectSearchRequest {
+ uint64 offset = 1;
+ uint64 limit = 2;
+ repeated ProjectSearchQuery queries = 3;
+}
+
+message ProjectGrantSearchRequest {
+ string project_id = 1 [(validate.rules).string = {min_len: 1}];
+ uint64 offset = 2;
+ uint64 limit = 3;
+ repeated ProjectGrantSearchQuery queries = 4;
+}
+
+message ProjectGrantSearchQuery {
+ ProjectGrantSearchKey key = 1 [(validate.rules).enum = {not_in: [0]}];
+ SearchMethod method = 2;
+ string value = 3;
+}
+
+enum ProjectGrantSearchKey {
+ PROJECTGRANTSEARCHKEY_UNSPECIFIED = 0;
+ PROJECTGRANTSEARCHKEY_PROJECT_NAME = 1;
+ PROJECTGRANTSEARCHKEY_ROLE_KEY = 2;
+}
+
+message ProjectGrantMemberRoles {
+ repeated string roles = 1;
+}
+
+message ProjectGrantMember {
+ string user_id = 1;
+ repeated string roles = 2;
+ google.protobuf.Timestamp change_date = 3;
+ google.protobuf.Timestamp creation_date = 4;
+ uint64 sequence = 5;
+}
+
+message ProjectGrantMemberAdd {
+ string project_id = 1 [(validate.rules).string = {min_len: 1}];
+ string grant_id = 2 [(validate.rules).string = {min_len: 1}];
+ string user_id = 3 [(validate.rules).string = {min_len: 1}];
+ repeated string roles = 4;
+}
+
+message ProjectGrantMemberChange {
+ string project_id = 1 [(validate.rules).string = {min_len: 1}];
+ string grant_id = 2 [(validate.rules).string = {min_len: 1}];
+ string user_id = 3 [(validate.rules).string = {min_len: 1}];
+ repeated string roles = 4;
+}
+
+message ProjectGrantMemberRemove {
+ string project_id = 1 [(validate.rules).string = {min_len: 1}];
+ string grant_id = 2 [(validate.rules).string = {min_len: 1}];
+ string user_id = 3 [(validate.rules).string = {min_len: 1}];
+}
+
+message ProjectGrantMemberView {
+ string user_id = 1;
+ string user_name = 2;
+ string email = 3;
+ string first_name = 4;
+ string last_name = 5;
+ repeated string roles = 6;
+ google.protobuf.Timestamp change_date = 7;
+ google.protobuf.Timestamp creation_date = 8;
+ uint64 sequence = 9;
+ string display_name = 10;
+}
+
+message ProjectGrantMemberSearchResponse {
+ uint64 offset = 1;
+ uint64 limit = 2;
+ uint64 total_result = 3;
+ repeated ProjectGrantMemberView result = 4;
+ uint64 processed_sequence = 5;
+ google.protobuf.Timestamp view_timestamp = 6;
+}
+
+message ProjectGrantMemberSearchRequest {
+ string project_id = 1 [(validate.rules).string = {min_len: 1}];
+ string grant_id = 2 [(validate.rules).string = {min_len: 1}];
+ uint64 offset = 3;
+ uint64 limit = 4;
+ repeated ProjectGrantMemberSearchQuery queries = 5;
+}
+
+message ProjectGrantMemberSearchQuery {
+ ProjectGrantMemberSearchKey key = 1 [(validate.rules).enum = {not_in: [0]}];
+ SearchMethod method = 2;
+ string value = 3;
+}
+
+enum ProjectGrantMemberSearchKey {
+ PROJECTGRANTMEMBERSEARCHKEY_UNSPECIFIED = 0;
+ PROJECTGRANTMEMBERSEARCHKEY_FIRST_NAME = 1;
+ PROJECTGRANTMEMBERSEARCHKEY_LAST_NAME = 2;
+ PROJECTGRANTMEMBERSEARCHKEY_EMAIL = 3;
+ PROJECTGRANTMEMBERSEARCHKEY_USER_ID = 4;
+ PROJECTGRANTMEMBERSEARCHKEY_USER_NAME = 5;
+}
+
+message UserGrant {
+ string id = 1;
+ string user_id = 2;
+ string org_id = 3;
+ string project_id = 4;
+ repeated string role_keys = 5;
+ UserGrantState state = 6;
+ google.protobuf.Timestamp creation_date = 7;
+ google.protobuf.Timestamp change_date = 8;
+ uint64 sequence = 9;
+ string grant_id = 10;
+}
+
+message UserGrantCreate {
+ string user_id = 1 [(validate.rules).string = {min_len: 1}];
+ string project_id = 2 [(validate.rules).string = {min_len: 1}];
+ repeated string role_keys = 3;
+ string grant_id = 4;
+}
+
+message UserGrantUpdate {
+ string user_id = 1 [(validate.rules).string = {min_len: 1}];
+ string id = 2 [(validate.rules).string = {min_len: 1}];
+ repeated string role_keys = 3;
+}
+
+message UserGrantRemoveBulk {
+ repeated string ids = 1 [(validate.rules).repeated.min_items = 1];
+}
+
+message UserGrantID {
+ string user_id = 1 [(validate.rules).string = {min_len: 1}];
+ string id = 2 [(validate.rules).string = {min_len: 1}];
+}
+
+enum UserGrantState {
+ USERGRANTSTATE_UNSPECIFIED = 0;
+ USERGRANTSTATE_ACTIVE = 1;
+ USERGRANTSTATE_INACTIVE = 2;
+}
+
+message UserGrantView {
+ string id = 1;
+ string user_id = 2;
+ string org_id = 3;
+ string project_id = 4;
+ repeated string role_keys = 5;
+ UserGrantState state = 6;
+ google.protobuf.Timestamp creation_date = 7;
+ google.protobuf.Timestamp change_date = 8;
+ string user_name = 9;
+ string first_name = 10;
+ string last_name = 11;
+ string email = 12;
+ string org_name = 13;
+ string org_domain = 14;
+ string project_name = 15;
+ uint64 sequence = 16;
+ string resource_owner = 17;
+ string display_name = 18;
+ string grant_id = 19;
+}
+
+
+message UserGrantSearchResponse {
+ uint64 offset = 1;
+ uint64 limit = 2;
+ uint64 total_result = 3;
+ repeated UserGrantView result = 4;
+ uint64 processed_sequence = 5;
+ google.protobuf.Timestamp view_timestamp = 6;
+}
+
+message UserGrantSearchRequest {
+ uint64 offset = 1;
+ uint64 limit = 2;
+ repeated UserGrantSearchQuery queries = 3;
+}
+
+message UserGrantSearchQuery {
+ UserGrantSearchKey key = 1 [(validate.rules).enum = {not_in: [0]}];
+ SearchMethod method = 2 [(validate.rules).enum.defined_only = true];
+ string value = 3;
+}
+
+enum UserGrantSearchKey {
+ USERGRANTSEARCHKEY_UNSPECIFIED = 0;
+ USERGRANTSEARCHKEY_PROJECT_ID = 1;
+ USERGRANTSEARCHKEY_USER_ID = 2;
+ USERGRANTSEARCHKEY_WITH_GRANTED = 3;
+ USERGRANTSEARCHKEY_ROLE_KEY = 4;
+ USERGRANTSEARCHKEY_GRANT_ID = 5;
+ USERGRANTSEARCHKEY_USER_NAME = 6;
+ USERGRANTSEARCHKEY_FIRST_NAME = 7;
+ USERGRANTSEARCHKEY_LAST_NAME = 8;
+ USERGRANTSEARCHKEY_EMAIL = 9;
+ USERGRANTSEARCHKEY_ORG_NAME = 10;
+ USERGRANTSEARCHKEY_ORG_DOMAIN = 11;
+ USERGRANTSEARCHKEY_PROJECT_NAME = 12;
+ USERGRANTSEARCHKEY_DISPLAY_NAME = 13;
+}
+
+message UserMembershipSearchResponse {
+ uint64 offset = 1;
+ uint64 limit = 2;
+ uint64 total_result = 3;
+ repeated UserMembershipView result = 4;
+ uint64 processed_sequence = 5;
+ google.protobuf.Timestamp view_timestamp = 6;
+}
+
+message UserMembershipSearchRequest {
+ string user_id = 1 [(validate.rules).string = {min_len: 1}];
+ uint64 offset = 2;
+ uint64 limit = 3;
+ repeated UserMembershipSearchQuery queries = 4;
+}
+
+message UserMembershipSearchQuery {
+ UserMembershipSearchKey key = 1 [(validate.rules).enum = {not_in: [0]}];
+ SearchMethod method = 2 [(validate.rules).enum = {in: [0]}];
+ string value = 3;
+}
+
+enum UserMembershipSearchKey {
+ USERMEMBERSHIPSEARCHKEY_UNSPECIFIED = 0;
+ USERMEMBERSHIPSEARCHKEY_TYPE = 1;
+ USERMEMBERSHIPSEARCHKEY_OBJECT_ID = 2;
+}
+
+message UserMembershipView {
+ string user_id = 1;
+ MemberType member_type = 2;
+ string aggregate_id = 3;
+ string object_id = 4;
+ repeated string roles = 5;
+ string display_name = 6;
+ google.protobuf.Timestamp creation_date = 7;
+ google.protobuf.Timestamp change_date = 8;
+ uint64 sequence = 9;
+ string resource_owner = 10;
+}
+
+enum MemberType {
+ MEMBERTYPE_UNSPECIFIED = 0;
+ MEMBERTYPE_ORGANISATION = 1;
+ MEMBERTYPE_PROJECT = 2;
+ MEMBERTYPE_PROJECT_GRANT = 3;
+}
+
+message IdpID {
+ string id = 1 [(validate.rules).string = {min_len: 1}];
+}
+
+message Idp {
+ string id = 1;
+ IdpState state = 2;
+ google.protobuf.Timestamp creation_date = 3;
+ google.protobuf.Timestamp change_date = 4;
+ string name = 5;
+ IdpStylingType styling_type = 6;
+ oneof idp_config {
+ OidcIdpConfig oidc_config = 7;
+ }
+ uint64 sequence = 8;
+}
+
+message IdpUpdate {
+ string id = 1 [(validate.rules).string = {min_len: 1}];
+ string name = 2 [(validate.rules).string = {min_len: 1, max_len: 200}];
+ IdpStylingType styling_type = 3;
+}
+
+message OidcIdpConfig {
+ string client_id = 1;
+ string client_secret = 2;
+ string issuer = 3;
+ repeated string scopes = 4;
+ OIDCMappingField idp_display_name_mapping = 5;
+ OIDCMappingField username_mapping = 6;
+}
+
+enum IdpStylingType {
+ IDPSTYLINGTYPE_UNSPECIFIED = 0;
+ IDPSTYLINGTYPE_GOOGLE = 1;
+}
+
+enum IdpState {
+ IDPCONFIGSTATE_UNSPECIFIED = 0;
+ IDPCONFIGSTATE_ACTIVE = 1;
+ IDPCONFIGSTATE_INACTIVE = 2;
+}
+
+enum OIDCMappingField {
+ OIDCMAPPINGFIELD_UNSPECIFIED = 0;
+ OIDCMAPPINGFIELD_PREFERRED_USERNAME = 1;
+ OIDCMAPPINGFIELD_EMAIL = 2;
+}
+
+message OidcIdpConfigCreate {
+ string name = 1 [(validate.rules).string = {min_len: 1, max_len: 200}];
+ IdpStylingType styling_type = 2;
+ string client_id = 3 [(validate.rules).string = {min_len: 1, max_len: 200}];
+ string client_secret = 4 [(validate.rules).string = {min_len: 1, max_len: 200}];
+ string issuer = 5 [(validate.rules).string = {min_len: 1, max_len: 200}];
+ repeated string scopes = 6;
+ OIDCMappingField idp_display_name_mapping = 7;
+ OIDCMappingField username_mapping = 8;
+}
+
+message OidcIdpConfigUpdate {
+ string idp_id = 1 [(validate.rules).string = {min_len: 1}];
+ string client_id = 2 [(validate.rules).string = {min_len: 1, max_len: 200}];
+ string client_secret = 3;
+ string issuer = 4 [(validate.rules).string = {min_len: 1, max_len: 200}];
+ repeated string scopes = 5;
+ OIDCMappingField idp_display_name_mapping = 6;
+ OIDCMappingField username_mapping = 7;
+}
+
+message IdpSearchResponse {
+ uint64 offset = 1;
+ uint64 limit = 2;
+ uint64 total_result = 3;
+ repeated IdpView result = 4;
+ uint64 processed_sequence = 5;
+ google.protobuf.Timestamp view_timestamp = 6;
+}
+
+message IdpView {
+ string id = 1;
+ IdpState state = 2;
+ google.protobuf.Timestamp creation_date = 3;
+ google.protobuf.Timestamp change_date = 4;
+ string name = 5;
+ IdpStylingType styling_type = 6;
+ IdpProviderType provider_type = 7;
+ oneof idp_config_view {
+ OidcIdpConfigView oidc_config = 8;
+ }
+ uint64 sequence = 9;
+}
+
+message OidcIdpConfigView {
+ string client_id = 1;
+ string issuer = 2;
+ repeated string scopes = 3;
+ OIDCMappingField idp_display_name_mapping = 4;
+ OIDCMappingField username_mapping = 5;
+}
+
+message IdpSearchRequest {
+ uint64 offset = 1;
+ uint64 limit = 2;
+ repeated IdpSearchQuery queries = 3;
+}
+
+message IdpSearchQuery {
+ IdpSearchKey key = 1 [(validate.rules).enum = {not_in: [0]}];
+ SearchMethod method = 2;
+ string value = 3;
+}
+
+enum IdpSearchKey {
+ IDPSEARCHKEY_UNSPECIFIED = 0;
+ IDPSEARCHKEY_IDP_CONFIG_ID = 1;
+ IDPSEARCHKEY_NAME = 2;
+ IDPSEARCHKEY_PROVIDER_TYPE = 3;
+}
+
+message LoginPolicy {
+ bool allow_username_password = 1;
+ bool allow_register = 2;
+ bool allow_external_idp = 3;
+ google.protobuf.Timestamp creation_date = 4;
+ google.protobuf.Timestamp change_date = 5;
+ bool force_mfa = 6;
+ PasswordlessType passwordless_type = 7;
+}
+
+message LoginPolicyRequest {
+ bool allow_username_password = 1;
+ bool allow_register = 2;
+ bool allow_external_idp = 3;
+ bool force_mfa = 4;
+ PasswordlessType passwordless_type = 5;
+}
+
+enum PasswordlessType {
+ PASSWORDLESSTYPE_NOT_ALLOWED = 0;
+ PASSWORDLESSTYPE_ALLOWED = 1;
+}
+
+
+message IdpProviderID {
+ string idp_config_id = 1 [(validate.rules).string = {min_len: 1}];
+}
+
+message IdpProviderAdd {
+ string idp_config_id = 1 [(validate.rules).string = {min_len: 1, max_len: 200}];
+ IdpProviderType idp_provider_type = 2 [(validate.rules).enum = {not_in: [0]}];
+}
+
+message IdpProvider {
+ string idp_config_id = 1;
+ IdpProviderType idp_provider_Type = 2;
+}
+
+message LoginPolicyView {
+ bool default = 1;
+ bool allow_username_password = 2;
+ bool allow_register = 3;
+ bool allow_external_idp = 4;
+ google.protobuf.Timestamp creation_date = 5;
+ google.protobuf.Timestamp change_date = 6;
+ bool force_mfa = 7;
+ PasswordlessType passwordless_type = 8;
+}
+
+message IdpProviderView {
+ string idp_config_id = 1;
+ string name = 2;
+ IdpProviderType type = 3;
+}
+
+enum IdpType {
+ IDPTYPE_UNSPECIFIED = 0;
+ IDPTYPE_OIDC = 1;
+ IDPTYPE_SAML = 2;
+}
+
+enum IdpProviderType {
+ IDPPROVIDERTYPE_UNSPECIFIED = 0;
+ IDPPROVIDERTYPE_SYSTEM = 1;
+ IDPPROVIDERTYPE_ORG = 2;
+}
+
+message IdpProviderSearchResponse {
+ uint64 offset = 1;
+ uint64 limit = 2;
+ uint64 total_result = 3;
+ repeated IdpProviderView result = 4;
+ uint64 processed_sequence = 5;
+ google.protobuf.Timestamp view_timestamp = 6;
+}
+
+message IdpProviderSearchRequest {
+ uint64 offset = 1;
+ uint64 limit = 2;
+}
+
+//ProjectType is deprecated, remove as soon as console is ready
+enum ProjectType {
+ PROJECTTYPE_UNSPECIFIED = 0;
+ PROJECTTYPE_OWNED = 1;
+ PROJECTTYPE_GRANTED = 2;
+}
+
+message ExternalIDPSearchRequest {
+ uint64 offset = 1;
+ uint64 limit = 2;
+ string user_id = 3;
+}
+
+message ExternalIDPSearchResponse {
+ uint64 offset = 1;
+ uint64 limit = 2;
+ uint64 total_result = 3;
+ repeated ExternalIDPView result = 4;
+ uint64 processed_sequence = 5;
+ google.protobuf.Timestamp view_timestamp = 6;
+}
+
+message ExternalIDPView {
+ string user_id = 1;
+ string idp_config_id = 2;
+ string external_user_id = 3;
+ string idp_name = 4;
+ string external_user_display_name = 5;
+ google.protobuf.Timestamp creation_date = 6;
+ google.protobuf.Timestamp change_date = 7;
+}
+
+message ExternalIDPRemoveRequest {
+ string user_id = 1;
+ string idp_config_id = 2;
+ string external_user_id = 3;
+}
+
+message SecondFactorsResult {
+ repeated SecondFactorType second_factors = 1;
+}
+
+message SecondFactor {
+ SecondFactorType second_factor = 1;
+}
+
+enum SecondFactorType {
+ SECONDFACTORTYPE_UNSPECIFIED = 0;
+ SECONDFACTORTYPE_OTP = 1;
+ SECONDFACTORTYPE_U2F = 2;
+}
+
+message MultiFactorsResult {
+ repeated MultiFactorType multi_factors = 1;
+}
+
+message MultiFactor {
+ MultiFactorType multi_factor = 1;
+}
+
+enum MultiFactorType {
+ MULTIFACTORTYPE_UNSPECIFIED = 0;
+ MULTIFACTORTYPE_U2F_WITH_PIN = 1;
+}
+
+message PasswordComplexityPolicy {
+ uint64 min_length = 1;
+ bool has_lowercase = 2;
+ bool has_uppercase = 3;
+ bool has_number = 4;
+ bool has_symbol = 5;
+ uint64 sequence = 6;
+ google.protobuf.Timestamp creation_date = 7;
+ google.protobuf.Timestamp change_date = 8;
+}
+
+message PasswordComplexityPolicyRequest {
+ uint64 min_length = 1;
+ bool has_lowercase = 2;
+ bool has_uppercase = 3;
+ bool has_number = 4;
+ bool has_symbol = 5;
+}
+
+message PasswordComplexityPolicyView {
+ bool default = 1;
+ uint64 min_length = 2;
+ bool has_lowercase = 3;
+ bool has_uppercase = 4;
+ bool has_number = 5;
+ bool has_symbol = 6;
+ uint64 sequence = 7;
+ google.protobuf.Timestamp creation_date = 8;
+ google.protobuf.Timestamp change_date = 9;
+}
+
+message PasswordAgePolicy {
+ uint64 max_age_days = 1;
+ uint64 expire_warn_days = 2;
+ uint64 sequence = 3;
+ google.protobuf.Timestamp creation_date = 4;
+ google.protobuf.Timestamp change_date = 5;
+}
+
+message PasswordAgePolicyRequest {
+ uint64 max_age_days = 1;
+ uint64 expire_warn_days = 2;
+}
+
+message PasswordAgePolicyView {
+ bool default = 1;
+ uint64 max_age_days = 2;
+ uint64 expire_warn_days = 3;
+ uint64 sequence = 4;
+ google.protobuf.Timestamp creation_date = 5;
+ google.protobuf.Timestamp change_date = 6;
+}
+
+message PasswordLockoutPolicy {
+ uint64 max_attempts = 1;
+ bool show_lockout_failure = 2;
+ uint64 sequence = 3;
+ google.protobuf.Timestamp creation_date = 4;
+ google.protobuf.Timestamp change_date = 5;
+}
+
+message PasswordLockoutPolicyRequest {
+ uint64 max_attempts = 1;
+ bool show_lockout_failure = 2;
+}
+
+message PasswordLockoutPolicyView {
+ bool default = 1;
+ uint64 max_attempts = 2;
+ bool show_lockout_failure = 3;
+ uint64 sequence = 4;
+ google.protobuf.Timestamp creation_date = 5;
+ google.protobuf.Timestamp change_date = 6;
+}
+message MailTemplate {
+ bytes template = 1;
+ google.protobuf.Timestamp creation_date = 2;
+ google.protobuf.Timestamp change_date = 3;
+}
+
+message MailTemplateUpdate {
+ bytes template = 1;
+}
+
+message MailTemplateView {
+ bool default = 1;
+ bytes template = 2;
+ google.protobuf.Timestamp creation_date = 3;
+ google.protobuf.Timestamp change_date = 4;
+}
+
+message MailText {
+ string mail_text_type = 1;
+ string language = 2;
+ string title = 3;
+ string pre_header = 4;
+ string subject = 5;
+ string greeting = 6;
+ string text = 7;
+ string button_text = 8;
+ google.protobuf.Timestamp creation_date = 9;
+ google.protobuf.Timestamp change_date = 10;
+}
+
+message MailTextUpdate {
+ string mail_text_type = 1;
+ string language = 2;
+ string title = 3;
+ string pre_header = 4;
+ string subject = 5;
+ string greeting = 6;
+ string text = 7;
+ string button_text = 8;
+}
+
+message MailTextRemove {
+ string mail_text_type = 1;
+ string language = 2;
+}
+
+message MailTextsView{
+ repeated MailTextView texts = 1;
+}
+
+message MailTextView {
+ bool default = 1;
+ string mail_text_type = 2;
+ string language = 3;
+ string title = 4;
+ string pre_header = 5;
+ string subject = 6;
+ string greeting = 7;
+ string text = 8;
+ string button_text = 9;
+ google.protobuf.Timestamp creation_date = 10;
+ google.protobuf.Timestamp change_date = 11;
+}
+
+message LabelPolicy {
+ string primary_color = 1;
+ string secondary_color = 2;
+ google.protobuf.Timestamp creation_date = 3;
+ google.protobuf.Timestamp change_date = 4;
+ bool hide_login_name_suffix = 5;
+}
+
+message LabelPolicyRequest {
+ string primary_color = 1;
+ string secondary_color = 2;
+ google.protobuf.Timestamp creation_date = 3;
+ google.protobuf.Timestamp change_date = 4;
+ bool hide_login_name_suffix = 5;
+}
+
+message LabelPolicyView {
+ bool default = 1;
+ string primary_color = 2;
+ string secondary_color = 3;
+ google.protobuf.Timestamp creation_date = 4;
+ google.protobuf.Timestamp change_date = 5;
+ bool hide_login_name_suffix = 6;
+}
\ No newline at end of file
diff --git a/src/Zitadel.Api/proto/message.proto b/src/Zitadel.Api/proto/message.proto
new file mode 100644
index 00000000..535f1dee
--- /dev/null
+++ b/src/Zitadel.Api/proto/message.proto
@@ -0,0 +1,15 @@
+syntax = "proto3";
+
+package caos.zitadel.api.v1;
+
+option go_package = "github.com/caos/zitadel/pkg/grpc/message";
+
+message ErrorDetail {
+ string id = 1;
+ string message = 2;
+}
+
+message LocalizedMessage {
+ string key = 1;
+ string localized_message = 2;
+}
\ No newline at end of file
diff --git a/src/Zitadel.Api/protoc-gen-swagger/options/annotations.proto b/src/Zitadel.Api/protoc-gen-swagger/options/annotations.proto
new file mode 100644
index 00000000..5151fd5a
--- /dev/null
+++ b/src/Zitadel.Api/protoc-gen-swagger/options/annotations.proto
@@ -0,0 +1,44 @@
+syntax = "proto3";
+
+package grpc.gateway.protoc_gen_swagger.options;
+
+option go_package = "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger/options";
+
+import "google/protobuf/descriptor.proto";
+import "protoc-gen-swagger/options/openapiv2.proto";
+
+extend google.protobuf.FileOptions {
+ // ID assigned by protobuf-global-extension-registry@google.com for grpc-gateway project.
+ //
+ // All IDs are the same, as assigned. It is okay that they are the same, as they extend
+ // different descriptor messages.
+ Swagger openapiv2_swagger = 1042;
+}
+extend google.protobuf.MethodOptions {
+ // ID assigned by protobuf-global-extension-registry@google.com for grpc-gateway project.
+ //
+ // All IDs are the same, as assigned. It is okay that they are the same, as they extend
+ // different descriptor messages.
+ Operation openapiv2_operation = 1042;
+}
+extend google.protobuf.MessageOptions {
+ // ID assigned by protobuf-global-extension-registry@google.com for grpc-gateway project.
+ //
+ // All IDs are the same, as assigned. It is okay that they are the same, as they extend
+ // different descriptor messages.
+ Schema openapiv2_schema = 1042;
+}
+extend google.protobuf.ServiceOptions {
+ // ID assigned by protobuf-global-extension-registry@google.com for grpc-gateway project.
+ //
+ // All IDs are the same, as assigned. It is okay that they are the same, as they extend
+ // different descriptor messages.
+ Tag openapiv2_tag = 1042;
+}
+extend google.protobuf.FieldOptions {
+ // ID assigned by protobuf-global-extension-registry@google.com for grpc-gateway project.
+ //
+ // All IDs are the same, as assigned. It is okay that they are the same, as they extend
+ // different descriptor messages.
+ JSONSchema openapiv2_field = 1042;
+}
diff --git a/src/Zitadel.Api/protoc-gen-swagger/options/openapiv2.proto b/src/Zitadel.Api/protoc-gen-swagger/options/openapiv2.proto
new file mode 100644
index 00000000..389558cd
--- /dev/null
+++ b/src/Zitadel.Api/protoc-gen-swagger/options/openapiv2.proto
@@ -0,0 +1,648 @@
+syntax = "proto3";
+
+package grpc.gateway.protoc_gen_swagger.options;
+
+option go_package = "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger/options";
+
+import "google/protobuf/any.proto";
+import "google/protobuf/struct.proto";
+
+// `Swagger` is a representation of OpenAPI v2 specification's Swagger object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#swaggerObject
+//
+// Example:
+//
+// option (grpc.gateway.protoc_gen_swagger.options.openapiv2_swagger) = {
+// info: {
+// title: "Echo API";
+// version: "1.0";
+// description: ";
+// contact: {
+// name: "gRPC-Gateway project";
+// url: "https://github.com/grpc-ecosystem/grpc-gateway";
+// email: "none@example.com";
+// };
+// license: {
+// name: "BSD 3-Clause License";
+// url: "https://github.com/grpc-ecosystem/grpc-gateway/blob/master/LICENSE.txt";
+// };
+// };
+// schemes: HTTPS;
+// consumes: "application/json";
+// produces: "application/json";
+// };
+//
+message Swagger {
+ // Specifies the Swagger Specification version being used. It can be
+ // used by the Swagger UI and other clients to interpret the API listing. The
+ // value MUST be "2.0".
+ string swagger = 1;
+ // Provides metadata about the API. The metadata can be used by the
+ // clients if needed.
+ Info info = 2;
+ // The host (name or ip) serving the API. This MUST be the host only and does
+ // not include the scheme nor sub-paths. It MAY include a port. If the host is
+ // not included, the host serving the documentation is to be used (including
+ // the port). The host does not support path templating.
+ string host = 3;
+ // The base path on which the API is served, which is relative to the host. If
+ // it is not included, the API is served directly under the host. The value
+ // MUST start with a leading slash (/). The basePath does not support path
+ // templating.
+ // Note that using `base_path` does not change the endpoint paths that are
+ // generated in the resulting Swagger file. If you wish to use `base_path`
+ // with relatively generated Swagger paths, the `base_path` prefix must be
+ // manually removed from your `google.api.http` paths and your code changed to
+ // serve the API from the `base_path`.
+ string base_path = 4;
+ enum SwaggerScheme {
+ UNKNOWN = 0;
+ HTTP = 1;
+ HTTPS = 2;
+ WS = 3;
+ WSS = 4;
+ }
+ // The transfer protocol of the API. Values MUST be from the list: "http",
+ // "https", "ws", "wss". If the schemes is not included, the default scheme to
+ // be used is the one used to access the Swagger definition itself.
+ repeated SwaggerScheme schemes = 5;
+ // A list of MIME types the APIs can consume. This is global to all APIs but
+ // can be overridden on specific API calls. Value MUST be as described under
+ // Mime Types.
+ repeated string consumes = 6;
+ // A list of MIME types the APIs can produce. This is global to all APIs but
+ // can be overridden on specific API calls. Value MUST be as described under
+ // Mime Types.
+ repeated string produces = 7;
+ // field 8 is reserved for 'paths'.
+ reserved 8;
+ // field 9 is reserved for 'definitions', which at this time are already
+ // exposed as and customizable as proto messages.
+ reserved 9;
+ // An object to hold responses that can be used across operations. This
+ // property does not define global responses for all operations.
+ map responses = 10;
+ // Security scheme definitions that can be used across the specification.
+ SecurityDefinitions security_definitions = 11;
+ // A declaration of which security schemes are applied for the API as a whole.
+ // The list of values describes alternative security schemes that can be used
+ // (that is, there is a logical OR between the security requirements).
+ // Individual operations can override this definition.
+ repeated SecurityRequirement security = 12;
+ // field 13 is reserved for 'tags', which are supposed to be exposed as and
+ // customizable as proto services. TODO(ivucica): add processing of proto
+ // service objects into OpenAPI v2 Tag objects.
+ reserved 13;
+ // Additional external documentation.
+ ExternalDocumentation external_docs = 14;
+ map extensions = 15;
+}
+
+// `Operation` is a representation of OpenAPI v2 specification's Operation object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#operationObject
+//
+// Example:
+//
+// service EchoService {
+// rpc Echo(SimpleMessage) returns (SimpleMessage) {
+// option (google.api.http) = {
+// get: "/v1/example/echo/{id}"
+// };
+//
+// option (grpc.gateway.protoc_gen_swagger.options.openapiv2_operation) = {
+// summary: "Get a message.";
+// operation_id: "getMessage";
+// tags: "echo";
+// responses: {
+// key: "200"
+// value: {
+// description: "OK";
+// }
+// }
+// };
+// }
+// }
+message Operation {
+ // A list of tags for API documentation control. Tags can be used for logical
+ // grouping of operations by resources or any other qualifier.
+ repeated string tags = 1;
+ // A short summary of what the operation does. For maximum readability in the
+ // swagger-ui, this field SHOULD be less than 120 characters.
+ string summary = 2;
+ // A verbose explanation of the operation behavior. GFM syntax can be used for
+ // rich text representation.
+ string description = 3;
+ // Additional external documentation for this operation.
+ ExternalDocumentation external_docs = 4;
+ // Unique string used to identify the operation. The id MUST be unique among
+ // all operations described in the API. Tools and libraries MAY use the
+ // operationId to uniquely identify an operation, therefore, it is recommended
+ // to follow common programming naming conventions.
+ string operation_id = 5;
+ // A list of MIME types the operation can consume. This overrides the consumes
+ // definition at the Swagger Object. An empty value MAY be used to clear the
+ // global definition. Value MUST be as described under Mime Types.
+ repeated string consumes = 6;
+ // A list of MIME types the operation can produce. This overrides the produces
+ // definition at the Swagger Object. An empty value MAY be used to clear the
+ // global definition. Value MUST be as described under Mime Types.
+ repeated string produces = 7;
+ // field 8 is reserved for 'parameters'.
+ reserved 8;
+ // The list of possible responses as they are returned from executing this
+ // operation.
+ map responses = 9;
+ // The transfer protocol for the operation. Values MUST be from the list:
+ // "http", "https", "ws", "wss". The value overrides the Swagger Object
+ // schemes definition.
+ repeated string schemes = 10;
+ // Declares this operation to be deprecated. Usage of the declared operation
+ // should be refrained. Default value is false.
+ bool deprecated = 11;
+ // A declaration of which security schemes are applied for this operation. The
+ // list of values describes alternative security schemes that can be used
+ // (that is, there is a logical OR between the security requirements). This
+ // definition overrides any declared top-level security. To remove a top-level
+ // security declaration, an empty array can be used.
+ repeated SecurityRequirement security = 12;
+ map extensions = 13;
+}
+
+// `Header` is a representation of OpenAPI v2 specification's Header object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#headerObject
+//
+message Header {
+ // `Description` is a short description of the header.
+ string description = 1;
+ // The type of the object. The value MUST be one of "string", "number", "integer", or "boolean". The "array" type is not supported.
+ string type = 2;
+ // `Format` The extending format for the previously mentioned type.
+ string format = 3;
+ // field 4 is reserved for 'items', but in OpenAPI-specific way.
+ reserved 4;
+ // field 5 is reserved `Collection Format` Determines the format of the array if type array is used.
+ reserved 5;
+ // `Default` Declares the value of the header that the server will use if none is provided.
+ // See: https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-6.2.
+ // Unlike JSON Schema this value MUST conform to the defined type for the header.
+ string default = 6;
+ // field 7 is reserved for 'maximum'.
+ reserved 7;
+ // field 8 is reserved for 'exclusiveMaximum'.
+ reserved 8;
+ // field 9 is reserved for 'minimum'.
+ reserved 9;
+ // field 10 is reserved for 'exclusiveMinimum'.
+ reserved 10;
+ // field 11 is reserved for 'maxLength'.
+ reserved 11;
+ // field 12 is reserved for 'minLength'.
+ reserved 12;
+ // 'Pattern' See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.2.3.
+ string pattern = 13;
+ // field 14 is reserved for 'maxItems'.
+ reserved 14;
+ // field 15 is reserved for 'minItems'.
+ reserved 15;
+ // field 16 is reserved for 'uniqueItems'.
+ reserved 16;
+ // field 17 is reserved for 'enum'.
+ reserved 17;
+ // field 18 is reserved for 'multipleOf'.
+ reserved 18;
+}
+
+// `Response` is a representation of OpenAPI v2 specification's Response object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#responseObject
+//
+message Response {
+ // `Description` is a short description of the response.
+ // GFM syntax can be used for rich text representation.
+ string description = 1;
+ // `Schema` optionally defines the structure of the response.
+ // If `Schema` is not provided, it means there is no content to the response.
+ Schema schema = 2;
+ // `Headers` A list of headers that are sent with the response.
+ // `Header` name is expected to be a string in the canonical format of the MIME header key
+ // See: https://golang.org/pkg/net/textproto/#CanonicalMIMEHeaderKey
+ map headers = 3;
+ // `Examples` gives per-mimetype response examples.
+ // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#example-object
+ map examples = 4;
+ map extensions = 5;
+}
+
+// `Info` is a representation of OpenAPI v2 specification's Info object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#infoObject
+//
+// Example:
+//
+// option (grpc.gateway.protoc_gen_swagger.options.openapiv2_swagger) = {
+// info: {
+// title: "Echo API";
+// version: "1.0";
+// description: ";
+// contact: {
+// name: "gRPC-Gateway project";
+// url: "https://github.com/grpc-ecosystem/grpc-gateway";
+// email: "none@example.com";
+// };
+// license: {
+// name: "BSD 3-Clause License";
+// url: "https://github.com/grpc-ecosystem/grpc-gateway/blob/master/LICENSE.txt";
+// };
+// };
+// ...
+// };
+//
+message Info {
+ // The title of the application.
+ string title = 1;
+ // A short description of the application. GFM syntax can be used for rich
+ // text representation.
+ string description = 2;
+ // The Terms of Service for the API.
+ string terms_of_service = 3;
+ // The contact information for the exposed API.
+ Contact contact = 4;
+ // The license information for the exposed API.
+ License license = 5;
+ // Provides the version of the application API (not to be confused
+ // with the specification version).
+ string version = 6;
+ map extensions = 7;
+}
+
+// `Contact` is a representation of OpenAPI v2 specification's Contact object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#contactObject
+//
+// Example:
+//
+// option (grpc.gateway.protoc_gen_swagger.options.openapiv2_swagger) = {
+// info: {
+// ...
+// contact: {
+// name: "gRPC-Gateway project";
+// url: "https://github.com/grpc-ecosystem/grpc-gateway";
+// email: "none@example.com";
+// };
+// ...
+// };
+// ...
+// };
+//
+message Contact {
+ // The identifying name of the contact person/organization.
+ string name = 1;
+ // The URL pointing to the contact information. MUST be in the format of a
+ // URL.
+ string url = 2;
+ // The email address of the contact person/organization. MUST be in the format
+ // of an email address.
+ string email = 3;
+}
+
+// `License` is a representation of OpenAPI v2 specification's License object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#licenseObject
+//
+// Example:
+//
+// option (grpc.gateway.protoc_gen_swagger.options.openapiv2_swagger) = {
+// info: {
+// ...
+// license: {
+// name: "BSD 3-Clause License";
+// url: "https://github.com/grpc-ecosystem/grpc-gateway/blob/master/LICENSE.txt";
+// };
+// ...
+// };
+// ...
+// };
+//
+message License {
+ // The license name used for the API.
+ string name = 1;
+ // A URL to the license used for the API. MUST be in the format of a URL.
+ string url = 2;
+}
+
+// `ExternalDocumentation` is a representation of OpenAPI v2 specification's
+// ExternalDocumentation object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#externalDocumentationObject
+//
+// Example:
+//
+// option (grpc.gateway.protoc_gen_swagger.options.openapiv2_swagger) = {
+// ...
+// external_docs: {
+// description: "More about gRPC-Gateway";
+// url: "https://github.com/grpc-ecosystem/grpc-gateway";
+// }
+// ...
+// };
+//
+message ExternalDocumentation {
+ // A short description of the target documentation. GFM syntax can be used for
+ // rich text representation.
+ string description = 1;
+ // The URL for the target documentation. Value MUST be in the format
+ // of a URL.
+ string url = 2;
+}
+
+// `Schema` is a representation of OpenAPI v2 specification's Schema object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#schemaObject
+//
+message Schema {
+ JSONSchema json_schema = 1;
+ // Adds support for polymorphism. The discriminator is the schema property
+ // name that is used to differentiate between other schema that inherit this
+ // schema. The property name used MUST be defined at this schema and it MUST
+ // be in the required property list. When used, the value MUST be the name of
+ // this schema or any schema that inherits it.
+ string discriminator = 2;
+ // Relevant only for Schema "properties" definitions. Declares the property as
+ // "read only". This means that it MAY be sent as part of a response but MUST
+ // NOT be sent as part of the request. Properties marked as readOnly being
+ // true SHOULD NOT be in the required list of the defined schema. Default
+ // value is false.
+ bool read_only = 3;
+ // field 4 is reserved for 'xml'.
+ reserved 4;
+ // Additional external documentation for this schema.
+ ExternalDocumentation external_docs = 5;
+ // A free-form property to include an example of an instance for this schema.
+ // Deprecated, please use example_string instead.
+ google.protobuf.Any example = 6 [
+ deprecated = true
+ ];
+ // A free-form property to include a JSON example of this field. This is copied
+ // verbatim to the output swagger.json. Quotes must be escaped.
+ string example_string = 7;
+}
+
+// `JSONSchema` represents properties from JSON Schema taken, and as used, in
+// the OpenAPI v2 spec.
+//
+// This includes changes made by OpenAPI v2.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#schemaObject
+//
+// See also: https://cswr.github.io/JsonSchema/spec/basic_types/,
+// https://github.com/json-schema-org/json-schema-spec/blob/master/schema.json
+//
+// Example:
+//
+// message SimpleMessage {
+// option (grpc.gateway.protoc_gen_swagger.options.openapiv2_schema) = {
+// json_schema: {
+// title: "SimpleMessage"
+// description: "A simple message."
+// required: ["id"]
+// }
+// };
+//
+// // Id represents the message identifier.
+// string id = 1; [
+// (grpc.gateway.protoc_gen_swagger.options.openapiv2_field) = {
+// {description: "The unique identifier of the simple message."
+// }];
+// }
+//
+message JSONSchema {
+ // field 1 is reserved for '$id', omitted from OpenAPI v2.
+ reserved 1;
+ // field 2 is reserved for '$schema', omitted from OpenAPI v2.
+ reserved 2;
+ // Ref is used to define an external reference to include in the message.
+ // This could be a fully qualified proto message reference, and that type must
+ // be imported into the protofile. If no message is identified, the Ref will
+ // be used verbatim in the output.
+ // For example:
+ // `ref: ".google.protobuf.Timestamp"`.
+ string ref = 3;
+ // field 4 is reserved for '$comment', omitted from OpenAPI v2.
+ reserved 4;
+ // The title of the schema.
+ string title = 5;
+ // A short description of the schema.
+ string description = 6;
+ string default = 7;
+ bool read_only = 8;
+ // A free-form property to include a JSON example of this field. This is copied
+ // verbatim to the output swagger.json. Quotes must be escaped.
+ // This property is the same for 2.0 and 3.0.0 https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/3.0.0.md#schemaObject https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#schemaObject
+ string example = 9;
+ double multiple_of = 10;
+ // Maximum represents an inclusive upper limit for a numeric instance. The
+ // value of MUST be a number,
+ double maximum = 11;
+ bool exclusive_maximum = 12;
+ // minimum represents an inclusive lower limit for a numeric instance. The
+ // value of MUST be a number,
+ double minimum = 13;
+ bool exclusive_minimum = 14;
+ uint64 max_length = 15;
+ uint64 min_length = 16;
+ string pattern = 17;
+ // field 18 is reserved for 'additionalItems', omitted from OpenAPI v2.
+ reserved 18;
+ // field 19 is reserved for 'items', but in OpenAPI-specific way.
+ // TODO(ivucica): add 'items'?
+ reserved 19;
+ uint64 max_items = 20;
+ uint64 min_items = 21;
+ bool unique_items = 22;
+ // field 23 is reserved for 'contains', omitted from OpenAPI v2.
+ reserved 23;
+ uint64 max_properties = 24;
+ uint64 min_properties = 25;
+ repeated string required = 26;
+ // field 27 is reserved for 'additionalProperties', but in OpenAPI-specific
+ // way. TODO(ivucica): add 'additionalProperties'?
+ reserved 27;
+ // field 28 is reserved for 'definitions', omitted from OpenAPI v2.
+ reserved 28;
+ // field 29 is reserved for 'properties', but in OpenAPI-specific way.
+ // TODO(ivucica): add 'additionalProperties'?
+ reserved 29;
+ // following fields are reserved, as the properties have been omitted from
+ // OpenAPI v2:
+ // patternProperties, dependencies, propertyNames, const
+ reserved 30 to 33;
+ // Items in 'array' must be unique.
+ repeated string array = 34;
+
+ enum JSONSchemaSimpleTypes {
+ UNKNOWN = 0;
+ ARRAY = 1;
+ BOOLEAN = 2;
+ INTEGER = 3;
+ NULL = 4;
+ NUMBER = 5;
+ OBJECT = 6;
+ STRING = 7;
+ }
+
+ repeated JSONSchemaSimpleTypes type = 35;
+ // `Format`
+ string format = 36;
+ // following fields are reserved, as the properties have been omitted from
+ // OpenAPI v2: contentMediaType, contentEncoding, if, then, else
+ reserved 37 to 41;
+ // field 42 is reserved for 'allOf', but in OpenAPI-specific way.
+ // TODO(ivucica): add 'allOf'?
+ reserved 42;
+ // following fields are reserved, as the properties have been omitted from
+ // OpenAPI v2:
+ // anyOf, oneOf, not
+ reserved 43 to 45;
+ // Items in `enum` must be unique https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.5.1
+ repeated string enum = 46;
+}
+
+// `Tag` is a representation of OpenAPI v2 specification's Tag object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#tagObject
+//
+message Tag {
+ // field 1 is reserved for 'name'. In our generator, this is (to be) extracted
+ // from the name of proto service, and thus not exposed to the user, as
+ // changing tag object's name would break the link to the references to the
+ // tag in individual operation specifications.
+ //
+ // TODO(ivucica): Add 'name' property. Use it to allow override of the name of
+ // global Tag object, then use that name to reference the tag throughout the
+ // Swagger file.
+ reserved 1;
+ // A short description for the tag. GFM syntax can be used for rich text
+ // representation.
+ string description = 2;
+ // Additional external documentation for this tag.
+ ExternalDocumentation external_docs = 3;
+}
+
+// `SecurityDefinitions` is a representation of OpenAPI v2 specification's
+// Security Definitions object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#securityDefinitionsObject
+//
+// A declaration of the security schemes available to be used in the
+// specification. This does not enforce the security schemes on the operations
+// and only serves to provide the relevant details for each scheme.
+message SecurityDefinitions {
+ // A single security scheme definition, mapping a "name" to the scheme it
+ // defines.
+ map security = 1;
+}
+
+// `SecurityScheme` is a representation of OpenAPI v2 specification's
+// Security Scheme object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#securitySchemeObject
+//
+// Allows the definition of a security scheme that can be used by the
+// operations. Supported schemes are basic authentication, an API key (either as
+// a header or as a query parameter) and OAuth2's common flows (implicit,
+// password, application and access code).
+message SecurityScheme {
+ // The type of the security scheme. Valid values are "basic",
+ // "apiKey" or "oauth2".
+ enum Type {
+ TYPE_INVALID = 0;
+ TYPE_BASIC = 1;
+ TYPE_API_KEY = 2;
+ TYPE_OAUTH2 = 3;
+ }
+
+ // The location of the API key. Valid values are "query" or "header".
+ enum In {
+ IN_INVALID = 0;
+ IN_QUERY = 1;
+ IN_HEADER = 2;
+ }
+
+ // The flow used by the OAuth2 security scheme. Valid values are
+ // "implicit", "password", "application" or "accessCode".
+ enum Flow {
+ FLOW_INVALID = 0;
+ FLOW_IMPLICIT = 1;
+ FLOW_PASSWORD = 2;
+ FLOW_APPLICATION = 3;
+ FLOW_ACCESS_CODE = 4;
+ }
+
+ // The type of the security scheme. Valid values are "basic",
+ // "apiKey" or "oauth2".
+ Type type = 1;
+ // A short description for security scheme.
+ string description = 2;
+ // The name of the header or query parameter to be used.
+ // Valid for apiKey.
+ string name = 3;
+ // The location of the API key. Valid values are "query" or
+ // "header".
+ // Valid for apiKey.
+ In in = 4;
+ // The flow used by the OAuth2 security scheme. Valid values are
+ // "implicit", "password", "application" or "accessCode".
+ // Valid for oauth2.
+ Flow flow = 5;
+ // The authorization URL to be used for this flow. This SHOULD be in
+ // the form of a URL.
+ // Valid for oauth2/implicit and oauth2/accessCode.
+ string authorization_url = 6;
+ // The token URL to be used for this flow. This SHOULD be in the
+ // form of a URL.
+ // Valid for oauth2/password, oauth2/application and oauth2/accessCode.
+ string token_url = 7;
+ // The available scopes for the OAuth2 security scheme.
+ // Valid for oauth2.
+ Scopes scopes = 8;
+ map extensions = 9;
+}
+
+// `SecurityRequirement` is a representation of OpenAPI v2 specification's
+// Security Requirement object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#securityRequirementObject
+//
+// Lists the required security schemes to execute this operation. The object can
+// have multiple security schemes declared in it which are all required (that
+// is, there is a logical AND between the schemes).
+//
+// The name used for each property MUST correspond to a security scheme
+// declared in the Security Definitions.
+message SecurityRequirement {
+ // If the security scheme is of type "oauth2", then the value is a list of
+ // scope names required for the execution. For other security scheme types,
+ // the array MUST be empty.
+ message SecurityRequirementValue {
+ repeated string scope = 1;
+ }
+ // Each name must correspond to a security scheme which is declared in
+ // the Security Definitions. If the security scheme is of type "oauth2",
+ // then the value is a list of scope names required for the execution.
+ // For other security scheme types, the array MUST be empty.
+ map security_requirement = 1;
+}
+
+// `Scopes` is a representation of OpenAPI v2 specification's Scopes object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#scopesObject
+//
+// Lists the available scopes for an OAuth2 security scheme.
+message Scopes {
+ // Maps between a name of a scope to a short description of it (as the value
+ // of the property).
+ map scope = 1;
+}
diff --git a/src/Zitadel.Api/validate/validate.proto b/src/Zitadel.Api/validate/validate.proto
new file mode 100644
index 00000000..4195ecf9
--- /dev/null
+++ b/src/Zitadel.Api/validate/validate.proto
@@ -0,0 +1,863 @@
+syntax = "proto2";
+package validate;
+
+option go_package = "github.com/envoyproxy/protoc-gen-validate/validate";
+option java_package = "io.envoyproxy.pgv.validate";
+
+import "google/protobuf/descriptor.proto";
+import "google/protobuf/duration.proto";
+import "google/protobuf/timestamp.proto";
+
+// Validation rules applied at the message level
+extend google.protobuf.MessageOptions {
+ // Disabled nullifies any validation rules for this message, including any
+ // message fields associated with it that do support validation.
+ optional bool disabled = 1071;
+ // Ignore skips generation of validation methods for this message.
+ optional bool ignored = 1072;
+}
+
+// Validation rules applied at the oneof level
+extend google.protobuf.OneofOptions {
+ // Required ensures that exactly one the field options in a oneof is set;
+ // validation fails if no fields in the oneof are set.
+ optional bool required = 1071;
+}
+
+// Validation rules applied at the field level
+extend google.protobuf.FieldOptions {
+ // Rules specify the validations to be performed on this field. By default,
+ // no validation is performed against a field.
+ optional FieldRules rules = 1071;
+}
+
+// FieldRules encapsulates the rules for each type of field. Depending on the
+// field, the correct set should be used to ensure proper validations.
+message FieldRules {
+ optional MessageRules message = 17;
+ oneof type {
+ // Scalar Field Types
+ FloatRules float = 1;
+ DoubleRules double = 2;
+ Int32Rules int32 = 3;
+ Int64Rules int64 = 4;
+ UInt32Rules uint32 = 5;
+ UInt64Rules uint64 = 6;
+ SInt32Rules sint32 = 7;
+ SInt64Rules sint64 = 8;
+ Fixed32Rules fixed32 = 9;
+ Fixed64Rules fixed64 = 10;
+ SFixed32Rules sfixed32 = 11;
+ SFixed64Rules sfixed64 = 12;
+ BoolRules bool = 13;
+ StringRules string = 14;
+ BytesRules bytes = 15;
+
+ // Complex Field Types
+ EnumRules enum = 16;
+ RepeatedRules repeated = 18;
+ MapRules map = 19;
+
+ // Well-Known Field Types
+ AnyRules any = 20;
+ DurationRules duration = 21;
+ TimestampRules timestamp = 22;
+ }
+}
+
+// FloatRules describes the constraints applied to `float` values
+message FloatRules {
+ // Const specifies that this field must be exactly the specified value
+ optional float const = 1;
+
+ // Lt specifies that this field must be less than the specified value,
+ // exclusive
+ optional float lt = 2;
+
+ // Lte specifies that this field must be less than or equal to the
+ // specified value, inclusive
+ optional float lte = 3;
+
+ // Gt specifies that this field must be greater than the specified value,
+ // exclusive. If the value of Gt is larger than a specified Lt or Lte, the
+ // range is reversed.
+ optional float gt = 4;
+
+ // Gte specifies that this field must be greater than or equal to the
+ // specified value, inclusive. If the value of Gte is larger than a
+ // specified Lt or Lte, the range is reversed.
+ optional float gte = 5;
+
+ // In specifies that this field must be equal to one of the specified
+ // values
+ repeated float in = 6;
+
+ // NotIn specifies that this field cannot be equal to one of the specified
+ // values
+ repeated float not_in = 7;
+
+ // IgnoreEmpty specifies that the validation rules of this field should be
+ // evaluated only if the field is not empty
+ optional bool ignore_empty = 8;
+}
+
+// DoubleRules describes the constraints applied to `double` values
+message DoubleRules {
+ // Const specifies that this field must be exactly the specified value
+ optional double const = 1;
+
+ // Lt specifies that this field must be less than the specified value,
+ // exclusive
+ optional double lt = 2;
+
+ // Lte specifies that this field must be less than or equal to the
+ // specified value, inclusive
+ optional double lte = 3;
+
+ // Gt specifies that this field must be greater than the specified value,
+ // exclusive. If the value of Gt is larger than a specified Lt or Lte, the
+ // range is reversed.
+ optional double gt = 4;
+
+ // Gte specifies that this field must be greater than or equal to the
+ // specified value, inclusive. If the value of Gte is larger than a
+ // specified Lt or Lte, the range is reversed.
+ optional double gte = 5;
+
+ // In specifies that this field must be equal to one of the specified
+ // values
+ repeated double in = 6;
+
+ // NotIn specifies that this field cannot be equal to one of the specified
+ // values
+ repeated double not_in = 7;
+
+ // IgnoreEmpty specifies that the validation rules of this field should be
+ // evaluated only if the field is not empty
+ optional bool ignore_empty = 8;
+}
+
+// Int32Rules describes the constraints applied to `int32` values
+message Int32Rules {
+ // Const specifies that this field must be exactly the specified value
+ optional int32 const = 1;
+
+ // Lt specifies that this field must be less than the specified value,
+ // exclusive
+ optional int32 lt = 2;
+
+ // Lte specifies that this field must be less than or equal to the
+ // specified value, inclusive
+ optional int32 lte = 3;
+
+ // Gt specifies that this field must be greater than the specified value,
+ // exclusive. If the value of Gt is larger than a specified Lt or Lte, the
+ // range is reversed.
+ optional int32 gt = 4;
+
+ // Gte specifies that this field must be greater than or equal to the
+ // specified value, inclusive. If the value of Gte is larger than a
+ // specified Lt or Lte, the range is reversed.
+ optional int32 gte = 5;
+
+ // In specifies that this field must be equal to one of the specified
+ // values
+ repeated int32 in = 6;
+
+ // NotIn specifies that this field cannot be equal to one of the specified
+ // values
+ repeated int32 not_in = 7;
+
+ // IgnoreEmpty specifies that the validation rules of this field should be
+ // evaluated only if the field is not empty
+ optional bool ignore_empty = 8;
+}
+
+// Int64Rules describes the constraints applied to `int64` values
+message Int64Rules {
+ // Const specifies that this field must be exactly the specified value
+ optional int64 const = 1;
+
+ // Lt specifies that this field must be less than the specified value,
+ // exclusive
+ optional int64 lt = 2;
+
+ // Lte specifies that this field must be less than or equal to the
+ // specified value, inclusive
+ optional int64 lte = 3;
+
+ // Gt specifies that this field must be greater than the specified value,
+ // exclusive. If the value of Gt is larger than a specified Lt or Lte, the
+ // range is reversed.
+ optional int64 gt = 4;
+
+ // Gte specifies that this field must be greater than or equal to the
+ // specified value, inclusive. If the value of Gte is larger than a
+ // specified Lt or Lte, the range is reversed.
+ optional int64 gte = 5;
+
+ // In specifies that this field must be equal to one of the specified
+ // values
+ repeated int64 in = 6;
+
+ // NotIn specifies that this field cannot be equal to one of the specified
+ // values
+ repeated int64 not_in = 7;
+
+ // IgnoreEmpty specifies that the validation rules of this field should be
+ // evaluated only if the field is not empty
+ optional bool ignore_empty = 8;
+}
+
+// UInt32Rules describes the constraints applied to `uint32` values
+message UInt32Rules {
+ // Const specifies that this field must be exactly the specified value
+ optional uint32 const = 1;
+
+ // Lt specifies that this field must be less than the specified value,
+ // exclusive
+ optional uint32 lt = 2;
+
+ // Lte specifies that this field must be less than or equal to the
+ // specified value, inclusive
+ optional uint32 lte = 3;
+
+ // Gt specifies that this field must be greater than the specified value,
+ // exclusive. If the value of Gt is larger than a specified Lt or Lte, the
+ // range is reversed.
+ optional uint32 gt = 4;
+
+ // Gte specifies that this field must be greater than or equal to the
+ // specified value, inclusive. If the value of Gte is larger than a
+ // specified Lt or Lte, the range is reversed.
+ optional uint32 gte = 5;
+
+ // In specifies that this field must be equal to one of the specified
+ // values
+ repeated uint32 in = 6;
+
+ // NotIn specifies that this field cannot be equal to one of the specified
+ // values
+ repeated uint32 not_in = 7;
+
+ // IgnoreEmpty specifies that the validation rules of this field should be
+ // evaluated only if the field is not empty
+ optional bool ignore_empty = 8;
+}
+
+// UInt64Rules describes the constraints applied to `uint64` values
+message UInt64Rules {
+ // Const specifies that this field must be exactly the specified value
+ optional uint64 const = 1;
+
+ // Lt specifies that this field must be less than the specified value,
+ // exclusive
+ optional uint64 lt = 2;
+
+ // Lte specifies that this field must be less than or equal to the
+ // specified value, inclusive
+ optional uint64 lte = 3;
+
+ // Gt specifies that this field must be greater than the specified value,
+ // exclusive. If the value of Gt is larger than a specified Lt or Lte, the
+ // range is reversed.
+ optional uint64 gt = 4;
+
+ // Gte specifies that this field must be greater than or equal to the
+ // specified value, inclusive. If the value of Gte is larger than a
+ // specified Lt or Lte, the range is reversed.
+ optional uint64 gte = 5;
+
+ // In specifies that this field must be equal to one of the specified
+ // values
+ repeated uint64 in = 6;
+
+ // NotIn specifies that this field cannot be equal to one of the specified
+ // values
+ repeated uint64 not_in = 7;
+
+ // IgnoreEmpty specifies that the validation rules of this field should be
+ // evaluated only if the field is not empty
+ optional bool ignore_empty = 8;
+}
+
+// SInt32Rules describes the constraints applied to `sint32` values
+message SInt32Rules {
+ // Const specifies that this field must be exactly the specified value
+ optional sint32 const = 1;
+
+ // Lt specifies that this field must be less than the specified value,
+ // exclusive
+ optional sint32 lt = 2;
+
+ // Lte specifies that this field must be less than or equal to the
+ // specified value, inclusive
+ optional sint32 lte = 3;
+
+ // Gt specifies that this field must be greater than the specified value,
+ // exclusive. If the value of Gt is larger than a specified Lt or Lte, the
+ // range is reversed.
+ optional sint32 gt = 4;
+
+ // Gte specifies that this field must be greater than or equal to the
+ // specified value, inclusive. If the value of Gte is larger than a
+ // specified Lt or Lte, the range is reversed.
+ optional sint32 gte = 5;
+
+ // In specifies that this field must be equal to one of the specified
+ // values
+ repeated sint32 in = 6;
+
+ // NotIn specifies that this field cannot be equal to one of the specified
+ // values
+ repeated sint32 not_in = 7;
+
+ // IgnoreEmpty specifies that the validation rules of this field should be
+ // evaluated only if the field is not empty
+ optional bool ignore_empty = 8;
+}
+
+// SInt64Rules describes the constraints applied to `sint64` values
+message SInt64Rules {
+ // Const specifies that this field must be exactly the specified value
+ optional sint64 const = 1;
+
+ // Lt specifies that this field must be less than the specified value,
+ // exclusive
+ optional sint64 lt = 2;
+
+ // Lte specifies that this field must be less than or equal to the
+ // specified value, inclusive
+ optional sint64 lte = 3;
+
+ // Gt specifies that this field must be greater than the specified value,
+ // exclusive. If the value of Gt is larger than a specified Lt or Lte, the
+ // range is reversed.
+ optional sint64 gt = 4;
+
+ // Gte specifies that this field must be greater than or equal to the
+ // specified value, inclusive. If the value of Gte is larger than a
+ // specified Lt or Lte, the range is reversed.
+ optional sint64 gte = 5;
+
+ // In specifies that this field must be equal to one of the specified
+ // values
+ repeated sint64 in = 6;
+
+ // NotIn specifies that this field cannot be equal to one of the specified
+ // values
+ repeated sint64 not_in = 7;
+
+ // IgnoreEmpty specifies that the validation rules of this field should be
+ // evaluated only if the field is not empty
+ optional bool ignore_empty = 8;
+}
+
+// Fixed32Rules describes the constraints applied to `fixed32` values
+message Fixed32Rules {
+ // Const specifies that this field must be exactly the specified value
+ optional fixed32 const = 1;
+
+ // Lt specifies that this field must be less than the specified value,
+ // exclusive
+ optional fixed32 lt = 2;
+
+ // Lte specifies that this field must be less than or equal to the
+ // specified value, inclusive
+ optional fixed32 lte = 3;
+
+ // Gt specifies that this field must be greater than the specified value,
+ // exclusive. If the value of Gt is larger than a specified Lt or Lte, the
+ // range is reversed.
+ optional fixed32 gt = 4;
+
+ // Gte specifies that this field must be greater than or equal to the
+ // specified value, inclusive. If the value of Gte is larger than a
+ // specified Lt or Lte, the range is reversed.
+ optional fixed32 gte = 5;
+
+ // In specifies that this field must be equal to one of the specified
+ // values
+ repeated fixed32 in = 6;
+
+ // NotIn specifies that this field cannot be equal to one of the specified
+ // values
+ repeated fixed32 not_in = 7;
+
+ // IgnoreEmpty specifies that the validation rules of this field should be
+ // evaluated only if the field is not empty
+ optional bool ignore_empty = 8;
+}
+
+// Fixed64Rules describes the constraints applied to `fixed64` values
+message Fixed64Rules {
+ // Const specifies that this field must be exactly the specified value
+ optional fixed64 const = 1;
+
+ // Lt specifies that this field must be less than the specified value,
+ // exclusive
+ optional fixed64 lt = 2;
+
+ // Lte specifies that this field must be less than or equal to the
+ // specified value, inclusive
+ optional fixed64 lte = 3;
+
+ // Gt specifies that this field must be greater than the specified value,
+ // exclusive. If the value of Gt is larger than a specified Lt or Lte, the
+ // range is reversed.
+ optional fixed64 gt = 4;
+
+ // Gte specifies that this field must be greater than or equal to the
+ // specified value, inclusive. If the value of Gte is larger than a
+ // specified Lt or Lte, the range is reversed.
+ optional fixed64 gte = 5;
+
+ // In specifies that this field must be equal to one of the specified
+ // values
+ repeated fixed64 in = 6;
+
+ // NotIn specifies that this field cannot be equal to one of the specified
+ // values
+ repeated fixed64 not_in = 7;
+
+ // IgnoreEmpty specifies that the validation rules of this field should be
+ // evaluated only if the field is not empty
+ optional bool ignore_empty = 8;
+}
+
+// SFixed32Rules describes the constraints applied to `sfixed32` values
+message SFixed32Rules {
+ // Const specifies that this field must be exactly the specified value
+ optional sfixed32 const = 1;
+
+ // Lt specifies that this field must be less than the specified value,
+ // exclusive
+ optional sfixed32 lt = 2;
+
+ // Lte specifies that this field must be less than or equal to the
+ // specified value, inclusive
+ optional sfixed32 lte = 3;
+
+ // Gt specifies that this field must be greater than the specified value,
+ // exclusive. If the value of Gt is larger than a specified Lt or Lte, the
+ // range is reversed.
+ optional sfixed32 gt = 4;
+
+ // Gte specifies that this field must be greater than or equal to the
+ // specified value, inclusive. If the value of Gte is larger than a
+ // specified Lt or Lte, the range is reversed.
+ optional sfixed32 gte = 5;
+
+ // In specifies that this field must be equal to one of the specified
+ // values
+ repeated sfixed32 in = 6;
+
+ // NotIn specifies that this field cannot be equal to one of the specified
+ // values
+ repeated sfixed32 not_in = 7;
+
+ // IgnoreEmpty specifies that the validation rules of this field should be
+ // evaluated only if the field is not empty
+ optional bool ignore_empty = 8;
+}
+
+// SFixed64Rules describes the constraints applied to `sfixed64` values
+message SFixed64Rules {
+ // Const specifies that this field must be exactly the specified value
+ optional sfixed64 const = 1;
+
+ // Lt specifies that this field must be less than the specified value,
+ // exclusive
+ optional sfixed64 lt = 2;
+
+ // Lte specifies that this field must be less than or equal to the
+ // specified value, inclusive
+ optional sfixed64 lte = 3;
+
+ // Gt specifies that this field must be greater than the specified value,
+ // exclusive. If the value of Gt is larger than a specified Lt or Lte, the
+ // range is reversed.
+ optional sfixed64 gt = 4;
+
+ // Gte specifies that this field must be greater than or equal to the
+ // specified value, inclusive. If the value of Gte is larger than a
+ // specified Lt or Lte, the range is reversed.
+ optional sfixed64 gte = 5;
+
+ // In specifies that this field must be equal to one of the specified
+ // values
+ repeated sfixed64 in = 6;
+
+ // NotIn specifies that this field cannot be equal to one of the specified
+ // values
+ repeated sfixed64 not_in = 7;
+
+ // IgnoreEmpty specifies that the validation rules of this field should be
+ // evaluated only if the field is not empty
+ optional bool ignore_empty = 8;
+}
+
+// BoolRules describes the constraints applied to `bool` values
+message BoolRules {
+ // Const specifies that this field must be exactly the specified value
+ optional bool const = 1;
+}
+
+// StringRules describe the constraints applied to `string` values
+message StringRules {
+ // Const specifies that this field must be exactly the specified value
+ optional string const = 1;
+
+ // Len specifies that this field must be the specified number of
+ // characters (Unicode code points). Note that the number of
+ // characters may differ from the number of bytes in the string.
+ optional uint64 len = 19;
+
+ // MinLen specifies that this field must be the specified number of
+ // characters (Unicode code points) at a minimum. Note that the number of
+ // characters may differ from the number of bytes in the string.
+ optional uint64 min_len = 2;
+
+ // MaxLen specifies that this field must be the specified number of
+ // characters (Unicode code points) at a maximum. Note that the number of
+ // characters may differ from the number of bytes in the string.
+ optional uint64 max_len = 3;
+
+ // LenBytes specifies that this field must be the specified number of bytes
+ // at a minimum
+ optional uint64 len_bytes = 20;
+
+ // MinBytes specifies that this field must be the specified number of bytes
+ // at a minimum
+ optional uint64 min_bytes = 4;
+
+ // MaxBytes specifies that this field must be the specified number of bytes
+ // at a maximum
+ optional uint64 max_bytes = 5;
+
+ // Pattern specifes that this field must match against the specified
+ // regular expression (RE2 syntax). The included expression should elide
+ // any delimiters.
+ optional string pattern = 6;
+
+ // Prefix specifies that this field must have the specified substring at
+ // the beginning of the string.
+ optional string prefix = 7;
+
+ // Suffix specifies that this field must have the specified substring at
+ // the end of the string.
+ optional string suffix = 8;
+
+ // Contains specifies that this field must have the specified substring
+ // anywhere in the string.
+ optional string contains = 9;
+
+ // NotContains specifies that this field cannot have the specified substring
+ // anywhere in the string.
+ optional string not_contains = 23;
+
+ // In specifies that this field must be equal to one of the specified
+ // values
+ repeated string in = 10;
+
+ // NotIn specifies that this field cannot be equal to one of the specified
+ // values
+ repeated string not_in = 11;
+
+ // WellKnown rules provide advanced constraints against common string
+ // patterns
+ oneof well_known {
+ // Email specifies that the field must be a valid email address as
+ // defined by RFC 5322
+ bool email = 12;
+
+ // Hostname specifies that the field must be a valid hostname as
+ // defined by RFC 1034. This constraint does not support
+ // internationalized domain names (IDNs).
+ bool hostname = 13;
+
+ // Ip specifies that the field must be a valid IP (v4 or v6) address.
+ // Valid IPv6 addresses should not include surrounding square brackets.
+ bool ip = 14;
+
+ // Ipv4 specifies that the field must be a valid IPv4 address.
+ bool ipv4 = 15;
+
+ // Ipv6 specifies that the field must be a valid IPv6 address. Valid
+ // IPv6 addresses should not include surrounding square brackets.
+ bool ipv6 = 16;
+
+ // Uri specifies that the field must be a valid, absolute URI as defined
+ // by RFC 3986
+ bool uri = 17;
+
+ // UriRef specifies that the field must be a valid URI as defined by RFC
+ // 3986 and may be relative or absolute.
+ bool uri_ref = 18;
+
+ // Address specifies that the field must be either a valid hostname as
+ // defined by RFC 1034 (which does not support internationalized domain
+ // names or IDNs), or it can be a valid IP (v4 or v6).
+ bool address = 21;
+
+ // Uuid specifies that the field must be a valid UUID as defined by
+ // RFC 4122
+ bool uuid = 22;
+
+ // WellKnownRegex specifies a common well known pattern defined as a regex.
+ KnownRegex well_known_regex = 24;
+ }
+
+ // This applies to regexes HTTP_HEADER_NAME and HTTP_HEADER_VALUE to enable
+ // strict header validation.
+ // By default, this is true, and HTTP header validations are RFC-compliant.
+ // Setting to false will enable a looser validations that only disallows
+ // \r\n\0 characters, which can be used to bypass header matching rules.
+ optional bool strict = 25 [default = true];
+
+ // IgnoreEmpty specifies that the validation rules of this field should be
+ // evaluated only if the field is not empty
+ optional bool ignore_empty = 26;
+}
+
+// WellKnownRegex contain some well-known patterns.
+enum KnownRegex {
+ UNKNOWN = 0;
+
+ // HTTP header name as defined by RFC 7230.
+ HTTP_HEADER_NAME = 1;
+
+ // HTTP header value as defined by RFC 7230.
+ HTTP_HEADER_VALUE = 2;
+}
+
+// BytesRules describe the constraints applied to `bytes` values
+message BytesRules {
+ // Const specifies that this field must be exactly the specified value
+ optional bytes const = 1;
+
+ // Len specifies that this field must be the specified number of bytes
+ optional uint64 len = 13;
+
+ // MinLen specifies that this field must be the specified number of bytes
+ // at a minimum
+ optional uint64 min_len = 2;
+
+ // MaxLen specifies that this field must be the specified number of bytes
+ // at a maximum
+ optional uint64 max_len = 3;
+
+ // Pattern specifes that this field must match against the specified
+ // regular expression (RE2 syntax). The included expression should elide
+ // any delimiters.
+ optional string pattern = 4;
+
+ // Prefix specifies that this field must have the specified bytes at the
+ // beginning of the string.
+ optional bytes prefix = 5;
+
+ // Suffix specifies that this field must have the specified bytes at the
+ // end of the string.
+ optional bytes suffix = 6;
+
+ // Contains specifies that this field must have the specified bytes
+ // anywhere in the string.
+ optional bytes contains = 7;
+
+ // In specifies that this field must be equal to one of the specified
+ // values
+ repeated bytes in = 8;
+
+ // NotIn specifies that this field cannot be equal to one of the specified
+ // values
+ repeated bytes not_in = 9;
+
+ // WellKnown rules provide advanced constraints against common byte
+ // patterns
+ oneof well_known {
+ // Ip specifies that the field must be a valid IP (v4 or v6) address in
+ // byte format
+ bool ip = 10;
+
+ // Ipv4 specifies that the field must be a valid IPv4 address in byte
+ // format
+ bool ipv4 = 11;
+
+ // Ipv6 specifies that the field must be a valid IPv6 address in byte
+ // format
+ bool ipv6 = 12;
+ }
+
+ // IgnoreEmpty specifies that the validation rules of this field should be
+ // evaluated only if the field is not empty
+ optional bool ignore_empty = 14;
+}
+
+// EnumRules describe the constraints applied to enum values
+message EnumRules {
+ // Const specifies that this field must be exactly the specified value
+ optional int32 const = 1;
+
+ // DefinedOnly specifies that this field must be only one of the defined
+ // values for this enum, failing on any undefined value.
+ optional bool defined_only = 2;
+
+ // In specifies that this field must be equal to one of the specified
+ // values
+ repeated int32 in = 3;
+
+ // NotIn specifies that this field cannot be equal to one of the specified
+ // values
+ repeated int32 not_in = 4;
+}
+
+// MessageRules describe the constraints applied to embedded message values.
+// For message-type fields, validation is performed recursively.
+message MessageRules {
+ // Skip specifies that the validation rules of this field should not be
+ // evaluated
+ optional bool skip = 1;
+
+ // Required specifies that this field must be set
+ optional bool required = 2;
+}
+
+// RepeatedRules describe the constraints applied to `repeated` values
+message RepeatedRules {
+ // MinItems specifies that this field must have the specified number of
+ // items at a minimum
+ optional uint64 min_items = 1;
+
+ // MaxItems specifies that this field must have the specified number of
+ // items at a maximum
+ optional uint64 max_items = 2;
+
+ // Unique specifies that all elements in this field must be unique. This
+ // contraint is only applicable to scalar and enum types (messages are not
+ // supported).
+ optional bool unique = 3;
+
+ // Items specifies the contraints to be applied to each item in the field.
+ // Repeated message fields will still execute validation against each item
+ // unless skip is specified here.
+ optional FieldRules items = 4;
+
+ // IgnoreEmpty specifies that the validation rules of this field should be
+ // evaluated only if the field is not empty
+ optional bool ignore_empty = 5;
+}
+
+// MapRules describe the constraints applied to `map` values
+message MapRules {
+ // MinPairs specifies that this field must have the specified number of
+ // KVs at a minimum
+ optional uint64 min_pairs = 1;
+
+ // MaxPairs specifies that this field must have the specified number of
+ // KVs at a maximum
+ optional uint64 max_pairs = 2;
+
+ // NoSparse specifies values in this field cannot be unset. This only
+ // applies to map's with message value types.
+ optional bool no_sparse = 3;
+
+ // Keys specifies the constraints to be applied to each key in the field.
+ optional FieldRules keys = 4;
+
+ // Values specifies the constraints to be applied to the value of each key
+ // in the field. Message values will still have their validations evaluated
+ // unless skip is specified here.
+ optional FieldRules values = 5;
+
+ // IgnoreEmpty specifies that the validation rules of this field should be
+ // evaluated only if the field is not empty
+ optional bool ignore_empty = 6;
+}
+
+// AnyRules describe constraints applied exclusively to the
+// `google.protobuf.Any` well-known type
+message AnyRules {
+ // Required specifies that this field must be set
+ optional bool required = 1;
+
+ // In specifies that this field's `type_url` must be equal to one of the
+ // specified values.
+ repeated string in = 2;
+
+ // NotIn specifies that this field's `type_url` must not be equal to any of
+ // the specified values.
+ repeated string not_in = 3;
+}
+
+// DurationRules describe the constraints applied exclusively to the
+// `google.protobuf.Duration` well-known type
+message DurationRules {
+ // Required specifies that this field must be set
+ optional bool required = 1;
+
+ // Const specifies that this field must be exactly the specified value
+ optional google.protobuf.Duration const = 2;
+
+ // Lt specifies that this field must be less than the specified value,
+ // exclusive
+ optional google.protobuf.Duration lt = 3;
+
+ // Lt specifies that this field must be less than the specified value,
+ // inclusive
+ optional google.protobuf.Duration lte = 4;
+
+ // Gt specifies that this field must be greater than the specified value,
+ // exclusive
+ optional google.protobuf.Duration gt = 5;
+
+ // Gte specifies that this field must be greater than the specified value,
+ // inclusive
+ optional google.protobuf.Duration gte = 6;
+
+ // In specifies that this field must be equal to one of the specified
+ // values
+ repeated google.protobuf.Duration in = 7;
+
+ // NotIn specifies that this field cannot be equal to one of the specified
+ // values
+ repeated google.protobuf.Duration not_in = 8;
+}
+
+// TimestampRules describe the constraints applied exclusively to the
+// `google.protobuf.Timestamp` well-known type
+message TimestampRules {
+ // Required specifies that this field must be set
+ optional bool required = 1;
+
+ // Const specifies that this field must be exactly the specified value
+ optional google.protobuf.Timestamp const = 2;
+
+ // Lt specifies that this field must be less than the specified value,
+ // exclusive
+ optional google.protobuf.Timestamp lt = 3;
+
+ // Lte specifies that this field must be less than the specified value,
+ // inclusive
+ optional google.protobuf.Timestamp lte = 4;
+
+ // Gt specifies that this field must be greater than the specified value,
+ // exclusive
+ optional google.protobuf.Timestamp gt = 5;
+
+ // Gte specifies that this field must be greater than the specified value,
+ // inclusive
+ optional google.protobuf.Timestamp gte = 6;
+
+ // LtNow specifies that this must be less than the current time. LtNow
+ // can only be used with the Within rule.
+ optional bool lt_now = 7;
+
+ // GtNow specifies that this must be greater than the current time. GtNow
+ // can only be used with the Within rule.
+ optional bool gt_now = 8;
+
+ // Within specifies that this field must be within this duration of the
+ // current time. This constraint can be used alone or with the LtNow and
+ // GtNow rules.
+ optional google.protobuf.Duration within = 9;
+}
diff --git a/src/Zitadel/Authentication/Credentials/ServiceAccount.cs b/src/Zitadel/Authentication/Credentials/ServiceAccount.cs
new file mode 100644
index 00000000..c31a27ec
--- /dev/null
+++ b/src/Zitadel/Authentication/Credentials/ServiceAccount.cs
@@ -0,0 +1,277 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Net.Http;
+using System.Net.Http.Json;
+using System.Security.Cryptography;
+using System.Text;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+using System.Threading.Tasks;
+using Jose;
+using Microsoft.IdentityModel.Protocols;
+using Microsoft.IdentityModel.Protocols.OpenIdConnect;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.OpenSsl;
+using Org.BouncyCastle.Security;
+
+namespace Zitadel.Authentication.Credentials
+{
+ ///
+ ///
+ /// A Zitadel can be loaded from a json file
+ /// and helps with authentication on a Zitadel IAM.
+ ///
+ ///
+ /// The mechanism is defined here:
+ /// Zitadel Docs.
+ ///
+ ///
+ public record ServiceAccount
+ {
+ private static readonly HttpClient HttpClient = new();
+
+ ///
+ /// The key type.
+ ///
+ public const string Type = "serviceaccount";
+
+ ///
+ /// The user id associated with this service account.
+ ///
+ public string UserId { get; init; } = string.Empty;
+
+ ///
+ /// This is unique ID (on Zitadel) of the key.
+ ///
+ public string KeyId { get; init; } = string.Empty;
+
+ ///
+ /// The private key generated by Zitadel for this .
+ ///
+ public string Key { get; init; } = string.Empty;
+
+ ///
+ /// Load a from a file at a given (relative or absolute) path.
+ ///
+ /// The relative or absolute filepath to the json file.
+ /// The parsed .
+ /// When the file does not exist.
+ /// When the deserializer returns 'null'.
+ ///
+ /// Thrown when the JSON is invalid,
+ /// the type is not compatible with the JSON,
+ /// or when there is remaining data in the Stream.
+ ///
+ public static async Task LoadFromJsonFileAsync(string pathToJson)
+ {
+ var path = Path.GetFullPath(
+ Path.IsPathRooted(pathToJson)
+ ? pathToJson
+ : Path.Join(Directory.GetCurrentDirectory(), pathToJson));
+
+ if (!File.Exists(path))
+ {
+ throw new FileNotFoundException($"File not found: {path}.", path);
+ }
+
+ await using var stream = File.OpenRead(path);
+ return await LoadFromJsonStreamAsync(stream);
+ }
+
+ ///
+ public static ServiceAccount LoadFromJsonFile(string pathToJson) => LoadFromJsonFileAsync(pathToJson).Result;
+
+ ///
+ /// Load a from a given stream (FileStream, MemoryStream, ...).
+ ///
+ /// The stream to read the json from.
+ /// The parsed .
+ /// When the deserializer returns 'null'.
+ ///
+ /// Thrown when the JSON is invalid,
+ /// the type is not compatible with the JSON,
+ /// or when there is remaining data in the Stream.
+ ///
+ public static async Task LoadFromJsonStreamAsync(Stream stream) =>
+ await JsonSerializer.DeserializeAsync(
+ stream,
+ new() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }) ??
+ throw new InvalidDataException("The json file yielded a 'null' result for deserialization.");
+
+ ///
+ public static ServiceAccount LoadFromJsonStream(Stream stream) => LoadFromJsonStreamAsync(stream).Result;
+
+ ///
+ /// Load a from a string that contains json.
+ ///
+ /// Json string.
+ /// The parsed .
+ /// When the deserializer returns 'null'.
+ ///
+ /// Thrown when the JSON is invalid,
+ /// the type is not compatible with the JSON,
+ /// or when there is remaining data in the Stream.
+ ///
+ public static async Task LoadFromJsonStringAsync(string json)
+ {
+ await using var memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(json), 0, json.Length);
+ return await LoadFromJsonStreamAsync(memoryStream);
+ }
+
+ ///
+ public static ServiceAccount LoadFromJsonString(string json) => LoadFromJsonStringAsync(json).Result;
+
+ ///
+ /// Authenticate the given service account against the issuer in the options.
+ /// As example, this token can be used to communicate with API applications or
+ /// with the Zitadel API itself.
+ ///
+ /// that contain the parameters for the authentication.
+ /// An opaque access token which can be used to communciate with relying parties.
+ public async Task AuthenticateAsync(AuthOptions authOptions)
+ {
+ var manager = new ConfigurationManager(
+ DiscoveryEndpoint(authOptions.DiscoveryEndpoint ?? authOptions.Endpoint),
+ new OpenIdConnectConfigurationRetriever(),
+ new HttpDocumentRetriever(HttpClient));
+
+ var oidcConfig = await manager.GetConfigurationAsync();
+
+ var jwt = await GetSignedJwtAsync(authOptions.Endpoint);
+ var request = new HttpRequestMessage(HttpMethod.Post, oidcConfig.TokenEndpoint)
+ {
+ Content = new FormUrlEncodedContent(
+ new[]
+ {
+ new KeyValuePair("grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer"),
+ new KeyValuePair(
+ "assertion",
+ $"{jwt}"),
+ new KeyValuePair("scope", authOptions.CreateOidcScopes()),
+ }),
+ };
+
+ var response = await HttpClient.SendAsync(request);
+ var token = await response
+ .EnsureSuccessStatusCode()
+ .Content
+ .ReadFromJsonAsync();
+
+ return token?.AccessToken ?? throw new("Access token could not be parsed.");
+ }
+
+ ///
+ public string Authenticate(AuthOptions authOptions) => AuthenticateAsync(authOptions).Result;
+
+ private static string DiscoveryEndpoint(string discoveryEndpoint) =>
+ discoveryEndpoint.EndsWith(ZitadelDefaults.DiscoveryEndpointPath)
+ ? discoveryEndpoint
+ : discoveryEndpoint.TrimEnd('/') + ZitadelDefaults.DiscoveryEndpointPath;
+
+ private string GetSignedJwt(string issuer) => GetSignedJwtAsync(issuer).Result;
+
+ private async Task GetSignedJwtAsync(string issuer)
+ {
+ using var rsa = new RSACryptoServiceProvider();
+ rsa.ImportParameters(await GetRsaParametersAsync());
+
+ return JWT.Encode(
+ new Dictionary
+ {
+ { "iss", UserId },
+ { "sub", UserId },
+ { "iat", DateTimeOffset.Now.ToUnixTimeSeconds() },
+ { "exp", ((DateTimeOffset)DateTime.Now.AddMinutes(1)).ToUnixTimeSeconds() },
+ { "aud", issuer },
+ },
+ rsa,
+ JwsAlgorithm.RS256,
+ new Dictionary
+ {
+ { "kid", KeyId },
+ });
+ }
+
+ private async Task GetRsaParametersAsync()
+ {
+ var bytes = Encoding.UTF8.GetBytes(Key);
+ await using var ms = new MemoryStream(bytes);
+ using var sr = new StreamReader(ms);
+ var pemReader = new PemReader(sr);
+
+ if (!(pemReader.ReadObject() is AsymmetricCipherKeyPair keyPair))
+ {
+ throw new("RSA Keypair could not be read.");
+ }
+
+ return DotNetUtilities.ToRSAParameters(keyPair.Private as RsaPrivateCrtKeyParameters);
+ }
+
+ private record AccessTokenResponse
+ {
+ [JsonPropertyName("access_token")]
+ public string AccessToken { get; init; } = string.Empty;
+ }
+
+ ///
+ /// Options for the authentication with a .
+ ///
+ public record AuthOptions
+ {
+ ///
+ /// Endpoint which will be called on the "token endpoint" to get an access token.
+ /// Defaults to .
+ ///
+ public string Endpoint { get; init; } = ZitadelDefaults.Issuer;
+
+ ///
+ /// If set, overwrites the discovery endpoint for .
+ /// This may be used, if the discovery endpoint is not on the well-known url
+ /// of the endpoint. Beware that the well-known part ("/.well-known/openid-configuration")
+ /// is still attached to the url.
+ ///
+ public string? DiscoveryEndpoint { get; init; }
+
+ ///
+ /// If set, the scope for a primary domain ("urn:zitadel:iam:org:domain:primary:{PrimaryDomain}")
+ /// will be attached to the list of scopes for the access token of the service account.
+ ///
+ public string? PrimaryDomain { get; init; }
+
+ ///
+ /// Set a list of roles that must be attached to this service account to be
+ /// successfully authenticated. Translates to the role scope ("urn:zitadel:iam:org:project:role:{Role}").
+ ///
+ public IList RequiredRoles { get; init; } = new List();
+
+ ///
+ /// Set a list of audiences that are attached to the returned access token.
+ /// Translates to the additional audience scope ("urn:zitadel:iam:org:project:id:{ProjectId}:aud").
+ ///
+ public IList ProjectAudiences { get; init; } = new List();
+
+ ///
+ /// List of arbitrary additional scopes that are concatenated into the scope.
+ ///
+ public IList AdditionalScopes { get; init; } = new List();
+
+ internal string CreateOidcScopes() =>
+ string.Join(
+ ' ',
+ new[]
+ {
+ "openid",
+ PrimaryDomain != null
+ ? $"urn:zitadel:iam:org:domain:primary:{PrimaryDomain}"
+ : string.Empty,
+ }
+ .Union(AdditionalScopes)
+ .Union(ProjectAudiences.Select(p => $"urn:zitadel:iam:org:project:id:{p}:aud"))
+ .Union(RequiredRoles.Select(r => $"urn:zitadel:iam:org:project:role:{r}"))
+ .Where(s => !string.IsNullOrWhiteSpace(s)));
+ }
+ }
+}
diff --git a/src/Zitadel/Authentication/ZitadelDefaults.cs b/src/Zitadel/Authentication/ZitadelDefaults.cs
index 66606b7f..8b1e0fbb 100644
--- a/src/Zitadel/Authentication/ZitadelDefaults.cs
+++ b/src/Zitadel/Authentication/ZitadelDefaults.cs
@@ -1,4 +1,5 @@
-using Zitadel.Authorization;
+using Zitadel.Authentication.Credentials;
+using Zitadel.Authorization;
namespace Zitadel.Authentication
{
@@ -66,6 +67,23 @@ public static class ZitadelDefaults
///
public const string PrimaryDomainClaimName = "urn:zitadel:iam:org:domain:primary";
+ ///
+ /// This is the project id for the zitadel API of Zitadel.ch.
+ /// This is needed for accessing the official zitadel API via grpc / rest endpoint
+ /// when using a to authenticate.
+ ///
+ public const string ZitadelApiProjectId = "69234237810729019";
+
+ ///
+ /// The endpoint (url) of the official zitadel API.
+ ///
+ public const string ZitadelApiEndpoint = "https://api.zitadel.ch";
+
+ ///
+ /// Header which is used to provide context to grpc/rest api calls.
+ ///
+ public const string ZitadelOrgIdHeader = "x-zitadel-orgid";
+
///
/// Constructor for organisation specific role claims.
/// They are used to specify roles on a specific organization.
diff --git a/src/Zitadel/Zitadel.csproj b/src/Zitadel/Zitadel.csproj
index 38cff877..d74a390b 100644
--- a/src/Zitadel/Zitadel.csproj
+++ b/src/Zitadel/Zitadel.csproj
@@ -4,8 +4,8 @@
- net5.0
true
+ net5.0
@@ -28,7 +28,11 @@
-
+
+ true
+ \
+ false
+
diff --git a/tests/Zitadel.Api.Access.Dev/Program.cs b/tests/Zitadel.Api.Access.Dev/Program.cs
new file mode 100644
index 00000000..97ef52d1
--- /dev/null
+++ b/tests/Zitadel.Api.Access.Dev/Program.cs
@@ -0,0 +1,25 @@
+using System;
+using Zitadel.Api;
+using Zitadel.Authentication;
+using Zitadel.Authentication.Credentials;
+
+Console.WriteLine("Login with Zitadel Service Account");
+var sa = await ServiceAccount.LoadFromJsonFileAsync("./service-account.json");
+var api = Clients.ManagementService(
+ new()
+ {
+ Endpoint = ZitadelDefaults.ZitadelApiEndpoint,
+ Organization = "69234230193872955",
+ ServiceAccountAuthentication = (sa, new()
+ {
+ ProjectAudiences = { ZitadelDefaults.ZitadelApiProjectId },
+ }),
+ });
+Console.WriteLine("Fetch Roles from Zitadel API");
+var roles = await api.SearchProjectRolesAsync(
+ new() { ProjectId = "84856448403694484" });
+Console.WriteLine("Roles:");
+foreach (var r in roles.Result)
+{
+ Console.WriteLine($"{r.Key} : {r.DisplayName} : {r.Group}");
+}
diff --git a/tests/Zitadel.Api.Access.Dev/Zitadel.Api.Access.Dev.csproj b/tests/Zitadel.Api.Access.Dev/Zitadel.Api.Access.Dev.csproj
new file mode 100644
index 00000000..bd3d7a16
--- /dev/null
+++ b/tests/Zitadel.Api.Access.Dev/Zitadel.Api.Access.Dev.csproj
@@ -0,0 +1,19 @@
+
+
+
+ Exe
+ net5.0
+
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+
+
diff --git a/tests/Zitadel.Api.Access.Dev/service-account.json b/tests/Zitadel.Api.Access.Dev/service-account.json
new file mode 100644
index 00000000..b6e85660
--- /dev/null
+++ b/tests/Zitadel.Api.Access.Dev/service-account.json
@@ -0,0 +1,6 @@
+{
+ "type": "serviceaccount",
+ "keyId": "100820491081673449",
+ "key": "-----BEGIN RSA PRIVATE KEY-----\nMIIEpQIBAAKCAQEAtxkh+++/afNlrpVQxCtcfwDtWtc4MwF/SfW3TNuXgnNP52MG\ni3Gb4voLJHh+IjuLubDt2GSkFsvRmdqNU8rYF5ATtVnSwaA8I76FZwHpTYPRqM4j\nrUjCQTv8V+1xKlzDANn0pq+aJuUwP89TmOgk+S5yKHdc9Am27SxFxXlIjeyr/t//\nQE4BLp8BLjbWqb04s9kWUdZhnPyvrjekmO2F0P58xUKq7Of7wgbA7aSY610TSzMj\nyZpToByO3NSaLOIQEmgiXMGXIrH1SeGvZ2YWe2ONoEp1RJBel2MvcfzOWIHWtsfG\nS8FCnq/tS4kTQaNvcSgv1OHHIaST11rZ7ETzNwIDAQABAoIBAQCNAmYRyMn5puGg\nWo4hBePuS6CAXU+CuJx3MS1Bm7xLUtMuuCzKJ2yOmVMLe2BorMMm9wO1q4xTohSC\nELbW2VkijGshN1QAmo62WHwUoHw0nlhRULBZO7ee1bu5W7vTjC0B8tlfpc1qNwe5\nnMoc8GvJG+P/Fi4YI4MllPsG4ijmYxfJKQcw5EZofW53RGdYsxBeAn6AHeK1To9/\nMVidEEQFHpDP4S5sE+oE8PAmy4FXpTUkCHqK0hj9Iyn1MvqzYBA9AkPJHkDOgMIG\nu2yH4ld1+BqPOFaD2i9+n++DS7PuD0k5GAZnHVNvOef7p0zzcf7pU8HvQ81rY+en\nP5yj58BBAoGBAMPIajJkhJOqCVSTEK+OobNeq/htdGk0A0soj1X11Oj8OdQqcmti\nRsAib4AGsuZ232dCQktHrRgehvbOX11KawvNm6IHVV55v8BdXaFNPknUszduMUH/\nRZKzrIJbvHmJh+A1NLMS5gGJ27pLuOBEuQMuqjlgbz/wnFJgy1UyNjtrAoGBAO9p\n8rwhj8WBUawtK8JomOXw5WT4Pj+Q2tq78fSQd4RBN5+lJoX/PHMMFB+hYG5Pc5Wr\ntQB/6jXer/k8h0EnT1rLLVBaxMAfTRivVrbN6sZmlFX/CbYcLyWFF0yefg2Bf6ro\ny8N+JJq7vENIcxzRqoCSakQvWzaRuGznsWFoMQZlAoGBALQa7V7YS4IP/S9ZbxMh\nUi3RHMCX6GxTVehRMrLwSGHgjk5YkhOpP87Gnu4Wu4L5vgCe2p+oG1tB0gS/ysjm\nid080zxWJLmZpMWQ3m5hwbhnvEp0y0mcTONs+HifbZ4c3+to5scJzp+Bs6oIuNVP\nQyfjSOMpjI40iYna05LXcz5rAoGBAK1kJhBqnh2EkwoHjPG3n0SpOvntb+fJmTdh\ndtKQ7n4yXX6ZtVTGjZkk3k4qKhS6JhP3z5cVDSMGrJvtYmeleKthCuhvVJ9wC/4c\nvsiWSbp3AGdn1ji2IM8jnMQ45UISz8uP3kMvUINgA/EWv4fXsYx8fcn0IjNbRh5Z\njvXk59yhAoGAWvPOyX+g02Oi4958WpOyG3hU5XxPUxWB1FMTsusatARwXOwbbl92\n5bBgz7eb4wXhfUf7U3sItIH4Kf7xSrZwwq2cbTfBUE7k78kPhYOaJQD7LxxmdE98\n44Kc2VWK82jZIhgcswjRuuxpTMzWB89mC5UQtzykK5/m7+LLbOMdtHg=\n-----END RSA PRIVATE KEY-----\n",
+ "userId": "85328809577999392"
+}
diff --git a/tests/Zitadel.Test/Authentication/ZitadelAuthenticationHandler.Test.cs b/tests/Zitadel.Test/Authentication/ZitadelAuthenticationHandler.Test.cs
index 586ac770..f97e98d9 100644
--- a/tests/Zitadel.Test/Authentication/ZitadelAuthenticationHandler.Test.cs
+++ b/tests/Zitadel.Test/Authentication/ZitadelAuthenticationHandler.Test.cs
@@ -1,8 +1,10 @@
-using System.Net.Http.Json;
+using System.Net.Http.Headers;
+using System.Net.Http.Json;
using System.Threading.Tasks;
using FluentAssertions;
using Microsoft.AspNetCore.Http;
using Xunit;
+using Zitadel.Authentication.Credentials;
using Zitadel.Test.WebFactories;
namespace Zitadel.Test.Authentication
@@ -35,12 +37,19 @@ public async Task Should_Return_Unauthorized_Without_Any_Token()
result.StatusCode.Should().Be(StatusCodes.Status401Unauthorized);
}
- [Fact(Skip = "Until a solution for 'get an access token' is found.")]
- public async Task Should_Return_Data_With_Jwt_Token()
+ [Fact]
+ public async Task Should_Return_Data_With_Token()
{
+ var sa = await ServiceAccount.LoadFromJsonFileAsync("service-account.json");
+ var token = await sa.AuthenticateAsync(
+ new()
+ {
+ ProjectAudiences = { "84856448403694484" },
+ });
var client = _factory.CreateClient();
+ client.DefaultRequestHeaders.Authorization = new("Bearer", token);
var result = await client.GetAsync("/authed");
- result.StatusCode.Should().Be(StatusCodes.Status401Unauthorized);
+ result.StatusCode.Should().Be(StatusCodes.Status200OK);
}
}
}
diff --git a/tests/Zitadel.Test/WebFactories/AuthenticationHandlerWebFactory.cs b/tests/Zitadel.Test/WebFactories/AuthenticationHandlerWebFactory.cs
index a4c749aa..7e710c5a 100644
--- a/tests/Zitadel.Test/WebFactories/AuthenticationHandlerWebFactory.cs
+++ b/tests/Zitadel.Test/WebFactories/AuthenticationHandlerWebFactory.cs
@@ -9,6 +9,7 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Zitadel.Authentication;
+using Zitadel.Authentication.Credentials;
namespace Zitadel.Test.WebFactories
{
@@ -21,7 +22,13 @@ public void ConfigureServices(IServiceCollection services)
services
.AddAuthorization()
.AddAuthentication(ZitadelDefaults.ApiAuthenticationScheme)
- .AddZitadelApi(o => o.ClientId = "84891356119558811@zitadel_net");
+ .AddZitadelApi(
+ o =>
+ {
+ o.ClientId = "100962076121492209@zitadel_net";
+ o.JwtProfileKey = new JwtPrivateKeyPath("api-application.json");
+ o.ValidAudiences = new[] { "84856448403694484" };
+ });
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
diff --git a/tests/Zitadel.Test/Zitadel.Test.csproj b/tests/Zitadel.Test/Zitadel.Test.csproj
index 0c905b03..95471b08 100644
--- a/tests/Zitadel.Test/Zitadel.Test.csproj
+++ b/tests/Zitadel.Test/Zitadel.Test.csproj
@@ -25,4 +25,10 @@
+
+
+ PreserveNewest
+
+
+
diff --git a/tests/Zitadel.Test/api-application.json b/tests/Zitadel.Test/api-application.json
new file mode 100644
index 00000000..d6cf6e7a
--- /dev/null
+++ b/tests/Zitadel.Test/api-application.json
@@ -0,0 +1 @@
+{"type":"application","keyId":"100962085483110428","key":"-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEAuAz+zzcAnsaSyFdWxyR+fMWAHmFB03Csn/Ggvgvum1rH5emD\niA++hs7m/8HLI4xQDVXkCjenq8RezAIpcJAz9ntSHLeMSLH838k25d5fwNSxx4CN\nKBRrev2L930undntGZ2Z7mhCfqKprxPLzdGgIcZHPmduTQ8CQC/nYRWsdG6EcG8d\n4/Jx/OPLsZlIMtgVr3tpxgaoi1TduAWG1lhD30zqBhrt7EB0OynDq5h7me6ogY6M\nGxIJHUerIBRnADv3QhAVOEiKHwUi3wLR9oJmob7uW2KQrHkawnIpmnHPJTQGA4hH\nTIJJbEmBzAQYTrbE3OrVbrtTaCPx5UckTaSM/QIDAQABAoIBAE0ozY5rnavyzciF\nrRCxwQFn/y09Us5k10n6j4v9Dpw8s780ZXseNp7nkLo6MYKGqWzdzEtoR7fgDGn0\nohDZs58q1iLJ5Fr5m2zqO0SlNHlv8dQUlZju7pxSPWKVLXzpxtfNVaI4PWA/q2mF\noBR6RGrEaEvGKtzNZQEp1BPEdVcd4/QerxeGdRzJLXvzd3k84W7/k8RavKMDdIl1\nRoWrQDHlEicQmj/Nj9yPPm0MDNMlfTAbRnruppFRL5aKDtA9oCVjReHA+HqE+yU0\ngiavfy2GVnbtAqZtLrNoIQaSCIwfm5zR0gCHu4OjB2fkXOE9uwozScRRHGBgsK0n\nuP/BwEECgYEA0X4+vi/98Z61oYTFdYtmX2H91Guozu88qRDYPkaKjsZAHJBdzH2P\nSWOrXv/la0iwC8XoFbEv6WjiL1jblP8/mol/eYcQTBOCUYQjWDYt9LIV+5EquX0k\n6WBKGWgGye7eX2hjobdr+gGXzUKy4s+YQE07UE/w1Sli6l/jcClqgy0CgYEA4OjU\nBCWKVMmSZCg3N/naztZDUEXydxj1VZA/hKHwCNogRDrHkDbkFOXVHKcODQkm1Kko\n7k9fpTdgLGLFyq/RAQRz16QmBjzOUjSu+W/1uViD1i67Ry2KnZeTXp3IpGH3ntTJ\ncFkOe6mVJ+N3fziGD66zYxiiGrg+vc1MdtibkxECgYEAl6kymRM7X7GLQnxRSzB5\nE3JohWDPW8g8fRTRx/vfkU8a2NL25PS9R98dEHBnUUzVDiDfTNzyl6KzpJ1Kkkpb\nbHBAVeWeucSh4our3s+SY4SNf4rviEt97mokGtKBn60LVbzH7CpSxDJlCFdSE/s/\n+MUwvIqzCk6k6pIyoF+LWZ0CgYBosLgP/hF4CiQUbwvVCH6rjNzkfsqwWXPJkk2e\nxWpgFHi0ic/e904P1DPxFGnb84iZsOwWkefple80ef2rrU9Sc+ogVI5GlQNNDKzt\n+wmcbvFfP315Ul+Vn7q/bh65Ncj3rADgRPQS6As/+Afltj/hCOcDl7HNUjoSS3/u\nSkGQoQKBgQCNDLkWVeAQefC319GosByvCb9zzug1hXr6IKguWJvNOC+I/TPwRdEz\nQby3s5IL3rf1ZfJfOWlFXYeV41OQOOnsvpE1+ORJUjpJ7RgQsFWewLsSitRpxekU\nEV8b1+7OWOeTgu9M65XtZapKXb9pFE+OCit+q4fbAGcAh8ITt66aJw==\n-----END RSA PRIVATE KEY-----\n","appId":"100962076121426673","clientId":"100962076121492209@zitadel_net"}
\ No newline at end of file
diff --git a/tests/Zitadel.Test/service-account.json b/tests/Zitadel.Test/service-account.json
new file mode 100644
index 00000000..b6e85660
--- /dev/null
+++ b/tests/Zitadel.Test/service-account.json
@@ -0,0 +1,6 @@
+{
+ "type": "serviceaccount",
+ "keyId": "100820491081673449",
+ "key": "-----BEGIN RSA PRIVATE KEY-----\nMIIEpQIBAAKCAQEAtxkh+++/afNlrpVQxCtcfwDtWtc4MwF/SfW3TNuXgnNP52MG\ni3Gb4voLJHh+IjuLubDt2GSkFsvRmdqNU8rYF5ATtVnSwaA8I76FZwHpTYPRqM4j\nrUjCQTv8V+1xKlzDANn0pq+aJuUwP89TmOgk+S5yKHdc9Am27SxFxXlIjeyr/t//\nQE4BLp8BLjbWqb04s9kWUdZhnPyvrjekmO2F0P58xUKq7Of7wgbA7aSY610TSzMj\nyZpToByO3NSaLOIQEmgiXMGXIrH1SeGvZ2YWe2ONoEp1RJBel2MvcfzOWIHWtsfG\nS8FCnq/tS4kTQaNvcSgv1OHHIaST11rZ7ETzNwIDAQABAoIBAQCNAmYRyMn5puGg\nWo4hBePuS6CAXU+CuJx3MS1Bm7xLUtMuuCzKJ2yOmVMLe2BorMMm9wO1q4xTohSC\nELbW2VkijGshN1QAmo62WHwUoHw0nlhRULBZO7ee1bu5W7vTjC0B8tlfpc1qNwe5\nnMoc8GvJG+P/Fi4YI4MllPsG4ijmYxfJKQcw5EZofW53RGdYsxBeAn6AHeK1To9/\nMVidEEQFHpDP4S5sE+oE8PAmy4FXpTUkCHqK0hj9Iyn1MvqzYBA9AkPJHkDOgMIG\nu2yH4ld1+BqPOFaD2i9+n++DS7PuD0k5GAZnHVNvOef7p0zzcf7pU8HvQ81rY+en\nP5yj58BBAoGBAMPIajJkhJOqCVSTEK+OobNeq/htdGk0A0soj1X11Oj8OdQqcmti\nRsAib4AGsuZ232dCQktHrRgehvbOX11KawvNm6IHVV55v8BdXaFNPknUszduMUH/\nRZKzrIJbvHmJh+A1NLMS5gGJ27pLuOBEuQMuqjlgbz/wnFJgy1UyNjtrAoGBAO9p\n8rwhj8WBUawtK8JomOXw5WT4Pj+Q2tq78fSQd4RBN5+lJoX/PHMMFB+hYG5Pc5Wr\ntQB/6jXer/k8h0EnT1rLLVBaxMAfTRivVrbN6sZmlFX/CbYcLyWFF0yefg2Bf6ro\ny8N+JJq7vENIcxzRqoCSakQvWzaRuGznsWFoMQZlAoGBALQa7V7YS4IP/S9ZbxMh\nUi3RHMCX6GxTVehRMrLwSGHgjk5YkhOpP87Gnu4Wu4L5vgCe2p+oG1tB0gS/ysjm\nid080zxWJLmZpMWQ3m5hwbhnvEp0y0mcTONs+HifbZ4c3+to5scJzp+Bs6oIuNVP\nQyfjSOMpjI40iYna05LXcz5rAoGBAK1kJhBqnh2EkwoHjPG3n0SpOvntb+fJmTdh\ndtKQ7n4yXX6ZtVTGjZkk3k4qKhS6JhP3z5cVDSMGrJvtYmeleKthCuhvVJ9wC/4c\nvsiWSbp3AGdn1ji2IM8jnMQ45UISz8uP3kMvUINgA/EWv4fXsYx8fcn0IjNbRh5Z\njvXk59yhAoGAWvPOyX+g02Oi4958WpOyG3hU5XxPUxWB1FMTsusatARwXOwbbl92\n5bBgz7eb4wXhfUf7U3sItIH4Kf7xSrZwwq2cbTfBUE7k78kPhYOaJQD7LxxmdE98\n44Kc2VWK82jZIhgcswjRuuxpTMzWB89mC5UQtzykK5/m7+LLbOMdtHg=\n-----END RSA PRIVATE KEY-----\n",
+ "userId": "85328809577999392"
+}