Repository: dexidp/dex

Issue:
gRPC endpoint for ListClients
### Preflight Checklist

- [X] I agree to follow the [Code of Conduct](https://github.com/dexidp/dex/blob/master/.github/CODE_OF_CONDUCT.md) that this project adheres to.
- [X] I have searched the [issue tracker](https://www.github.com/dexidp/dex/issues) for an issue that matches the one I want to file, without success.

### Problem Description

Api already have List endpoints for passwords and refresh tokens.
When someone install dex with storage backend (for example sql) and decides to add clients via gRPC there is no way to list all existing clients

### Proposed Solution

Add gRPC endpoint for ListClients

### Alternatives Considered

_No response_

### Additional Information

_No response_

Hints from issue comments:
@eLLIkin: +1@ifurs: It would be great to have that feature too for my automation tool https://github.com/ifurs/dexus-vault@daemonfire300: Added a PR for it: https://github.com/dexidp/dex/pull/4202

Solution patch:
diff --git a/.github/workflows/analysis-scorecard.yaml b/.github/workflows/analysis-scorecard.yaml
index 96036bcd..7adf42ad 100644
--- a/.github/workflows/analysis-scorecard.yaml
+++ b/.github/workflows/analysis-scorecard.yaml
@@ -23,7 +23,7 @@ jobs:
 
     steps:
       - name: Checkout repository
-        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+        uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
         with:
           persist-credentials: false
 
@@ -42,6 +42,6 @@ jobs:
           retention-days: 5
 
       - name: Upload results to GitHub Security tab
-        uses: github/codeql-action/upload-sarif@ce28f5bb42b7a9f2c824e633a3f6ee835bab6858 # v3.29.0
+        uses: github/codeql-action/upload-sarif@df559355d593797519d70b90fc8edd5db049e7a2 # v3.29.5
         with:
           sarif_file: results.sarif
diff --git a/.github/workflows/artifacts.yaml b/.github/workflows/artifacts.yaml
index 394e869c..1adc048d 100644
--- a/.github/workflows/artifacts.yaml
+++ b/.github/workflows/artifacts.yaml
@@ -51,7 +51,7 @@ jobs:
 
     steps:
       - name: Checkout repository
-        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+        uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
 
       - name: Set up QEMU
         uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0
@@ -60,7 +60,7 @@ jobs:
         uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
 
       - name: Set up Syft
-        uses: anchore/sbom-action/download-syft@cee1b8e05ae5b2593a75e197229729eabaa9f8ec # v0.20.2
+        uses: anchore/sbom-action/download-syft@da167eac915b4e86f08b264dbdbc867b61be6f0c # v0.20.5
 
       - name: Install cosign
         uses: sigstore/cosign-installer@d58896d6a1865668819e1d91763c7751a165e159 # v3.9.2
@@ -71,7 +71,7 @@ jobs:
 
       - name: Gather build metadata
         id: meta
-        uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5.7.0
+        uses: docker/metadata-action@c1e51972afc2121e065aed6d45c65596fe445f3f # v5.8.0
         with:
           images: |
             ${{ steps.image-name.outputs.value }}
@@ -101,7 +101,7 @@ jobs:
           if_false: type=oci,dest=image.tar
 
       - name: Login to GitHub Container Registry
-        uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
+        uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0
         with:
           registry: ghcr.io
           username: ${{ github.actor }}
@@ -109,7 +109,7 @@ jobs:
         if: inputs.publish
 
       - name: Login to Docker Hub
-        uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
+        uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0
         with:
           username: ${{ secrets.DOCKER_USERNAME }}
           password: ${{ secrets.DOCKER_PASSWORD }}
@@ -198,7 +198,7 @@ jobs:
         run: echo "date=$(date +%Y-%m-%d)" >> $GITHUB_OUTPUT
 
       - name: Restore trivy cache
-        uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
+        uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
         with:
           path: cache/db
           key: trivy-cache-${{ steps.date.outputs.date }}
@@ -233,6 +233,6 @@ jobs:
           overwrite: true
 
       - name: Upload Trivy scan results to GitHub Security tab
-        uses: github/codeql-action/upload-sarif@ce28f5bb42b7a9f2c824e633a3f6ee835bab6858 # v3.29.0
+        uses: github/codeql-action/upload-sarif@df559355d593797519d70b90fc8edd5db049e7a2 # v3.29.5
         with:
           sarif_file: trivy-results.sarif
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index f24ad280..b38ca64c 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -66,7 +66,7 @@ jobs:
 
     steps:
       - name: Checkout repository
-        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+        uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
 
       - name: Set up Go
         uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
@@ -137,7 +137,7 @@ jobs:
 
     steps:
       - name: Checkout repository
-        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+        uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
 
       - name: Set up Go
         uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
@@ -172,7 +172,7 @@ jobs:
 
     steps:
       - name: Checkout repository
-        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+        uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
 
       - name: Dependency Review
         uses: actions/dependency-review-action@da24556b548a50705dd671f47852072ea4c105d9 # v4.7.1
diff --git a/.github/workflows/trivydb-cache.yaml b/.github/workflows/trivydb-cache.yaml
index d1bc2463..b4409464 100644
--- a/.github/workflows/trivydb-cache.yaml
+++ b/.github/workflows/trivydb-cache.yaml
@@ -33,7 +33,7 @@ jobs:
           rm javadb.tar.gz
 
       - name: Cache DBs
-        uses: actions/cache/save@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
+        uses: actions/cache/save@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
         with:
           path: ${{ github.workspace }}/.cache/trivy
           key: cache-trivy-${{ steps.date.outputs.date }}
diff --git a/Dockerfile b/Dockerfile
index c3835c5f..f04f7e04 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -55,7 +55,7 @@ RUN wget -O /usr/local/bin/gomplate \
 
 # For Dependabot to detect base image versions
 FROM alpine:3.22.1@sha256:4bcff63911fcb4448bd4fdacec207030997caf25e9bea4045fa6c8c44de311d1 AS alpine
-FROM gcr.io/distroless/static-debian12:nonroot@sha256:627d6c5a23ad24e6bdff827f16c7b60e0289029b0c79e9f7ccd54ae3279fb45f AS distroless
+FROM gcr.io/distroless/static-debian12:nonroot@sha256:cdf4daaf154e3e27cfffc799c16f343a384228f38646928a1513d925f473cb46 AS distroless
 
 FROM $BASE_IMAGE
 
diff --git a/api/v2/api.pb.go b/api/v2/api.pb.go
index e0e1f1bd..6e8a134e 100644
--- a/api/v2/api.pb.go
+++ b/api/v2/api.pb.go
@@ -114,6 +114,91 @@ func (x *Client) GetLogoUrl() string {
 	return ""
 }
 
+// ClientInfo represents an OAuth2 client without sensitive information.
+type ClientInfo struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	Id            string                 `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
+	RedirectUris  []string               `protobuf:"bytes,2,rep,name=redirect_uris,json=redirectUris,proto3" json:"redirect_uris,omitempty"`
+	TrustedPeers  []string               `protobuf:"bytes,3,rep,name=trusted_peers,json=trustedPeers,proto3" json:"trusted_peers,omitempty"`
+	Public        bool                   `protobuf:"varint,4,opt,name=public,proto3" json:"public,omitempty"`
+	Name          string                 `protobuf:"bytes,5,opt,name=name,proto3" json:"name,omitempty"`
+	LogoUrl       string                 `protobuf:"bytes,6,opt,name=logo_url,json=logoUrl,proto3" json:"logo_url,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *ClientInfo) Reset() {
+	*x = ClientInfo{}
+	mi := &file_api_v2_api_proto_msgTypes[1]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *ClientInfo) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ClientInfo) ProtoMessage() {}
+
+func (x *ClientInfo) ProtoReflect() protoreflect.Message {
+	mi := &file_api_v2_api_proto_msgTypes[1]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ClientInfo.ProtoReflect.Descriptor instead.
+func (*ClientInfo) Descriptor() ([]byte, []int) {
+	return file_api_v2_api_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *ClientInfo) GetId() string {
+	if x != nil {
+		return x.Id
+	}
+	return ""
+}
+
+func (x *ClientInfo) GetRedirectUris() []string {
+	if x != nil {
+		return x.RedirectUris
+	}
+	return nil
+}
+
+func (x *ClientInfo) GetTrustedPeers() []string {
+	if x != nil {
+		return x.TrustedPeers
+	}
+	return nil
+}
+
+func (x *ClientInfo) GetPublic() bool {
+	if x != nil {
+		return x.Public
+	}
+	return false
+}
+
+func (x *ClientInfo) GetName() string {
+	if x != nil {
+		return x.Name
+	}
+	return ""
+}
+
+func (x *ClientInfo) GetLogoUrl() string {
+	if x != nil {
+		return x.LogoUrl
+	}
+	return ""
+}
+
 // GetClientReq is a request to retrieve client details.
 type GetClientReq struct {
 	state protoimpl.MessageState `protogen:"open.v1"`
@@ -125,7 +210,7 @@ type GetClientReq struct {
 
 func (x *GetClientReq) Reset() {
 	*x = GetClientReq{}
-	mi := &file_api_v2_api_proto_msgTypes[1]
+	mi := &file_api_v2_api_proto_msgTypes[2]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -137,7 +222,7 @@ func (x *GetClientReq) String() string {
 func (*GetClientReq) ProtoMessage() {}
 
 func (x *GetClientReq) ProtoReflect() protoreflect.Message {
-	mi := &file_api_v2_api_proto_msgTypes[1]
+	mi := &file_api_v2_api_proto_msgTypes[2]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -150,7 +235,7 @@ func (x *GetClientReq) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use GetClientReq.ProtoReflect.Descriptor instead.
 func (*GetClientReq) Descriptor() ([]byte, []int) {
-	return file_api_v2_api_proto_rawDescGZIP(), []int{1}
+	return file_api_v2_api_proto_rawDescGZIP(), []int{2}
 }
 
 func (x *GetClientReq) GetId() string {
@@ -170,7 +255,7 @@ type GetClientResp struct {
 
 func (x *GetClientResp) Reset() {
 	*x = GetClientResp{}
-	mi := &file_api_v2_api_proto_msgTypes[2]
+	mi := &file_api_v2_api_proto_msgTypes[3]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -182,7 +267,7 @@ func (x *GetClientResp) String() string {
 func (*GetClientResp) ProtoMessage() {}
 
 func (x *GetClientResp) ProtoReflect() protoreflect.Message {
-	mi := &file_api_v2_api_proto_msgTypes[2]
+	mi := &file_api_v2_api_proto_msgTypes[3]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -195,7 +280,7 @@ func (x *GetClientResp) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use GetClientResp.ProtoReflect.Descriptor instead.
 func (*GetClientResp) Descriptor() ([]byte, []int) {
-	return file_api_v2_api_proto_rawDescGZIP(), []int{2}
+	return file_api_v2_api_proto_rawDescGZIP(), []int{3}
 }
 
 func (x *GetClientResp) GetClient() *Client {
@@ -215,7 +300,7 @@ type CreateClientReq struct {
 
 func (x *CreateClientReq) Reset() {
 	*x = CreateClientReq{}
-	mi := &file_api_v2_api_proto_msgTypes[3]
+	mi := &file_api_v2_api_proto_msgTypes[4]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -227,7 +312,7 @@ func (x *CreateClientReq) String() string {
 func (*CreateClientReq) ProtoMessage() {}
 
 func (x *CreateClientReq) ProtoReflect() protoreflect.Message {
-	mi := &file_api_v2_api_proto_msgTypes[3]
+	mi := &file_api_v2_api_proto_msgTypes[4]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -240,7 +325,7 @@ func (x *CreateClientReq) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use CreateClientReq.ProtoReflect.Descriptor instead.
 func (*CreateClientReq) Descriptor() ([]byte, []int) {
-	return file_api_v2_api_proto_rawDescGZIP(), []int{3}
+	return file_api_v2_api_proto_rawDescGZIP(), []int{4}
 }
 
 func (x *CreateClientReq) GetClient() *Client {
@@ -261,7 +346,7 @@ type CreateClientResp struct {
 
 func (x *CreateClientResp) Reset() {
 	*x = CreateClientResp{}
-	mi := &file_api_v2_api_proto_msgTypes[4]
+	mi := &file_api_v2_api_proto_msgTypes[5]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -273,7 +358,7 @@ func (x *CreateClientResp) String() string {
 func (*CreateClientResp) ProtoMessage() {}
 
 func (x *CreateClientResp) ProtoReflect() protoreflect.Message {
-	mi := &file_api_v2_api_proto_msgTypes[4]
+	mi := &file_api_v2_api_proto_msgTypes[5]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -286,7 +371,7 @@ func (x *CreateClientResp) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use CreateClientResp.ProtoReflect.Descriptor instead.
 func (*CreateClientResp) Descriptor() ([]byte, []int) {
-	return file_api_v2_api_proto_rawDescGZIP(), []int{4}
+	return file_api_v2_api_proto_rawDescGZIP(), []int{5}
 }
 
 func (x *CreateClientResp) GetAlreadyExists() bool {
@@ -314,7 +399,7 @@ type DeleteClientReq struct {
 
 func (x *DeleteClientReq) Reset() {
 	*x = DeleteClientReq{}
-	mi := &file_api_v2_api_proto_msgTypes[5]
+	mi := &file_api_v2_api_proto_msgTypes[6]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -326,7 +411,7 @@ func (x *DeleteClientReq) String() string {
 func (*DeleteClientReq) ProtoMessage() {}
 
 func (x *DeleteClientReq) ProtoReflect() protoreflect.Message {
-	mi := &file_api_v2_api_proto_msgTypes[5]
+	mi := &file_api_v2_api_proto_msgTypes[6]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -339,7 +424,7 @@ func (x *DeleteClientReq) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use DeleteClientReq.ProtoReflect.Descriptor instead.
 func (*DeleteClientReq) Descriptor() ([]byte, []int) {
-	return file_api_v2_api_proto_rawDescGZIP(), []int{5}
+	return file_api_v2_api_proto_rawDescGZIP(), []int{6}
 }
 
 func (x *DeleteClientReq) GetId() string {
@@ -359,7 +444,7 @@ type DeleteClientResp struct {
 
 func (x *DeleteClientResp) Reset() {
 	*x = DeleteClientResp{}
-	mi := &file_api_v2_api_proto_msgTypes[6]
+	mi := &file_api_v2_api_proto_msgTypes[7]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -371,7 +456,7 @@ func (x *DeleteClientResp) String() string {
 func (*DeleteClientResp) ProtoMessage() {}
 
 func (x *DeleteClientResp) ProtoReflect() protoreflect.Message {
-	mi := &file_api_v2_api_proto_msgTypes[6]
+	mi := &file_api_v2_api_proto_msgTypes[7]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -384,7 +469,7 @@ func (x *DeleteClientResp) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use DeleteClientResp.ProtoReflect.Descriptor instead.
 func (*DeleteClientResp) Descriptor() ([]byte, []int) {
-	return file_api_v2_api_proto_rawDescGZIP(), []int{6}
+	return file_api_v2_api_proto_rawDescGZIP(), []int{7}
 }
 
 func (x *DeleteClientResp) GetNotFound() bool {
@@ -408,7 +493,7 @@ type UpdateClientReq struct {
 
 func (x *UpdateClientReq) Reset() {
 	*x = UpdateClientReq{}
-	mi := &file_api_v2_api_proto_msgTypes[7]
+	mi := &file_api_v2_api_proto_msgTypes[8]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -420,7 +505,7 @@ func (x *UpdateClientReq) String() string {
 func (*UpdateClientReq) ProtoMessage() {}
 
 func (x *UpdateClientReq) ProtoReflect() protoreflect.Message {
-	mi := &file_api_v2_api_proto_msgTypes[7]
+	mi := &file_api_v2_api_proto_msgTypes[8]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -433,7 +518,7 @@ func (x *UpdateClientReq) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use UpdateClientReq.ProtoReflect.Descriptor instead.
 func (*UpdateClientReq) Descriptor() ([]byte, []int) {
-	return file_api_v2_api_proto_rawDescGZIP(), []int{7}
+	return file_api_v2_api_proto_rawDescGZIP(), []int{8}
 }
 
 func (x *UpdateClientReq) GetId() string {
@@ -481,7 +566,7 @@ type UpdateClientResp struct {
 
 func (x *UpdateClientResp) Reset() {
 	*x = UpdateClientResp{}
-	mi := &file_api_v2_api_proto_msgTypes[8]
+	mi := &file_api_v2_api_proto_msgTypes[9]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -493,7 +578,7 @@ func (x *UpdateClientResp) String() string {
 func (*UpdateClientResp) ProtoMessage() {}
 
 func (x *UpdateClientResp) ProtoReflect() protoreflect.Message {
-	mi := &file_api_v2_api_proto_msgTypes[8]
+	mi := &file_api_v2_api_proto_msgTypes[9]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -506,7 +591,7 @@ func (x *UpdateClientResp) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use UpdateClientResp.ProtoReflect.Descriptor instead.
 func (*UpdateClientResp) Descriptor() ([]byte, []int) {
-	return file_api_v2_api_proto_rawDescGZIP(), []int{8}
+	return file_api_v2_api_proto_rawDescGZIP(), []int{9}
 }
 
 func (x *UpdateClientResp) GetNotFound() bool {
@@ -516,6 +601,88 @@ func (x *UpdateClientResp) GetNotFound() bool {
 	return false
 }
 
+// ListClientReq is a request to enumerate clients.
+type ListClientReq struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *ListClientReq) Reset() {
+	*x = ListClientReq{}
+	mi := &file_api_v2_api_proto_msgTypes[10]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *ListClientReq) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ListClientReq) ProtoMessage() {}
+
+func (x *ListClientReq) ProtoReflect() protoreflect.Message {
+	mi := &file_api_v2_api_proto_msgTypes[10]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ListClientReq.ProtoReflect.Descriptor instead.
+func (*ListClientReq) Descriptor() ([]byte, []int) {
+	return file_api_v2_api_proto_rawDescGZIP(), []int{10}
+}
+
+// ListClientResp returns a list of clients.
+type ListClientResp struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	Clients       []*ClientInfo          `protobuf:"bytes,1,rep,name=clients,proto3" json:"clients,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *ListClientResp) Reset() {
+	*x = ListClientResp{}
+	mi := &file_api_v2_api_proto_msgTypes[11]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *ListClientResp) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ListClientResp) ProtoMessage() {}
+
+func (x *ListClientResp) ProtoReflect() protoreflect.Message {
+	mi := &file_api_v2_api_proto_msgTypes[11]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ListClientResp.ProtoReflect.Descriptor instead.
+func (*ListClientResp) Descriptor() ([]byte, []int) {
+	return file_api_v2_api_proto_rawDescGZIP(), []int{11}
+}
+
+func (x *ListClientResp) GetClients() []*ClientInfo {
+	if x != nil {
+		return x.Clients
+	}
+	return nil
+}
+
 // Password is an email for password mapping managed by the storage.
 type Password struct {
 	state protoimpl.MessageState `protogen:"open.v1"`
@@ -530,7 +697,7 @@ type Password struct {
 
 func (x *Password) Reset() {
 	*x = Password{}
-	mi := &file_api_v2_api_proto_msgTypes[9]
+	mi := &file_api_v2_api_proto_msgTypes[12]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -542,7 +709,7 @@ func (x *Password) String() string {
 func (*Password) ProtoMessage() {}
 
 func (x *Password) ProtoReflect() protoreflect.Message {
-	mi := &file_api_v2_api_proto_msgTypes[9]
+	mi := &file_api_v2_api_proto_msgTypes[12]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -555,7 +722,7 @@ func (x *Password) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use Password.ProtoReflect.Descriptor instead.
 func (*Password) Descriptor() ([]byte, []int) {
-	return file_api_v2_api_proto_rawDescGZIP(), []int{9}
+	return file_api_v2_api_proto_rawDescGZIP(), []int{12}
 }
 
 func (x *Password) GetEmail() string {
@@ -596,7 +763,7 @@ type CreatePasswordReq struct {
 
 func (x *CreatePasswordReq) Reset() {
 	*x = CreatePasswordReq{}
-	mi := &file_api_v2_api_proto_msgTypes[10]
+	mi := &file_api_v2_api_proto_msgTypes[13]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -608,7 +775,7 @@ func (x *CreatePasswordReq) String() string {
 func (*CreatePasswordReq) ProtoMessage() {}
 
 func (x *CreatePasswordReq) ProtoReflect() protoreflect.Message {
-	mi := &file_api_v2_api_proto_msgTypes[10]
+	mi := &file_api_v2_api_proto_msgTypes[13]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -621,7 +788,7 @@ func (x *CreatePasswordReq) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use CreatePasswordReq.ProtoReflect.Descriptor instead.
 func (*CreatePasswordReq) Descriptor() ([]byte, []int) {
-	return file_api_v2_api_proto_rawDescGZIP(), []int{10}
+	return file_api_v2_api_proto_rawDescGZIP(), []int{13}
 }
 
 func (x *CreatePasswordReq) GetPassword() *Password {
@@ -641,7 +808,7 @@ type CreatePasswordResp struct {
 
 func (x *CreatePasswordResp) Reset() {
 	*x = CreatePasswordResp{}
-	mi := &file_api_v2_api_proto_msgTypes[11]
+	mi := &file_api_v2_api_proto_msgTypes[14]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -653,7 +820,7 @@ func (x *CreatePasswordResp) String() string {
 func (*CreatePasswordResp) ProtoMessage() {}
 
 func (x *CreatePasswordResp) ProtoReflect() protoreflect.Message {
-	mi := &file_api_v2_api_proto_msgTypes[11]
+	mi := &file_api_v2_api_proto_msgTypes[14]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -666,7 +833,7 @@ func (x *CreatePasswordResp) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use CreatePasswordResp.ProtoReflect.Descriptor instead.
 func (*CreatePasswordResp) Descriptor() ([]byte, []int) {
-	return file_api_v2_api_proto_rawDescGZIP(), []int{11}
+	return file_api_v2_api_proto_rawDescGZIP(), []int{14}
 }
 
 func (x *CreatePasswordResp) GetAlreadyExists() bool {
@@ -689,7 +856,7 @@ type UpdatePasswordReq struct {
 
 func (x *UpdatePasswordReq) Reset() {
 	*x = UpdatePasswordReq{}
-	mi := &file_api_v2_api_proto_msgTypes[12]
+	mi := &file_api_v2_api_proto_msgTypes[15]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -701,7 +868,7 @@ func (x *UpdatePasswordReq) String() string {
 func (*UpdatePasswordReq) ProtoMessage() {}
 
 func (x *UpdatePasswordReq) ProtoReflect() protoreflect.Message {
-	mi := &file_api_v2_api_proto_msgTypes[12]
+	mi := &file_api_v2_api_proto_msgTypes[15]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -714,7 +881,7 @@ func (x *UpdatePasswordReq) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use UpdatePasswordReq.ProtoReflect.Descriptor instead.
 func (*UpdatePasswordReq) Descriptor() ([]byte, []int) {
-	return file_api_v2_api_proto_rawDescGZIP(), []int{12}
+	return file_api_v2_api_proto_rawDescGZIP(), []int{15}
 }
 
 func (x *UpdatePasswordReq) GetEmail() string {
@@ -748,7 +915,7 @@ type UpdatePasswordResp struct {
 
 func (x *UpdatePasswordResp) Reset() {
 	*x = UpdatePasswordResp{}
-	mi := &file_api_v2_api_proto_msgTypes[13]
+	mi := &file_api_v2_api_proto_msgTypes[16]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -760,7 +927,7 @@ func (x *UpdatePasswordResp) String() string {
 func (*UpdatePasswordResp) ProtoMessage() {}
 
 func (x *UpdatePasswordResp) ProtoReflect() protoreflect.Message {
-	mi := &file_api_v2_api_proto_msgTypes[13]
+	mi := &file_api_v2_api_proto_msgTypes[16]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -773,7 +940,7 @@ func (x *UpdatePasswordResp) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use UpdatePasswordResp.ProtoReflect.Descriptor instead.
 func (*UpdatePasswordResp) Descriptor() ([]byte, []int) {
-	return file_api_v2_api_proto_rawDescGZIP(), []int{13}
+	return file_api_v2_api_proto_rawDescGZIP(), []int{16}
 }
 
 func (x *UpdatePasswordResp) GetNotFound() bool {
@@ -793,7 +960,7 @@ type DeletePasswordReq struct {
 
 func (x *DeletePasswordReq) Reset() {
 	*x = DeletePasswordReq{}
-	mi := &file_api_v2_api_proto_msgTypes[14]
+	mi := &file_api_v2_api_proto_msgTypes[17]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -805,7 +972,7 @@ func (x *DeletePasswordReq) String() string {
 func (*DeletePasswordReq) ProtoMessage() {}
 
 func (x *DeletePasswordReq) ProtoReflect() protoreflect.Message {
-	mi := &file_api_v2_api_proto_msgTypes[14]
+	mi := &file_api_v2_api_proto_msgTypes[17]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -818,7 +985,7 @@ func (x *DeletePasswordReq) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use DeletePasswordReq.ProtoReflect.Descriptor instead.
 func (*DeletePasswordReq) Descriptor() ([]byte, []int) {
-	return file_api_v2_api_proto_rawDescGZIP(), []int{14}
+	return file_api_v2_api_proto_rawDescGZIP(), []int{17}
 }
 
 func (x *DeletePasswordReq) GetEmail() string {
@@ -838,7 +1005,7 @@ type DeletePasswordResp struct {
 
 func (x *DeletePasswordResp) Reset() {
 	*x = DeletePasswordResp{}
-	mi := &file_api_v2_api_proto_msgTypes[15]
+	mi := &file_api_v2_api_proto_msgTypes[18]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -850,7 +1017,7 @@ func (x *DeletePasswordResp) String() string {
 func (*DeletePasswordResp) ProtoMessage() {}
 
 func (x *DeletePasswordResp) ProtoReflect() protoreflect.Message {
-	mi := &file_api_v2_api_proto_msgTypes[15]
+	mi := &file_api_v2_api_proto_msgTypes[18]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -863,7 +1030,7 @@ func (x *DeletePasswordResp) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use DeletePasswordResp.ProtoReflect.Descriptor instead.
 func (*DeletePasswordResp) Descriptor() ([]byte, []int) {
-	return file_api_v2_api_proto_rawDescGZIP(), []int{15}
+	return file_api_v2_api_proto_rawDescGZIP(), []int{18}
 }
 
 func (x *DeletePasswordResp) GetNotFound() bool {
@@ -882,7 +1049,7 @@ type ListPasswordReq struct {
 
 func (x *ListPasswordReq) Reset() {
 	*x = ListPasswordReq{}
-	mi := &file_api_v2_api_proto_msgTypes[16]
+	mi := &file_api_v2_api_proto_msgTypes[19]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -894,7 +1061,7 @@ func (x *ListPasswordReq) String() string {
 func (*ListPasswordReq) ProtoMessage() {}
 
 func (x *ListPasswordReq) ProtoReflect() protoreflect.Message {
-	mi := &file_api_v2_api_proto_msgTypes[16]
+	mi := &file_api_v2_api_proto_msgTypes[19]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -907,7 +1074,7 @@ func (x *ListPasswordReq) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use ListPasswordReq.ProtoReflect.Descriptor instead.
 func (*ListPasswordReq) Descriptor() ([]byte, []int) {
-	return file_api_v2_api_proto_rawDescGZIP(), []int{16}
+	return file_api_v2_api_proto_rawDescGZIP(), []int{19}
 }
 
 // ListPasswordResp returns a list of passwords.
@@ -920,7 +1087,7 @@ type ListPasswordResp struct {
 
 func (x *ListPasswordResp) Reset() {
 	*x = ListPasswordResp{}
-	mi := &file_api_v2_api_proto_msgTypes[17]
+	mi := &file_api_v2_api_proto_msgTypes[20]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -932,7 +1099,7 @@ func (x *ListPasswordResp) String() string {
 func (*ListPasswordResp) ProtoMessage() {}
 
 func (x *ListPasswordResp) ProtoReflect() protoreflect.Message {
-	mi := &file_api_v2_api_proto_msgTypes[17]
+	mi := &file_api_v2_api_proto_msgTypes[20]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -945,7 +1112,7 @@ func (x *ListPasswordResp) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use ListPasswordResp.ProtoReflect.Descriptor instead.
 func (*ListPasswordResp) Descriptor() ([]byte, []int) {
-	return file_api_v2_api_proto_rawDescGZIP(), []int{17}
+	return file_api_v2_api_proto_rawDescGZIP(), []int{20}
 }
 
 func (x *ListPasswordResp) GetPasswords() []*Password {
@@ -968,7 +1135,7 @@ type Connector struct {
 
 func (x *Connector) Reset() {
 	*x = Connector{}
-	mi := &file_api_v2_api_proto_msgTypes[18]
+	mi := &file_api_v2_api_proto_msgTypes[21]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -980,7 +1147,7 @@ func (x *Connector) String() string {
 func (*Connector) ProtoMessage() {}
 
 func (x *Connector) ProtoReflect() protoreflect.Message {
-	mi := &file_api_v2_api_proto_msgTypes[18]
+	mi := &file_api_v2_api_proto_msgTypes[21]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -993,7 +1160,7 @@ func (x *Connector) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use Connector.ProtoReflect.Descriptor instead.
 func (*Connector) Descriptor() ([]byte, []int) {
-	return file_api_v2_api_proto_rawDescGZIP(), []int{18}
+	return file_api_v2_api_proto_rawDescGZIP(), []int{21}
 }
 
 func (x *Connector) GetId() string {
@@ -1034,7 +1201,7 @@ type CreateConnectorReq struct {
 
 func (x *CreateConnectorReq) Reset() {
 	*x = CreateConnectorReq{}
-	mi := &file_api_v2_api_proto_msgTypes[19]
+	mi := &file_api_v2_api_proto_msgTypes[22]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -1046,7 +1213,7 @@ func (x *CreateConnectorReq) String() string {
 func (*CreateConnectorReq) ProtoMessage() {}
 
 func (x *CreateConnectorReq) ProtoReflect() protoreflect.Message {
-	mi := &file_api_v2_api_proto_msgTypes[19]
+	mi := &file_api_v2_api_proto_msgTypes[22]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1059,7 +1226,7 @@ func (x *CreateConnectorReq) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use CreateConnectorReq.ProtoReflect.Descriptor instead.
 func (*CreateConnectorReq) Descriptor() ([]byte, []int) {
-	return file_api_v2_api_proto_rawDescGZIP(), []int{19}
+	return file_api_v2_api_proto_rawDescGZIP(), []int{22}
 }
 
 func (x *CreateConnectorReq) GetConnector() *Connector {
@@ -1079,7 +1246,7 @@ type CreateConnectorResp struct {
 
 func (x *CreateConnectorResp) Reset() {
 	*x = CreateConnectorResp{}
-	mi := &file_api_v2_api_proto_msgTypes[20]
+	mi := &file_api_v2_api_proto_msgTypes[23]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -1091,7 +1258,7 @@ func (x *CreateConnectorResp) String() string {
 func (*CreateConnectorResp) ProtoMessage() {}
 
 func (x *CreateConnectorResp) ProtoReflect() protoreflect.Message {
-	mi := &file_api_v2_api_proto_msgTypes[20]
+	mi := &file_api_v2_api_proto_msgTypes[23]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1104,7 +1271,7 @@ func (x *CreateConnectorResp) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use CreateConnectorResp.ProtoReflect.Descriptor instead.
 func (*CreateConnectorResp) Descriptor() ([]byte, []int) {
-	return file_api_v2_api_proto_rawDescGZIP(), []int{20}
+	return file_api_v2_api_proto_rawDescGZIP(), []int{23}
 }
 
 func (x *CreateConnectorResp) GetAlreadyExists() bool {
@@ -1128,7 +1295,7 @@ type UpdateConnectorReq struct {
 
 func (x *UpdateConnectorReq) Reset() {
 	*x = UpdateConnectorReq{}
-	mi := &file_api_v2_api_proto_msgTypes[21]
+	mi := &file_api_v2_api_proto_msgTypes[24]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -1140,7 +1307,7 @@ func (x *UpdateConnectorReq) String() string {
 func (*UpdateConnectorReq) ProtoMessage() {}
 
 func (x *UpdateConnectorReq) ProtoReflect() protoreflect.Message {
-	mi := &file_api_v2_api_proto_msgTypes[21]
+	mi := &file_api_v2_api_proto_msgTypes[24]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1153,7 +1320,7 @@ func (x *UpdateConnectorReq) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use UpdateConnectorReq.ProtoReflect.Descriptor instead.
 func (*UpdateConnectorReq) Descriptor() ([]byte, []int) {
-	return file_api_v2_api_proto_rawDescGZIP(), []int{21}
+	return file_api_v2_api_proto_rawDescGZIP(), []int{24}
 }
 
 func (x *UpdateConnectorReq) GetId() string {
@@ -1194,7 +1361,7 @@ type UpdateConnectorResp struct {
 
 func (x *UpdateConnectorResp) Reset() {
 	*x = UpdateConnectorResp{}
-	mi := &file_api_v2_api_proto_msgTypes[22]
+	mi := &file_api_v2_api_proto_msgTypes[25]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -1206,7 +1373,7 @@ func (x *UpdateConnectorResp) String() string {
 func (*UpdateConnectorResp) ProtoMessage() {}
 
 func (x *UpdateConnectorResp) ProtoReflect() protoreflect.Message {
-	mi := &file_api_v2_api_proto_msgTypes[22]
+	mi := &file_api_v2_api_proto_msgTypes[25]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1219,7 +1386,7 @@ func (x *UpdateConnectorResp) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use UpdateConnectorResp.ProtoReflect.Descriptor instead.
 func (*UpdateConnectorResp) Descriptor() ([]byte, []int) {
-	return file_api_v2_api_proto_rawDescGZIP(), []int{22}
+	return file_api_v2_api_proto_rawDescGZIP(), []int{25}
 }
 
 func (x *UpdateConnectorResp) GetNotFound() bool {
@@ -1239,7 +1406,7 @@ type DeleteConnectorReq struct {
 
 func (x *DeleteConnectorReq) Reset() {
 	*x = DeleteConnectorReq{}
-	mi := &file_api_v2_api_proto_msgTypes[23]
+	mi := &file_api_v2_api_proto_msgTypes[26]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -1251,7 +1418,7 @@ func (x *DeleteConnectorReq) String() string {
 func (*DeleteConnectorReq) ProtoMessage() {}
 
 func (x *DeleteConnectorReq) ProtoReflect() protoreflect.Message {
-	mi := &file_api_v2_api_proto_msgTypes[23]
+	mi := &file_api_v2_api_proto_msgTypes[26]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1264,7 +1431,7 @@ func (x *DeleteConnectorReq) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use DeleteConnectorReq.ProtoReflect.Descriptor instead.
 func (*DeleteConnectorReq) Descriptor() ([]byte, []int) {
-	return file_api_v2_api_proto_rawDescGZIP(), []int{23}
+	return file_api_v2_api_proto_rawDescGZIP(), []int{26}
 }
 
 func (x *DeleteConnectorReq) GetId() string {
@@ -1284,7 +1451,7 @@ type DeleteConnectorResp struct {
 
 func (x *DeleteConnectorResp) Reset() {
 	*x = DeleteConnectorResp{}
-	mi := &file_api_v2_api_proto_msgTypes[24]
+	mi := &file_api_v2_api_proto_msgTypes[27]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -1296,7 +1463,7 @@ func (x *DeleteConnectorResp) String() string {
 func (*DeleteConnectorResp) ProtoMessage() {}
 
 func (x *DeleteConnectorResp) ProtoReflect() protoreflect.Message {
-	mi := &file_api_v2_api_proto_msgTypes[24]
+	mi := &file_api_v2_api_proto_msgTypes[27]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1309,7 +1476,7 @@ func (x *DeleteConnectorResp) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use DeleteConnectorResp.ProtoReflect.Descriptor instead.
 func (*DeleteConnectorResp) Descriptor() ([]byte, []int) {
-	return file_api_v2_api_proto_rawDescGZIP(), []int{24}
+	return file_api_v2_api_proto_rawDescGZIP(), []int{27}
 }
 
 func (x *DeleteConnectorResp) GetNotFound() bool {
@@ -1328,7 +1495,7 @@ type ListConnectorReq struct {
 
 func (x *ListConnectorReq) Reset() {
 	*x = ListConnectorReq{}
-	mi := &file_api_v2_api_proto_msgTypes[25]
+	mi := &file_api_v2_api_proto_msgTypes[28]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -1340,7 +1507,7 @@ func (x *ListConnectorReq) String() string {
 func (*ListConnectorReq) ProtoMessage() {}
 
 func (x *ListConnectorReq) ProtoReflect() protoreflect.Message {
-	mi := &file_api_v2_api_proto_msgTypes[25]
+	mi := &file_api_v2_api_proto_msgTypes[28]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1353,7 +1520,7 @@ func (x *ListConnectorReq) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use ListConnectorReq.ProtoReflect.Descriptor instead.
 func (*ListConnectorReq) Descriptor() ([]byte, []int) {
-	return file_api_v2_api_proto_rawDescGZIP(), []int{25}
+	return file_api_v2_api_proto_rawDescGZIP(), []int{28}
 }
 
 // ListConnectorResp returns a list of connectors.
@@ -1366,7 +1533,7 @@ type ListConnectorResp struct {
 
 func (x *ListConnectorResp) Reset() {
 	*x = ListConnectorResp{}
-	mi := &file_api_v2_api_proto_msgTypes[26]
+	mi := &file_api_v2_api_proto_msgTypes[29]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -1378,7 +1545,7 @@ func (x *ListConnectorResp) String() string {
 func (*ListConnectorResp) ProtoMessage() {}
 
 func (x *ListConnectorResp) ProtoReflect() protoreflect.Message {
-	mi := &file_api_v2_api_proto_msgTypes[26]
+	mi := &file_api_v2_api_proto_msgTypes[29]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1391,7 +1558,7 @@ func (x *ListConnectorResp) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use ListConnectorResp.ProtoReflect.Descriptor instead.
 func (*ListConnectorResp) Descriptor() ([]byte, []int) {
-	return file_api_v2_api_proto_rawDescGZIP(), []int{26}
+	return file_api_v2_api_proto_rawDescGZIP(), []int{29}
 }
 
 func (x *ListConnectorResp) GetConnectors() []*Connector {
@@ -1410,7 +1577,7 @@ type VersionReq struct {
 
 func (x *VersionReq) Reset() {
 	*x = VersionReq{}
-	mi := &file_api_v2_api_proto_msgTypes[27]
+	mi := &file_api_v2_api_proto_msgTypes[30]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -1422,7 +1589,7 @@ func (x *VersionReq) String() string {
 func (*VersionReq) ProtoMessage() {}
 
 func (x *VersionReq) ProtoReflect() protoreflect.Message {
-	mi := &file_api_v2_api_proto_msgTypes[27]
+	mi := &file_api_v2_api_proto_msgTypes[30]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1435,7 +1602,7 @@ func (x *VersionReq) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use VersionReq.ProtoReflect.Descriptor instead.
 func (*VersionReq) Descriptor() ([]byte, []int) {
-	return file_api_v2_api_proto_rawDescGZIP(), []int{27}
+	return file_api_v2_api_proto_rawDescGZIP(), []int{30}
 }
 
 // VersionResp holds the version info of components.
@@ -1452,7 +1619,7 @@ type VersionResp struct {
 
 func (x *VersionResp) Reset() {
 	*x = VersionResp{}
-	mi := &file_api_v2_api_proto_msgTypes[28]
+	mi := &file_api_v2_api_proto_msgTypes[31]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -1464,7 +1631,7 @@ func (x *VersionResp) String() string {
 func (*VersionResp) ProtoMessage() {}
 
 func (x *VersionResp) ProtoReflect() protoreflect.Message {
-	mi := &file_api_v2_api_proto_msgTypes[28]
+	mi := &file_api_v2_api_proto_msgTypes[31]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1477,7 +1644,7 @@ func (x *VersionResp) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use VersionResp.ProtoReflect.Descriptor instead.
 func (*VersionResp) Descriptor() ([]byte, []int) {
-	return file_api_v2_api_proto_rawDescGZIP(), []int{28}
+	return file_api_v2_api_proto_rawDescGZIP(), []int{31}
 }
 
 func (x *VersionResp) GetServer() string {
@@ -1503,7 +1670,7 @@ type DiscoveryReq struct {
 
 func (x *DiscoveryReq) Reset() {
 	*x = DiscoveryReq{}
-	mi := &file_api_v2_api_proto_msgTypes[29]
+	mi := &file_api_v2_api_proto_msgTypes[32]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -1515,7 +1682,7 @@ func (x *DiscoveryReq) String() string {
 func (*DiscoveryReq) ProtoMessage() {}
 
 func (x *DiscoveryReq) ProtoReflect() protoreflect.Message {
-	mi := &file_api_v2_api_proto_msgTypes[29]
+	mi := &file_api_v2_api_proto_msgTypes[32]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1528,7 +1695,7 @@ func (x *DiscoveryReq) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use DiscoveryReq.ProtoReflect.Descriptor instead.
 func (*DiscoveryReq) Descriptor() ([]byte, []int) {
-	return file_api_v2_api_proto_rawDescGZIP(), []int{29}
+	return file_api_v2_api_proto_rawDescGZIP(), []int{32}
 }
 
 // DiscoverResp holds the version oidc disovery info.
@@ -1555,7 +1722,7 @@ type DiscoveryResp struct {
 
 func (x *DiscoveryResp) Reset() {
 	*x = DiscoveryResp{}
-	mi := &file_api_v2_api_proto_msgTypes[30]
+	mi := &file_api_v2_api_proto_msgTypes[33]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -1567,7 +1734,7 @@ func (x *DiscoveryResp) String() string {
 func (*DiscoveryResp) ProtoMessage() {}
 
 func (x *DiscoveryResp) ProtoReflect() protoreflect.Message {
-	mi := &file_api_v2_api_proto_msgTypes[30]
+	mi := &file_api_v2_api_proto_msgTypes[33]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1580,7 +1747,7 @@ func (x *DiscoveryResp) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use DiscoveryResp.ProtoReflect.Descriptor instead.
 func (*DiscoveryResp) Descriptor() ([]byte, []int) {
-	return file_api_v2_api_proto_rawDescGZIP(), []int{30}
+	return file_api_v2_api_proto_rawDescGZIP(), []int{33}
 }
 
 func (x *DiscoveryResp) GetIssuer() string {
@@ -1702,7 +1869,7 @@ type RefreshTokenRef struct {
 
 func (x *RefreshTokenRef) Reset() {
 	*x = RefreshTokenRef{}
-	mi := &file_api_v2_api_proto_msgTypes[31]
+	mi := &file_api_v2_api_proto_msgTypes[34]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -1714,7 +1881,7 @@ func (x *RefreshTokenRef) String() string {
 func (*RefreshTokenRef) ProtoMessage() {}
 
 func (x *RefreshTokenRef) ProtoReflect() protoreflect.Message {
-	mi := &file_api_v2_api_proto_msgTypes[31]
+	mi := &file_api_v2_api_proto_msgTypes[34]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1727,7 +1894,7 @@ func (x *RefreshTokenRef) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use RefreshTokenRef.ProtoReflect.Descriptor instead.
 func (*RefreshTokenRef) Descriptor() ([]byte, []int) {
-	return file_api_v2_api_proto_rawDescGZIP(), []int{31}
+	return file_api_v2_api_proto_rawDescGZIP(), []int{34}
 }
 
 func (x *RefreshTokenRef) GetId() string {
@@ -1769,7 +1936,7 @@ type ListRefreshReq struct {
 
 func (x *ListRefreshReq) Reset() {
 	*x = ListRefreshReq{}
-	mi := &file_api_v2_api_proto_msgTypes[32]
+	mi := &file_api_v2_api_proto_msgTypes[35]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -1781,7 +1948,7 @@ func (x *ListRefreshReq) String() string {
 func (*ListRefreshReq) ProtoMessage() {}
 
 func (x *ListRefreshReq) ProtoReflect() protoreflect.Message {
-	mi := &file_api_v2_api_proto_msgTypes[32]
+	mi := &file_api_v2_api_proto_msgTypes[35]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1794,7 +1961,7 @@ func (x *ListRefreshReq) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use ListRefreshReq.ProtoReflect.Descriptor instead.
 func (*ListRefreshReq) Descriptor() ([]byte, []int) {
-	return file_api_v2_api_proto_rawDescGZIP(), []int{32}
+	return file_api_v2_api_proto_rawDescGZIP(), []int{35}
 }
 
 func (x *ListRefreshReq) GetUserId() string {
@@ -1814,7 +1981,7 @@ type ListRefreshResp struct {
 
 func (x *ListRefreshResp) Reset() {
 	*x = ListRefreshResp{}
-	mi := &file_api_v2_api_proto_msgTypes[33]
+	mi := &file_api_v2_api_proto_msgTypes[36]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -1826,7 +1993,7 @@ func (x *ListRefreshResp) String() string {
 func (*ListRefreshResp) ProtoMessage() {}
 
 func (x *ListRefreshResp) ProtoReflect() protoreflect.Message {
-	mi := &file_api_v2_api_proto_msgTypes[33]
+	mi := &file_api_v2_api_proto_msgTypes[36]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1839,7 +2006,7 @@ func (x *ListRefreshResp) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use ListRefreshResp.ProtoReflect.Descriptor instead.
 func (*ListRefreshResp) Descriptor() ([]byte, []int) {
-	return file_api_v2_api_proto_rawDescGZIP(), []int{33}
+	return file_api_v2_api_proto_rawDescGZIP(), []int{36}
 }
 
 func (x *ListRefreshResp) GetRefreshTokens() []*RefreshTokenRef {
@@ -1861,7 +2028,7 @@ type RevokeRefreshReq struct {
 
 func (x *RevokeRefreshReq) Reset() {
 	*x = RevokeRefreshReq{}
-	mi := &file_api_v2_api_proto_msgTypes[34]
+	mi := &file_api_v2_api_proto_msgTypes[37]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -1873,7 +2040,7 @@ func (x *RevokeRefreshReq) String() string {
 func (*RevokeRefreshReq) ProtoMessage() {}
 
 func (x *RevokeRefreshReq) ProtoReflect() protoreflect.Message {
-	mi := &file_api_v2_api_proto_msgTypes[34]
+	mi := &file_api_v2_api_proto_msgTypes[37]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1886,7 +2053,7 @@ func (x *RevokeRefreshReq) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use RevokeRefreshReq.ProtoReflect.Descriptor instead.
 func (*RevokeRefreshReq) Descriptor() ([]byte, []int) {
-	return file_api_v2_api_proto_rawDescGZIP(), []int{34}
+	return file_api_v2_api_proto_rawDescGZIP(), []int{37}
 }
 
 func (x *RevokeRefreshReq) GetUserId() string {
@@ -1914,7 +2081,7 @@ type RevokeRefreshResp struct {
 
 func (x *RevokeRefreshResp) Reset() {
 	*x = RevokeRefreshResp{}
-	mi := &file_api_v2_api_proto_msgTypes[35]
+	mi := &file_api_v2_api_proto_msgTypes[38]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -1926,7 +2093,7 @@ func (x *RevokeRefreshResp) String() string {
 func (*RevokeRefreshResp) ProtoMessage() {}
 
 func (x *RevokeRefreshResp) ProtoReflect() protoreflect.Message {
-	mi := &file_api_v2_api_proto_msgTypes[35]
+	mi := &file_api_v2_api_proto_msgTypes[38]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1939,7 +2106,7 @@ func (x *RevokeRefreshResp) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use RevokeRefreshResp.ProtoReflect.Descriptor instead.
 func (*RevokeRefreshResp) Descriptor() ([]byte, []int) {
-	return file_api_v2_api_proto_rawDescGZIP(), []int{35}
+	return file_api_v2_api_proto_rawDescGZIP(), []int{38}
 }
 
 func (x *RevokeRefreshResp) GetNotFound() bool {
@@ -1959,7 +2126,7 @@ type VerifyPasswordReq struct {
 
 func (x *VerifyPasswordReq) Reset() {
 	*x = VerifyPasswordReq{}
-	mi := &file_api_v2_api_proto_msgTypes[36]
+	mi := &file_api_v2_api_proto_msgTypes[39]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -1971,7 +2138,7 @@ func (x *VerifyPasswordReq) String() string {
 func (*VerifyPasswordReq) ProtoMessage() {}
 
 func (x *VerifyPasswordReq) ProtoReflect() protoreflect.Message {
-	mi := &file_api_v2_api_proto_msgTypes[36]
+	mi := &file_api_v2_api_proto_msgTypes[39]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1984,7 +2151,7 @@ func (x *VerifyPasswordReq) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use VerifyPasswordReq.ProtoReflect.Descriptor instead.
 func (*VerifyPasswordReq) Descriptor() ([]byte, []int) {
-	return file_api_v2_api_proto_rawDescGZIP(), []int{36}
+	return file_api_v2_api_proto_rawDescGZIP(), []int{39}
 }
 
 func (x *VerifyPasswordReq) GetEmail() string {
@@ -2011,7 +2178,7 @@ type VerifyPasswordResp struct {
 
 func (x *VerifyPasswordResp) Reset() {
 	*x = VerifyPasswordResp{}
-	mi := &file_api_v2_api_proto_msgTypes[37]
+	mi := &file_api_v2_api_proto_msgTypes[40]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -2023,7 +2190,7 @@ func (x *VerifyPasswordResp) String() string {
 func (*VerifyPasswordResp) ProtoMessage() {}
 
 func (x *VerifyPasswordResp) ProtoReflect() protoreflect.Message {
-	mi := &file_api_v2_api_proto_msgTypes[37]
+	mi := &file_api_v2_api_proto_msgTypes[40]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -2036,7 +2203,7 @@ func (x *VerifyPasswordResp) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use VerifyPasswordResp.ProtoReflect.Descriptor instead.
 func (*VerifyPasswordResp) Descriptor() ([]byte, []int) {
-	return file_api_v2_api_proto_rawDescGZIP(), []int{37}
+	return file_api_v2_api_proto_rawDescGZIP(), []int{40}
 }
 
 func (x *VerifyPasswordResp) GetVerified() bool {
@@ -2069,6 +2236,17 @@ var file_api_v2_api_proto_rawDesc = string([]byte{
 	0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x12, 0x12, 0x0a, 0x04,
 	0x6e, 0x61, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65,
 	0x12, 0x19, 0x0a, 0x08, 0x6c, 0x6f, 0x67, 0x6f, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x07, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x07, 0x6c, 0x6f, 0x67, 0x6f, 0x55, 0x72, 0x6c, 0x22, 0xad, 0x01, 0x0a, 0x0a,
+	0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64,
+	0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x72, 0x65,
+	0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x5f, 0x75, 0x72, 0x69, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28,
+	0x09, 0x52, 0x0c, 0x72, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x55, 0x72, 0x69, 0x73, 0x12,
+	0x23, 0x0a, 0x0d, 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x70, 0x65, 0x65, 0x72, 0x73,
+	0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x50,
+	0x65, 0x65, 0x72, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x18, 0x04,
+	0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x12, 0x12, 0x0a, 0x04,
+	0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65,
+	0x12, 0x19, 0x0a, 0x08, 0x6c, 0x6f, 0x67, 0x6f, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x06, 0x20, 0x01,
 	0x28, 0x09, 0x52, 0x07, 0x6c, 0x6f, 0x67, 0x6f, 0x55, 0x72, 0x6c, 0x22, 0x1e, 0x0a, 0x0c, 0x47,
 	0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x12, 0x0e, 0x0a, 0x02, 0x69,
 	0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x34, 0x0a, 0x0d, 0x47,
@@ -2102,241 +2280,250 @@ var file_api_v2_api_proto_rawDesc = string([]byte{
 	0x09, 0x52, 0x07, 0x6c, 0x6f, 0x67, 0x6f, 0x55, 0x72, 0x6c, 0x22, 0x2f, 0x0a, 0x10, 0x55, 0x70,
 	0x64, 0x61, 0x74, 0x65, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x1b,
 	0x0a, 0x09, 0x6e, 0x6f, 0x74, 0x5f, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
-	0x08, 0x52, 0x08, 0x6e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x22, 0x69, 0x0a, 0x08, 0x50,
-	0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c,
-	0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x12, 0x0a,
-	0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x68, 0x61, 0x73,
-	0x68, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20,
-	0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x17, 0x0a,
-	0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06,
-	0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x22, 0x3e, 0x0a, 0x11, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65,
-	0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x12, 0x29, 0x0a, 0x08, 0x70,
-	0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e,
-	0x61, 0x70, 0x69, 0x2e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x08, 0x70, 0x61,
-	0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x3b, 0x0a, 0x12, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65,
-	0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x12, 0x25, 0x0a, 0x0e,
-	0x61, 0x6c, 0x72, 0x65, 0x61, 0x64, 0x79, 0x5f, 0x65, 0x78, 0x69, 0x73, 0x74, 0x73, 0x18, 0x01,
-	0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x61, 0x6c, 0x72, 0x65, 0x61, 0x64, 0x79, 0x45, 0x78, 0x69,
-	0x73, 0x74, 0x73, 0x22, 0x67, 0x0a, 0x11, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x61, 0x73,
-	0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69,
-	0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x19,
-	0x0a, 0x08, 0x6e, 0x65, 0x77, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c,
-	0x52, 0x07, 0x6e, 0x65, 0x77, 0x48, 0x61, 0x73, 0x68, 0x12, 0x21, 0x0a, 0x0c, 0x6e, 0x65, 0x77,
-	0x5f, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
-	0x0b, 0x6e, 0x65, 0x77, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x31, 0x0a, 0x12,
-	0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65,
-	0x73, 0x70, 0x12, 0x1b, 0x0a, 0x09, 0x6e, 0x6f, 0x74, 0x5f, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x18,
-	0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x6e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x22,
-	0x29, 0x0a, 0x11, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72,
-	0x64, 0x52, 0x65, 0x71, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x01, 0x20,
-	0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x22, 0x31, 0x0a, 0x12, 0x44, 0x65,
-	0x6c, 0x65, 0x74, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70,
+	0x08, 0x52, 0x08, 0x6e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x22, 0x0f, 0x0a, 0x0d, 0x4c,
+	0x69, 0x73, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x22, 0x3b, 0x0a, 0x0e,
+	0x4c, 0x69, 0x73, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x29,
+	0x0a, 0x07, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32,
+	0x0f, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f,
+	0x52, 0x07, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x69, 0x0a, 0x08, 0x50, 0x61, 0x73,
+	0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x68,
+	0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12,
+	0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x75,
+	0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73,
+	0x65, 0x72, 0x49, 0x64, 0x22, 0x3e, 0x0a, 0x11, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x61,
+	0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x12, 0x29, 0x0a, 0x08, 0x70, 0x61, 0x73,
+	0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x61, 0x70,
+	0x69, 0x2e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73,
+	0x77, 0x6f, 0x72, 0x64, 0x22, 0x3b, 0x0a, 0x12, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x61,
+	0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x6c,
+	0x72, 0x65, 0x61, 0x64, 0x79, 0x5f, 0x65, 0x78, 0x69, 0x73, 0x74, 0x73, 0x18, 0x01, 0x20, 0x01,
+	0x28, 0x08, 0x52, 0x0d, 0x61, 0x6c, 0x72, 0x65, 0x61, 0x64, 0x79, 0x45, 0x78, 0x69, 0x73, 0x74,
+	0x73, 0x22, 0x67, 0x0a, 0x11, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77,
+	0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18,
+	0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x19, 0x0a, 0x08,
+	0x6e, 0x65, 0x77, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07,
+	0x6e, 0x65, 0x77, 0x48, 0x61, 0x73, 0x68, 0x12, 0x21, 0x0a, 0x0c, 0x6e, 0x65, 0x77, 0x5f, 0x75,
+	0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6e,
+	0x65, 0x77, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x31, 0x0a, 0x12, 0x55, 0x70,
+	0x64, 0x61, 0x74, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70,
+	0x12, 0x1b, 0x0a, 0x09, 0x6e, 0x6f, 0x74, 0x5f, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x01, 0x20,
+	0x01, 0x28, 0x08, 0x52, 0x08, 0x6e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x22, 0x29, 0x0a,
+	0x11, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52,
+	0x65, 0x71, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x22, 0x31, 0x0a, 0x12, 0x44, 0x65, 0x6c, 0x65,
+	0x74, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x12, 0x1b,
+	0x0a, 0x09, 0x6e, 0x6f, 0x74, 0x5f, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
+	0x08, 0x52, 0x08, 0x6e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x22, 0x11, 0x0a, 0x0f, 0x4c,
+	0x69, 0x73, 0x74, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x22, 0x3f,
+	0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65,
+	0x73, 0x70, 0x12, 0x2b, 0x0a, 0x09, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x73, 0x18,
+	0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x50, 0x61, 0x73, 0x73,
+	0x77, 0x6f, 0x72, 0x64, 0x52, 0x09, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x73, 0x22,
+	0x5b, 0x0a, 0x09, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x0e, 0x0a, 0x02,
+	0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04,
+	0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65,
+	0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
+	0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x04,
+	0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x42, 0x0a, 0x12,
+	0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x52,
+	0x65, 0x71, 0x12, 0x2c, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18,
+	0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x6f, 0x6e, 0x6e,
+	0x65, 0x63, 0x74, 0x6f, 0x72, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72,
+	0x22, 0x3c, 0x0a, 0x13, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63,
+	0x74, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x6c, 0x72, 0x65, 0x61,
+	0x64, 0x79, 0x5f, 0x65, 0x78, 0x69, 0x73, 0x74, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52,
+	0x0d, 0x61, 0x6c, 0x72, 0x65, 0x61, 0x64, 0x79, 0x45, 0x78, 0x69, 0x73, 0x74, 0x73, 0x22, 0x79,
+	0x0a, 0x12, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f,
+	0x72, 0x52, 0x65, 0x71, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x02, 0x69, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x6e, 0x65, 0x77, 0x5f, 0x74, 0x79, 0x70, 0x65,
+	0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, 0x77, 0x54, 0x79, 0x70, 0x65, 0x12,
+	0x19, 0x0a, 0x08, 0x6e, 0x65, 0x77, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x07, 0x6e, 0x65, 0x77, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x6e, 0x65,
+	0x77, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09,
+	0x6e, 0x65, 0x77, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x32, 0x0a, 0x13, 0x55, 0x70, 0x64,
+	0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70,
+	0x12, 0x1b, 0x0a, 0x09, 0x6e, 0x6f, 0x74, 0x5f, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x01, 0x20,
+	0x01, 0x28, 0x08, 0x52, 0x08, 0x6e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x22, 0x24, 0x0a,
+	0x12, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72,
+	0x52, 0x65, 0x71, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
+	0x02, 0x69, 0x64, 0x22, 0x32, 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x43, 0x6f, 0x6e,
+	0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, 0x12, 0x1b, 0x0a, 0x09, 0x6e, 0x6f,
+	0x74, 0x5f, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x6e,
+	0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x22, 0x12, 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74, 0x43,
+	0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x22, 0x43, 0x0a, 0x11, 0x4c,
+	0x69, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70,
+	0x12, 0x2e, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x01,
+	0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65,
+	0x63, 0x74, 0x6f, 0x72, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73,
+	0x22, 0x0c, 0x0a, 0x0a, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x22, 0x37,
+	0x0a, 0x0b, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x16, 0x0a,
+	0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73,
+	0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x70, 0x69, 0x18, 0x02, 0x20, 0x01,
+	0x28, 0x05, 0x52, 0x03, 0x61, 0x70, 0x69, 0x22, 0x0e, 0x0a, 0x0c, 0x44, 0x69, 0x73, 0x63, 0x6f,
+	0x76, 0x65, 0x72, 0x79, 0x52, 0x65, 0x71, 0x22, 0xb0, 0x06, 0x0a, 0x0d, 0x44, 0x69, 0x73, 0x63,
+	0x6f, 0x76, 0x65, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x69, 0x73, 0x73,
+	0x75, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x69, 0x73, 0x73, 0x75, 0x65,
+	0x72, 0x12, 0x35, 0x0a, 0x16, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69,
+	0x6f, 0x6e, 0x5f, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x15, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+	0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x74, 0x6f, 0x6b, 0x65,
+	0x6e, 0x5f, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x0d, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12,
+	0x19, 0x0a, 0x08, 0x6a, 0x77, 0x6b, 0x73, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x04, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x07, 0x6a, 0x77, 0x6b, 0x73, 0x55, 0x72, 0x69, 0x12, 0x2b, 0x0a, 0x11, 0x75, 0x73,
+	0x65, 0x72, 0x69, 0x6e, 0x66, 0x6f, 0x5f, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18,
+	0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x75, 0x73, 0x65, 0x72, 0x69, 0x6e, 0x66, 0x6f, 0x45,
+	0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x42, 0x0a, 0x1d, 0x64, 0x65, 0x76, 0x69, 0x63,
+	0x65, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f,
+	0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x1b,
+	0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74,
+	0x69, 0x6f, 0x6e, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x35, 0x0a, 0x16, 0x69,
+	0x6e, 0x74, 0x72, 0x6f, 0x73, 0x70, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x65, 0x6e, 0x64,
+	0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x15, 0x69, 0x6e, 0x74,
+	0x72, 0x6f, 0x73, 0x70, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69,
+	0x6e, 0x74, 0x12, 0x32, 0x0a, 0x15, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65,
+	0x73, 0x5f, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x08, 0x20, 0x03, 0x28,
+	0x09, 0x52, 0x13, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x73, 0x53, 0x75, 0x70,
+	0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x38, 0x0a, 0x18, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e,
+	0x73, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x5f, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74,
+	0x65, 0x64, 0x18, 0x09, 0x20, 0x03, 0x28, 0x09, 0x52, 0x16, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e,
+	0x73, 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64,
+	0x12, 0x36, 0x0a, 0x17, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65,
+	0x73, 0x5f, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x0a, 0x20, 0x03, 0x28,
+	0x09, 0x52, 0x15, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x73, 0x53,
+	0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x4f, 0x0a, 0x25, 0x69, 0x64, 0x5f, 0x74,
+	0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x61, 0x6c, 0x67,
+	0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x5f, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65,
+	0x64, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x09, 0x52, 0x20, 0x69, 0x64, 0x54, 0x6f, 0x6b, 0x65, 0x6e,
+	0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x41, 0x6c, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73,
+	0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x47, 0x0a, 0x20, 0x63, 0x6f, 0x64,
+	0x65, 0x5f, 0x63, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x68,
+	0x6f, 0x64, 0x73, 0x5f, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x0c, 0x20,
+	0x03, 0x28, 0x09, 0x52, 0x1d, 0x63, 0x6f, 0x64, 0x65, 0x43, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e,
+	0x67, 0x65, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74,
+	0x65, 0x64, 0x12, 0x29, 0x0a, 0x10, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x5f, 0x73, 0x75, 0x70,
+	0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x63,
+	0x6f, 0x70, 0x65, 0x73, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x50, 0x0a,
+	0x25, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x5f,
+	0x61, 0x75, 0x74, 0x68, 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x5f, 0x73, 0x75, 0x70,
+	0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x0e, 0x20, 0x03, 0x28, 0x09, 0x52, 0x21, 0x74, 0x6f,
+	0x6b, 0x65, 0x6e, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x41, 0x75, 0x74, 0x68, 0x4d,
+	0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12,
+	0x29, 0x0a, 0x10, 0x63, 0x6c, 0x61, 0x69, 0x6d, 0x73, 0x5f, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72,
+	0x74, 0x65, 0x64, 0x18, 0x0f, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x63, 0x6c, 0x61, 0x69, 0x6d,
+	0x73, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x22, 0x7a, 0x0a, 0x0f, 0x52, 0x65,
+	0x66, 0x72, 0x65, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x66, 0x12, 0x0e, 0x0a,
+	0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1b, 0x0a,
+	0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x72,
+	0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09,
+	0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x6c, 0x61, 0x73,
+	0x74, 0x5f, 0x75, 0x73, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x6c, 0x61,
+	0x73, 0x74, 0x55, 0x73, 0x65, 0x64, 0x22, 0x29, 0x0a, 0x0e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65,
+	0x66, 0x72, 0x65, 0x73, 0x68, 0x52, 0x65, 0x71, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72,
+	0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49,
+	0x64, 0x22, 0x4e, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68,
+	0x52, 0x65, 0x73, 0x70, 0x12, 0x3b, 0x0a, 0x0e, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x5f,
+	0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x61,
+	0x70, 0x69, 0x2e, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52,
+	0x65, 0x66, 0x52, 0x0d, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e,
+	0x73, 0x22, 0x48, 0x0a, 0x10, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x52, 0x65, 0x66, 0x72, 0x65,
+	0x73, 0x68, 0x52, 0x65, 0x71, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64,
+	0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1b,
+	0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x22, 0x30, 0x0a, 0x11, 0x52,
+	0x65, 0x76, 0x6f, 0x6b, 0x65, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70,
 	0x12, 0x1b, 0x0a, 0x09, 0x6e, 0x6f, 0x74, 0x5f, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x01, 0x20,
-	0x01, 0x28, 0x08, 0x52, 0x08, 0x6e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x22, 0x11, 0x0a,
-	0x0f, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71,
-	0x22, 0x3f, 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64,
-	0x52, 0x65, 0x73, 0x70, 0x12, 0x2b, 0x0a, 0x09, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64,
-	0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x50, 0x61,
-	0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x09, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64,
-	0x73, 0x22, 0x5b, 0x0a, 0x09, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x0e,
-	0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12,
-	0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79,
-	0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
-	0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,
-	0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x42,
-	0x0a, 0x12, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f,
-	0x72, 0x52, 0x65, 0x71, 0x12, 0x2c, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f,
-	0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x6f,
-	0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74,
-	0x6f, 0x72, 0x22, 0x3c, 0x0a, 0x13, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e,
-	0x65, 0x63, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x6c, 0x72,
-	0x65, 0x61, 0x64, 0x79, 0x5f, 0x65, 0x78, 0x69, 0x73, 0x74, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28,
-	0x08, 0x52, 0x0d, 0x61, 0x6c, 0x72, 0x65, 0x61, 0x64, 0x79, 0x45, 0x78, 0x69, 0x73, 0x74, 0x73,
-	0x22, 0x79, 0x0a, 0x12, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63,
-	0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01,
-	0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x6e, 0x65, 0x77, 0x5f, 0x74, 0x79,
-	0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, 0x77, 0x54, 0x79, 0x70,
-	0x65, 0x12, 0x19, 0x0a, 0x08, 0x6e, 0x65, 0x77, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20,
-	0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, 0x77, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a,
-	0x6e, 0x65, 0x77, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c,
-	0x52, 0x09, 0x6e, 0x65, 0x77, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x32, 0x0a, 0x13, 0x55,
-	0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x52, 0x65,
-	0x73, 0x70, 0x12, 0x1b, 0x0a, 0x09, 0x6e, 0x6f, 0x74, 0x5f, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x18,
-	0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x6e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x22,
-	0x24, 0x0a, 0x12, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74,
-	0x6f, 0x72, 0x52, 0x65, 0x71, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
-	0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x32, 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x43,
-	0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, 0x12, 0x1b, 0x0a, 0x09,
-	0x6e, 0x6f, 0x74, 0x5f, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52,
-	0x08, 0x6e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x22, 0x12, 0x0a, 0x10, 0x4c, 0x69, 0x73,
-	0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x22, 0x43, 0x0a,
-	0x11, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x52, 0x65,
-	0x73, 0x70, 0x12, 0x2e, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73,
-	0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x6f, 0x6e,
-	0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f,
-	0x72, 0x73, 0x22, 0x0c, 0x0a, 0x0a, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71,
-	0x22, 0x37, 0x0a, 0x0b, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12,
-	0x16, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
-	0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x70, 0x69, 0x18, 0x02,
-	0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x61, 0x70, 0x69, 0x22, 0x0e, 0x0a, 0x0c, 0x44, 0x69, 0x73,
-	0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x52, 0x65, 0x71, 0x22, 0xb0, 0x06, 0x0a, 0x0d, 0x44, 0x69,
-	0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x69,
-	0x73, 0x73, 0x75, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x69, 0x73, 0x73,
-	0x75, 0x65, 0x72, 0x12, 0x35, 0x0a, 0x16, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61,
-	0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x02, 0x20,
-	0x01, 0x28, 0x09, 0x52, 0x15, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69,
-	0x6f, 0x6e, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x74, 0x6f,
-	0x6b, 0x65, 0x6e, 0x5f, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01,
-	0x28, 0x09, 0x52, 0x0d, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e,
-	0x74, 0x12, 0x19, 0x0a, 0x08, 0x6a, 0x77, 0x6b, 0x73, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x04, 0x20,
-	0x01, 0x28, 0x09, 0x52, 0x07, 0x6a, 0x77, 0x6b, 0x73, 0x55, 0x72, 0x69, 0x12, 0x2b, 0x0a, 0x11,
-	0x75, 0x73, 0x65, 0x72, 0x69, 0x6e, 0x66, 0x6f, 0x5f, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e,
-	0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x75, 0x73, 0x65, 0x72, 0x69, 0x6e, 0x66,
-	0x6f, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x42, 0x0a, 0x1d, 0x64, 0x65, 0x76,
-	0x69, 0x63, 0x65, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f,
-	0x6e, 0x5f, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09,
-	0x52, 0x1b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a,
-	0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x35, 0x0a,
-	0x16, 0x69, 0x6e, 0x74, 0x72, 0x6f, 0x73, 0x70, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x65,
-	0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x15, 0x69,
-	0x6e, 0x74, 0x72, 0x6f, 0x73, 0x70, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x6e, 0x64, 0x70,
-	0x6f, 0x69, 0x6e, 0x74, 0x12, 0x32, 0x0a, 0x15, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x5f, 0x74, 0x79,
-	0x70, 0x65, 0x73, 0x5f, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x08, 0x20,
-	0x03, 0x28, 0x09, 0x52, 0x13, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x73, 0x53,
-	0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x38, 0x0a, 0x18, 0x72, 0x65, 0x73, 0x70,
-	0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x5f, 0x73, 0x75, 0x70, 0x70, 0x6f,
-	0x72, 0x74, 0x65, 0x64, 0x18, 0x09, 0x20, 0x03, 0x28, 0x09, 0x52, 0x16, 0x72, 0x65, 0x73, 0x70,
-	0x6f, 0x6e, 0x73, 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74,
-	0x65, 0x64, 0x12, 0x36, 0x0a, 0x17, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x74, 0x79,
-	0x70, 0x65, 0x73, 0x5f, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x0a, 0x20,
-	0x03, 0x28, 0x09, 0x52, 0x15, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65,
-	0x73, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x4f, 0x0a, 0x25, 0x69, 0x64,
-	0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x61,
-	0x6c, 0x67, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x5f, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72,
-	0x74, 0x65, 0x64, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x09, 0x52, 0x20, 0x69, 0x64, 0x54, 0x6f, 0x6b,
-	0x65, 0x6e, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x41, 0x6c, 0x67, 0x56, 0x61, 0x6c, 0x75,
-	0x65, 0x73, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x47, 0x0a, 0x20, 0x63,
-	0x6f, 0x64, 0x65, 0x5f, 0x63, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x5f, 0x6d, 0x65,
-	0x74, 0x68, 0x6f, 0x64, 0x73, 0x5f, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18,
-	0x0c, 0x20, 0x03, 0x28, 0x09, 0x52, 0x1d, 0x63, 0x6f, 0x64, 0x65, 0x43, 0x68, 0x61, 0x6c, 0x6c,
-	0x65, 0x6e, 0x67, 0x65, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x53, 0x75, 0x70, 0x70, 0x6f,
-	0x72, 0x74, 0x65, 0x64, 0x12, 0x29, 0x0a, 0x10, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x5f, 0x73,
-	0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f,
-	0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12,
-	0x50, 0x0a, 0x25, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e,
-	0x74, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x5f, 0x73,
-	0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x0e, 0x20, 0x03, 0x28, 0x09, 0x52, 0x21,
-	0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x41, 0x75, 0x74,
-	0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65,
-	0x64, 0x12, 0x29, 0x0a, 0x10, 0x63, 0x6c, 0x61, 0x69, 0x6d, 0x73, 0x5f, 0x73, 0x75, 0x70, 0x70,
-	0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x0f, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x63, 0x6c, 0x61,
-	0x69, 0x6d, 0x73, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x22, 0x7a, 0x0a, 0x0f,
-	0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x66, 0x12,
-	0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12,
-	0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01,
-	0x28, 0x09, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a,
-	0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03,
-	0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x6c,
-	0x61, 0x73, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08,
-	0x6c, 0x61, 0x73, 0x74, 0x55, 0x73, 0x65, 0x64, 0x22, 0x29, 0x0a, 0x0e, 0x4c, 0x69, 0x73, 0x74,
-	0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x52, 0x65, 0x71, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73,
-	0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65,
-	0x72, 0x49, 0x64, 0x22, 0x4e, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x66, 0x72, 0x65,
-	0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x12, 0x3b, 0x0a, 0x0e, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73,
-	0x68, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14,
-	0x2e, 0x61, 0x70, 0x69, 0x2e, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65,
-	0x6e, 0x52, 0x65, 0x66, 0x52, 0x0d, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x54, 0x6f, 0x6b,
-	0x65, 0x6e, 0x73, 0x22, 0x48, 0x0a, 0x10, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x52, 0x65, 0x66,
-	0x72, 0x65, 0x73, 0x68, 0x52, 0x65, 0x71, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f,
-	0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64,
-	0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20,
-	0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x22, 0x30, 0x0a,
-	0x11, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x52, 0x65,
-	0x73, 0x70, 0x12, 0x1b, 0x0a, 0x09, 0x6e, 0x6f, 0x74, 0x5f, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x18,
-	0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x6e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x22,
-	0x45, 0x0a, 0x11, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72,
-	0x64, 0x52, 0x65, 0x71, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x01, 0x20,
-	0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61,
-	0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61,
-	0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x4d, 0x0a, 0x12, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79,
-	0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x12, 0x1a, 0x0a, 0x08,
-	0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08,
-	0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x6e, 0x6f, 0x74, 0x5f,
-	0x66, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x6e, 0x6f, 0x74,
-	0x46, 0x6f, 0x75, 0x6e, 0x64, 0x32, 0xd1, 0x08, 0x0a, 0x03, 0x44, 0x65, 0x78, 0x12, 0x34, 0x0a,
-	0x09, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x11, 0x2e, 0x61, 0x70, 0x69,
-	0x2e, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x12, 0x2e,
-	0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73,
-	0x70, 0x22, 0x00, 0x12, 0x3d, 0x0a, 0x0c, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6c, 0x69,
-	0x65, 0x6e, 0x74, 0x12, 0x14, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65,
-	0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x15, 0x2e, 0x61, 0x70, 0x69, 0x2e,
-	0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70,
-	0x22, 0x00, 0x12, 0x3d, 0x0a, 0x0c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x6c, 0x69, 0x65,
-	0x6e, 0x74, 0x12, 0x14, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43,
-	0x6c, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x15, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x55,
-	0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x22,
-	0x00, 0x12, 0x3d, 0x0a, 0x0c, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x43, 0x6c, 0x69, 0x65, 0x6e,
-	0x74, 0x12, 0x14, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x43, 0x6c,
-	0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x15, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x65,
-	0x6c, 0x65, 0x74, 0x65, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00,
-	0x12, 0x43, 0x0a, 0x0e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f,
-	0x72, 0x64, 0x12, 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50,
-	0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x17, 0x2e, 0x61, 0x70, 0x69,
+	0x01, 0x28, 0x08, 0x52, 0x08, 0x6e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x22, 0x45, 0x0a,
+	0x11, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52,
+	0x65, 0x71, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73,
+	0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73,
+	0x77, 0x6f, 0x72, 0x64, 0x22, 0x4d, 0x0a, 0x12, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x50, 0x61,
+	0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x76, 0x65,
+	0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x76, 0x65,
+	0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x6e, 0x6f, 0x74, 0x5f, 0x66, 0x6f,
+	0x75, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x6e, 0x6f, 0x74, 0x46, 0x6f,
+	0x75, 0x6e, 0x64, 0x32, 0x8b, 0x09, 0x0a, 0x03, 0x44, 0x65, 0x78, 0x12, 0x34, 0x0a, 0x09, 0x47,
+	0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x11, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47,
+	0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x12, 0x2e, 0x61, 0x70,
+	0x69, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x22,
+	0x00, 0x12, 0x3d, 0x0a, 0x0c, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6c, 0x69, 0x65, 0x6e,
+	0x74, 0x12, 0x14, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6c,
+	0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x15, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72,
+	0x65, 0x61, 0x74, 0x65, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00,
+	0x12, 0x3d, 0x0a, 0x0c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74,
+	0x12, 0x14, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x6c, 0x69,
+	0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x15, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x55, 0x70, 0x64,
+	0x61, 0x74, 0x65, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, 0x12,
+	0x3d, 0x0a, 0x0c, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x12,
+	0x14, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x43, 0x6c, 0x69, 0x65,
+	0x6e, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x15, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x65, 0x6c, 0x65,
+	0x74, 0x65, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, 0x12, 0x38,
+	0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x12, 0x2e,
+	0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65,
+	0x71, 0x1a, 0x13, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6c, 0x69, 0x65,
+	0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, 0x12, 0x43, 0x0a, 0x0e, 0x43, 0x72, 0x65, 0x61,
+	0x74, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x16, 0x2e, 0x61, 0x70, 0x69,
 	0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52,
-	0x65, 0x73, 0x70, 0x22, 0x00, 0x12, 0x43, 0x0a, 0x0e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50,
-	0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x55, 0x70,
-	0x64, 0x61, 0x74, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x1a,
-	0x17, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x61, 0x73, 0x73,
-	0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, 0x12, 0x43, 0x0a, 0x0e, 0x44, 0x65,
-	0x6c, 0x65, 0x74, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x16, 0x2e, 0x61,
+	0x65, 0x71, 0x1a, 0x17, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50,
+	0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, 0x12, 0x43, 0x0a,
+	0x0e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12,
+	0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x61, 0x73, 0x73,
+	0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x17, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x55, 0x70,
+	0x64, 0x61, 0x74, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70,
+	0x22, 0x00, 0x12, 0x43, 0x0a, 0x0e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x61, 0x73, 0x73,
+	0x77, 0x6f, 0x72, 0x64, 0x12, 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74,
+	0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x17, 0x2e, 0x61,
 	0x70, 0x69, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72,
-	0x64, 0x52, 0x65, 0x71, 0x1a, 0x17, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74,
-	0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, 0x12,
-	0x3e, 0x0a, 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x73,
-	0x12, 0x14, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x61, 0x73, 0x73, 0x77,
-	0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x15, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73,
-	0x74, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, 0x12,
-	0x46, 0x0a, 0x0f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74,
-	0x6f, 0x72, 0x12, 0x17, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43,
-	0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x1a, 0x18, 0x2e, 0x61, 0x70,
-	0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f,
-	0x72, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, 0x12, 0x46, 0x0a, 0x0f, 0x55, 0x70, 0x64, 0x61, 0x74,
+	0x64, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, 0x12, 0x3e, 0x0a, 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x50,
+	0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x73, 0x12, 0x14, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c,
+	0x69, 0x73, 0x74, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x15,
+	0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72,
+	0x64, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, 0x12, 0x46, 0x0a, 0x0f, 0x43, 0x72, 0x65, 0x61, 0x74,
 	0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x17, 0x2e, 0x61, 0x70, 0x69,
-	0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72,
-	0x52, 0x65, 0x71, 0x1a, 0x18, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65,
+	0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72,
+	0x52, 0x65, 0x71, 0x1a, 0x18, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65,
 	0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, 0x12,
-	0x46, 0x0a, 0x0f, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74,
-	0x6f, 0x72, 0x12, 0x17, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x43,
+	0x46, 0x0a, 0x0f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74,
+	0x6f, 0x72, 0x12, 0x17, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43,
 	0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x1a, 0x18, 0x2e, 0x61, 0x70,
-	0x69, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f,
-	0x72, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, 0x12, 0x41, 0x0a, 0x0e, 0x4c, 0x69, 0x73, 0x74, 0x43,
-	0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x15, 0x2e, 0x61, 0x70, 0x69, 0x2e,
-	0x4c, 0x69, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71,
-	0x1a, 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65,
-	0x63, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, 0x12, 0x31, 0x0a, 0x0a, 0x47, 0x65,
-	0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x0f, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x56,
-	0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x10, 0x2e, 0x61, 0x70, 0x69, 0x2e,
-	0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, 0x12, 0x37, 0x0a,
-	0x0c, 0x47, 0x65, 0x74, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x12, 0x11, 0x2e,
-	0x61, 0x70, 0x69, 0x2e, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x52, 0x65, 0x71,
-	0x1a, 0x12, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79,
-	0x52, 0x65, 0x73, 0x70, 0x22, 0x00, 0x12, 0x3a, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65,
-	0x66, 0x72, 0x65, 0x73, 0x68, 0x12, 0x13, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74,
-	0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x52, 0x65, 0x71, 0x1a, 0x14, 0x2e, 0x61, 0x70, 0x69,
-	0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70,
-	0x22, 0x00, 0x12, 0x40, 0x0a, 0x0d, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x52, 0x65, 0x66, 0x72,
-	0x65, 0x73, 0x68, 0x12, 0x15, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65,
-	0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x52, 0x65, 0x71, 0x1a, 0x16, 0x2e, 0x61, 0x70, 0x69,
-	0x2e, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x52, 0x65,
-	0x73, 0x70, 0x22, 0x00, 0x12, 0x43, 0x0a, 0x0e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x50, 0x61,
-	0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x56, 0x65, 0x72,
-	0x69, 0x66, 0x79, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x17,
+	0x69, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f,
+	0x72, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, 0x12, 0x46, 0x0a, 0x0f, 0x44, 0x65, 0x6c, 0x65, 0x74,
+	0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x17, 0x2e, 0x61, 0x70, 0x69,
+	0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72,
+	0x52, 0x65, 0x71, 0x1a, 0x18, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65,
+	0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, 0x12,
+	0x41, 0x0a, 0x0e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72,
+	0x73, 0x12, 0x15, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x6e,
+	0x65, 0x63, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x1a, 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c,
+	0x69, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70,
+	0x22, 0x00, 0x12, 0x31, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
+	0x12, 0x0f, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65,
+	0x71, 0x1a, 0x10, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52,
+	0x65, 0x73, 0x70, 0x22, 0x00, 0x12, 0x37, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x44, 0x69, 0x73, 0x63,
+	0x6f, 0x76, 0x65, 0x72, 0x79, 0x12, 0x11, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x69, 0x73, 0x63,
+	0x6f, 0x76, 0x65, 0x72, 0x79, 0x52, 0x65, 0x71, 0x1a, 0x12, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44,
+	0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, 0x12, 0x3a,
+	0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x12, 0x13, 0x2e,
+	0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x52,
+	0x65, 0x71, 0x1a, 0x14, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x66,
+	0x72, 0x65, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, 0x12, 0x40, 0x0a, 0x0d, 0x52, 0x65,
+	0x76, 0x6f, 0x6b, 0x65, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x12, 0x15, 0x2e, 0x61, 0x70,
+	0x69, 0x2e, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x52,
+	0x65, 0x71, 0x1a, 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x52,
+	0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, 0x12, 0x43, 0x0a, 0x0e,
+	0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x16,
 	0x2e, 0x61, 0x70, 0x69, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x50, 0x61, 0x73, 0x73, 0x77,
-	0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, 0x42, 0x36, 0x0a, 0x12, 0x63, 0x6f, 0x6d,
-	0x2e, 0x63, 0x6f, 0x72, 0x65, 0x6f, 0x73, 0x2e, 0x64, 0x65, 0x78, 0x2e, 0x61, 0x70, 0x69, 0x5a,
-	0x20, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x64, 0x65, 0x78, 0x69,
-	0x64, 0x70, 0x2f, 0x64, 0x65, 0x78, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x32, 0x3b, 0x61, 0x70,
-	0x69, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+	0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x17, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x56, 0x65, 0x72,
+	0x69, 0x66, 0x79, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x22,
+	0x00, 0x42, 0x36, 0x0a, 0x12, 0x63, 0x6f, 0x6d, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x6f, 0x73, 0x2e,
+	0x64, 0x65, 0x78, 0x2e, 0x61, 0x70, 0x69, 0x5a, 0x20, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
+	0x63, 0x6f, 0x6d, 0x2f, 0x64, 0x65, 0x78, 0x69, 0x64, 0x70, 0x2f, 0x64, 0x65, 0x78, 0x2f, 0x61,
+	0x70, 0x69, 0x2f, 0x76, 0x32, 0x3b, 0x61, 0x70, 0x69, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+	0x33,
 })
 
 var (
@@ -2351,95 +2538,101 @@ func file_api_v2_api_proto_rawDescGZIP() []byte {
 	return file_api_v2_api_proto_rawDescData
 }
 
-var file_api_v2_api_proto_msgTypes = make([]protoimpl.MessageInfo, 38)
+var file_api_v2_api_proto_msgTypes = make([]protoimpl.MessageInfo, 41)
 var file_api_v2_api_proto_goTypes = []any{
 	(*Client)(nil),              // 0: api.Client
-	(*GetClientReq)(nil),        // 1: api.GetClientReq
-	(*GetClientResp)(nil),       // 2: api.GetClientResp
-	(*CreateClientReq)(nil),     // 3: api.CreateClientReq
-	(*CreateClientResp)(nil),    // 4: api.CreateClientResp
-	(*DeleteClientReq)(nil),     // 5: api.DeleteClientReq
-	(*DeleteClientResp)(nil),    // 6: api.DeleteClientResp
-	(*UpdateClientReq)(nil),     // 7: api.UpdateClientReq
-	(*UpdateClientResp)(nil),    // 8: api.UpdateClientResp
-	(*Password)(nil),            // 9: api.Password
-	(*CreatePasswordReq)(nil),   // 10: api.CreatePasswordReq
-	(*CreatePasswordResp)(nil),  // 11: api.CreatePasswordResp
-	(*UpdatePasswordReq)(nil),   // 12: api.UpdatePasswordReq
-	(*UpdatePasswordResp)(nil),  // 13: api.UpdatePasswordResp
-	(*DeletePasswordReq)(nil),   // 14: api.DeletePasswordReq
-	(*DeletePasswordResp)(nil),  // 15: api.DeletePasswordResp
-	(*ListPasswordReq)(nil),     // 16: api.ListPasswordReq
-	(*ListPasswordResp)(nil),    // 17: api.ListPasswordResp
-	(*Connector)(nil),           // 18: api.Connector
-	(*CreateConnectorReq)(nil),  // 19: api.CreateConnectorReq
-	(*CreateConnectorResp)(nil), // 20: api.CreateConnectorResp
-	(*UpdateConnectorReq)(nil),  // 21: api.UpdateConnectorReq
-	(*UpdateConnectorResp)(nil), // 22: api.UpdateConnectorResp
-	(*DeleteConnectorReq)(nil),  // 23: api.DeleteConnectorReq
-	(*DeleteConnectorResp)(nil), // 24: api.DeleteConnectorResp
-	(*ListConnectorReq)(nil),    // 25: api.ListConnectorReq
-	(*ListConnectorResp)(nil),   // 26: api.ListConnectorResp
-	(*VersionReq)(nil),          // 27: api.VersionReq
-	(*VersionResp)(nil),         // 28: api.VersionResp
-	(*DiscoveryReq)(nil),        // 29: api.DiscoveryReq
-	(*DiscoveryResp)(nil),       // 30: api.DiscoveryResp
-	(*RefreshTokenRef)(nil),     // 31: api.RefreshTokenRef
-	(*ListRefreshReq)(nil),      // 32: api.ListRefreshReq
-	(*ListRefreshResp)(nil),     // 33: api.ListRefreshResp
-	(*RevokeRefreshReq)(nil),    // 34: api.RevokeRefreshReq
-	(*RevokeRefreshResp)(nil),   // 35: api.RevokeRefreshResp
-	(*VerifyPasswordReq)(nil),   // 36: api.VerifyPasswordReq
-	(*VerifyPasswordResp)(nil),  // 37: api.VerifyPasswordResp
+	(*ClientInfo)(nil),          // 1: api.ClientInfo
+	(*GetClientReq)(nil),        // 2: api.GetClientReq
+	(*GetClientResp)(nil),       // 3: api.GetClientResp
+	(*CreateClientReq)(nil),     // 4: api.CreateClientReq
+	(*CreateClientResp)(nil),    // 5: api.CreateClientResp
+	(*DeleteClientReq)(nil),     // 6: api.DeleteClientReq
+	(*DeleteClientResp)(nil),    // 7: api.DeleteClientResp
+	(*UpdateClientReq)(nil),     // 8: api.UpdateClientReq
+	(*UpdateClientResp)(nil),    // 9: api.UpdateClientResp
+	(*ListClientReq)(nil),       // 10: api.ListClientReq
+	(*ListClientResp)(nil),      // 11: api.ListClientResp
+	(*Password)(nil),            // 12: api.Password
+	(*CreatePasswordReq)(nil),   // 13: api.CreatePasswordReq
+	(*CreatePasswordResp)(nil),  // 14: api.CreatePasswordResp
+	(*UpdatePasswordReq)(nil),   // 15: api.UpdatePasswordReq
+	(*UpdatePasswordResp)(nil),  // 16: api.UpdatePasswordResp
+	(*DeletePasswordReq)(nil),   // 17: api.DeletePasswordReq
+	(*DeletePasswordResp)(nil),  // 18: api.DeletePasswordResp
+	(*ListPasswordReq)(nil),     // 19: api.ListPasswordReq
+	(*ListPasswordResp)(nil),    // 20: api.ListPasswordResp
+	(*Connector)(nil),           // 21: api.Connector
+	(*CreateConnectorReq)(nil),  // 22: api.CreateConnectorReq
+	(*CreateConnectorResp)(nil), // 23: api.CreateConnectorResp
+	(*UpdateConnectorReq)(nil),  // 24: api.UpdateConnectorReq
+	(*UpdateConnectorResp)(nil), // 25: api.UpdateConnectorResp
+	(*DeleteConnectorReq)(nil),  // 26: api.DeleteConnectorReq
+	(*DeleteConnectorResp)(nil), // 27: api.DeleteConnectorResp
+	(*ListConnectorReq)(nil),    // 28: api.ListConnectorReq
+	(*ListConnectorResp)(nil),   // 29: api.ListConnectorResp
+	(*VersionReq)(nil),          // 30: api.VersionReq
+	(*VersionResp)(nil),         // 31: api.VersionResp
+	(*DiscoveryReq)(nil),        // 32: api.DiscoveryReq
+	(*DiscoveryResp)(nil),       // 33: api.DiscoveryResp
+	(*RefreshTokenRef)(nil),     // 34: api.RefreshTokenRef
+	(*ListRefreshReq)(nil),      // 35: api.ListRefreshReq
+	(*ListRefreshResp)(nil),     // 36: api.ListRefreshResp
+	(*RevokeRefreshReq)(nil),    // 37: api.RevokeRefreshReq
+	(*RevokeRefreshResp)(nil),   // 38: api.RevokeRefreshResp
+	(*VerifyPasswordReq)(nil),   // 39: api.VerifyPasswordReq
+	(*VerifyPasswordResp)(nil),  // 40: api.VerifyPasswordResp
 }
 var file_api_v2_api_proto_depIdxs = []int32{
 	0,  // 0: api.GetClientResp.client:type_name -> api.Client
 	0,  // 1: api.CreateClientReq.client:type_name -> api.Client
 	0,  // 2: api.CreateClientResp.client:type_name -> api.Client
-	9,  // 3: api.CreatePasswordReq.password:type_name -> api.Password
-	9,  // 4: api.ListPasswordResp.passwords:type_name -> api.Password
-	18, // 5: api.CreateConnectorReq.connector:type_name -> api.Connector
-	18, // 6: api.ListConnectorResp.connectors:type_name -> api.Connector
-	31, // 7: api.ListRefreshResp.refresh_tokens:type_name -> api.RefreshTokenRef
-	1,  // 8: api.Dex.GetClient:input_type -> api.GetClientReq
-	3,  // 9: api.Dex.CreateClient:input_type -> api.CreateClientReq
-	7,  // 10: api.Dex.UpdateClient:input_type -> api.UpdateClientReq
-	5,  // 11: api.Dex.DeleteClient:input_type -> api.DeleteClientReq
-	10, // 12: api.Dex.CreatePassword:input_type -> api.CreatePasswordReq
-	12, // 13: api.Dex.UpdatePassword:input_type -> api.UpdatePasswordReq
-	14, // 14: api.Dex.DeletePassword:input_type -> api.DeletePasswordReq
-	16, // 15: api.Dex.ListPasswords:input_type -> api.ListPasswordReq
-	19, // 16: api.Dex.CreateConnector:input_type -> api.CreateConnectorReq
-	21, // 17: api.Dex.UpdateConnector:input_type -> api.UpdateConnectorReq
-	23, // 18: api.Dex.DeleteConnector:input_type -> api.DeleteConnectorReq
-	25, // 19: api.Dex.ListConnectors:input_type -> api.ListConnectorReq
-	27, // 20: api.Dex.GetVersion:input_type -> api.VersionReq
-	29, // 21: api.Dex.GetDiscovery:input_type -> api.DiscoveryReq
-	32, // 22: api.Dex.ListRefresh:input_type -> api.ListRefreshReq
-	34, // 23: api.Dex.RevokeRefresh:input_type -> api.RevokeRefreshReq
-	36, // 24: api.Dex.VerifyPassword:input_type -> api.VerifyPasswordReq
-	2,  // 25: api.Dex.GetClient:output_type -> api.GetClientResp
-	4,  // 26: api.Dex.CreateClient:output_type -> api.CreateClientResp
-	8,  // 27: api.Dex.UpdateClient:output_type -> api.UpdateClientResp
-	6,  // 28: api.Dex.DeleteClient:output_type -> api.DeleteClientResp
-	11, // 29: api.Dex.CreatePassword:output_type -> api.CreatePasswordResp
-	13, // 30: api.Dex.UpdatePassword:output_type -> api.UpdatePasswordResp
-	15, // 31: api.Dex.DeletePassword:output_type -> api.DeletePasswordResp
-	17, // 32: api.Dex.ListPasswords:output_type -> api.ListPasswordResp
-	20, // 33: api.Dex.CreateConnector:output_type -> api.CreateConnectorResp
-	22, // 34: api.Dex.UpdateConnector:output_type -> api.UpdateConnectorResp
-	24, // 35: api.Dex.DeleteConnector:output_type -> api.DeleteConnectorResp
-	26, // 36: api.Dex.ListConnectors:output_type -> api.ListConnectorResp
-	28, // 37: api.Dex.GetVersion:output_type -> api.VersionResp
-	30, // 38: api.Dex.GetDiscovery:output_type -> api.DiscoveryResp
-	33, // 39: api.Dex.ListRefresh:output_type -> api.ListRefreshResp
-	35, // 40: api.Dex.RevokeRefresh:output_type -> api.RevokeRefreshResp
-	37, // 41: api.Dex.VerifyPassword:output_type -> api.VerifyPasswordResp
-	25, // [25:42] is the sub-list for method output_type
-	8,  // [8:25] is the sub-list for method input_type
-	8,  // [8:8] is the sub-list for extension type_name
-	8,  // [8:8] is the sub-list for extension extendee
-	0,  // [0:8] is the sub-list for field type_name
+	1,  // 3: api.ListClientResp.clients:type_name -> api.ClientInfo
+	12, // 4: api.CreatePasswordReq.password:type_name -> api.Password
+	12, // 5: api.ListPasswordResp.passwords:type_name -> api.Password
+	21, // 6: api.CreateConnectorReq.connector:type_name -> api.Connector
+	21, // 7: api.ListConnectorResp.connectors:type_name -> api.Connector
+	34, // 8: api.ListRefreshResp.refresh_tokens:type_name -> api.RefreshTokenRef
+	2,  // 9: api.Dex.GetClient:input_type -> api.GetClientReq
+	4,  // 10: api.Dex.CreateClient:input_type -> api.CreateClientReq
+	8,  // 11: api.Dex.UpdateClient:input_type -> api.UpdateClientReq
+	6,  // 12: api.Dex.DeleteClient:input_type -> api.DeleteClientReq
+	10, // 13: api.Dex.ListClients:input_type -> api.ListClientReq
+	13, // 14: api.Dex.CreatePassword:input_type -> api.CreatePasswordReq
+	15, // 15: api.Dex.UpdatePassword:input_type -> api.UpdatePasswordReq
+	17, // 16: api.Dex.DeletePassword:input_type -> api.DeletePasswordReq
+	19, // 17: api.Dex.ListPasswords:input_type -> api.ListPasswordReq
+	22, // 18: api.Dex.CreateConnector:input_type -> api.CreateConnectorReq
+	24, // 19: api.Dex.UpdateConnector:input_type -> api.UpdateConnectorReq
+	26, // 20: api.Dex.DeleteConnector:input_type -> api.DeleteConnectorReq
+	28, // 21: api.Dex.ListConnectors:input_type -> api.ListConnectorReq
+	30, // 22: api.Dex.GetVersion:input_type -> api.VersionReq
+	32, // 23: api.Dex.GetDiscovery:input_type -> api.DiscoveryReq
+	35, // 24: api.Dex.ListRefresh:input_type -> api.ListRefreshReq
+	37, // 25: api.Dex.RevokeRefresh:input_type -> api.RevokeRefreshReq
+	39, // 26: api.Dex.VerifyPassword:input_type -> api.VerifyPasswordReq
+	3,  // 27: api.Dex.GetClient:output_type -> api.GetClientResp
+	5,  // 28: api.Dex.CreateClient:output_type -> api.CreateClientResp
+	9,  // 29: api.Dex.UpdateClient:output_type -> api.UpdateClientResp
+	7,  // 30: api.Dex.DeleteClient:output_type -> api.DeleteClientResp
+	11, // 31: api.Dex.ListClients:output_type -> api.ListClientResp
+	14, // 32: api.Dex.CreatePassword:output_type -> api.CreatePasswordResp
+	16, // 33: api.Dex.UpdatePassword:output_type -> api.UpdatePasswordResp
+	18, // 34: api.Dex.DeletePassword:output_type -> api.DeletePasswordResp
+	20, // 35: api.Dex.ListPasswords:output_type -> api.ListPasswordResp
+	23, // 36: api.Dex.CreateConnector:output_type -> api.CreateConnectorResp
+	25, // 37: api.Dex.UpdateConnector:output_type -> api.UpdateConnectorResp
+	27, // 38: api.Dex.DeleteConnector:output_type -> api.DeleteConnectorResp
+	29, // 39: api.Dex.ListConnectors:output_type -> api.ListConnectorResp
+	31, // 40: api.Dex.GetVersion:output_type -> api.VersionResp
+	33, // 41: api.Dex.GetDiscovery:output_type -> api.DiscoveryResp
+	36, // 42: api.Dex.ListRefresh:output_type -> api.ListRefreshResp
+	38, // 43: api.Dex.RevokeRefresh:output_type -> api.RevokeRefreshResp
+	40, // 44: api.Dex.VerifyPassword:output_type -> api.VerifyPasswordResp
+	27, // [27:45] is the sub-list for method output_type
+	9,  // [9:27] is the sub-list for method input_type
+	9,  // [9:9] is the sub-list for extension type_name
+	9,  // [9:9] is the sub-list for extension extendee
+	0,  // [0:9] is the sub-list for field type_name
 }
 
 func init() { file_api_v2_api_proto_init() }
@@ -2453,7 +2646,7 @@ func file_api_v2_api_proto_init() {
 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
 			RawDescriptor: unsafe.Slice(unsafe.StringData(file_api_v2_api_proto_rawDesc), len(file_api_v2_api_proto_rawDesc)),
 			NumEnums:      0,
-			NumMessages:   38,
+			NumMessages:   41,
 			NumExtensions: 0,
 			NumServices:   1,
 		},
diff --git a/api/v2/api.proto b/api/v2/api.proto
index 66941083..fc14913b 100644
--- a/api/v2/api.proto
+++ b/api/v2/api.proto
@@ -16,6 +16,16 @@ message Client {
   string logo_url = 7;
 }
 
+// ClientInfo represents an OAuth2 client without sensitive information.
+message ClientInfo {
+  string id = 1;
+  repeated string redirect_uris = 2;
+  repeated string trusted_peers = 3;
+  bool public = 4;
+  string name = 5;
+  string logo_url = 6;
+}
+
 // GetClientReq is a request to retrieve client details.
 message GetClientReq {
   // The ID of the client.
@@ -63,6 +73,14 @@ message UpdateClientResp {
     bool not_found = 1;
 }
 
+// ListClientReq is a request to enumerate clients.
+message ListClientReq {}
+
+// ListClientResp returns a list of clients.
+message ListClientResp {
+  repeated ClientInfo clients = 1;
+}
+
 // TODO(ericchiang): expand this.
 
 // Password is an email for password mapping managed by the storage.
@@ -253,6 +271,8 @@ service Dex {
   rpc UpdateClient(UpdateClientReq) returns (UpdateClientResp) {};
   // DeleteClient deletes the provided client.
   rpc DeleteClient(DeleteClientReq) returns (DeleteClientResp) {};
+  // ListClients lists all client entries.
+  rpc ListClients(ListClientReq) returns (ListClientResp) {};
   // CreatePassword creates a password.
   rpc CreatePassword(CreatePasswordReq) returns (CreatePasswordResp) {};
   // UpdatePassword modifies existing password.
diff --git a/api/v2/api_grpc.pb.go b/api/v2/api_grpc.pb.go
index 6389ecb9..3fe210e6 100644
--- a/api/v2/api_grpc.pb.go
+++ b/api/v2/api_grpc.pb.go
@@ -23,6 +23,7 @@ const (
 	Dex_CreateClient_FullMethodName    = "/api.Dex/CreateClient"
 	Dex_UpdateClient_FullMethodName    = "/api.Dex/UpdateClient"
 	Dex_DeleteClient_FullMethodName    = "/api.Dex/DeleteClient"
+	Dex_ListClients_FullMethodName     = "/api.Dex/ListClients"
 	Dex_CreatePassword_FullMethodName  = "/api.Dex/CreatePassword"
 	Dex_UpdatePassword_FullMethodName  = "/api.Dex/UpdatePassword"
 	Dex_DeletePassword_FullMethodName  = "/api.Dex/DeletePassword"
@@ -52,6 +53,8 @@ type DexClient interface {
 	UpdateClient(ctx context.Context, in *UpdateClientReq, opts ...grpc.CallOption) (*UpdateClientResp, error)
 	// DeleteClient deletes the provided client.
 	DeleteClient(ctx context.Context, in *DeleteClientReq, opts ...grpc.CallOption) (*DeleteClientResp, error)
+	// ListClients lists all client entries.
+	ListClients(ctx context.Context, in *ListClientReq, opts ...grpc.CallOption) (*ListClientResp, error)
 	// CreatePassword creates a password.
 	CreatePassword(ctx context.Context, in *CreatePasswordReq, opts ...grpc.CallOption) (*CreatePasswordResp, error)
 	// UpdatePassword modifies existing password.
@@ -130,6 +133,16 @@ func (c *dexClient) DeleteClient(ctx context.Context, in *DeleteClientReq, opts
 	return out, nil
 }
 
+func (c *dexClient) ListClients(ctx context.Context, in *ListClientReq, opts ...grpc.CallOption) (*ListClientResp, error) {
+	cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+	out := new(ListClientResp)
+	err := c.cc.Invoke(ctx, Dex_ListClients_FullMethodName, in, out, cOpts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
 func (c *dexClient) CreatePassword(ctx context.Context, in *CreatePasswordReq, opts ...grpc.CallOption) (*CreatePasswordResp, error) {
 	cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
 	out := new(CreatePasswordResp)
@@ -274,6 +287,8 @@ type DexServer interface {
 	UpdateClient(context.Context, *UpdateClientReq) (*UpdateClientResp, error)
 	// DeleteClient deletes the provided client.
 	DeleteClient(context.Context, *DeleteClientReq) (*DeleteClientResp, error)
+	// ListClients lists all client entries.
+	ListClients(context.Context, *ListClientReq) (*ListClientResp, error)
 	// CreatePassword creates a password.
 	CreatePassword(context.Context, *CreatePasswordReq) (*CreatePasswordResp, error)
 	// UpdatePassword modifies existing password.
@@ -324,6 +339,9 @@ func (UnimplementedDexServer) UpdateClient(context.Context, *UpdateClientReq) (*
 func (UnimplementedDexServer) DeleteClient(context.Context, *DeleteClientReq) (*DeleteClientResp, error) {
 	return nil, status.Errorf(codes.Unimplemented, "method DeleteClient not implemented")
 }
+func (UnimplementedDexServer) ListClients(context.Context, *ListClientReq) (*ListClientResp, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method ListClients not implemented")
+}
 func (UnimplementedDexServer) CreatePassword(context.Context, *CreatePasswordReq) (*CreatePasswordResp, error) {
 	return nil, status.Errorf(codes.Unimplemented, "method CreatePassword not implemented")
 }
@@ -456,6 +474,24 @@ func _Dex_DeleteClient_Handler(srv interface{}, ctx context.Context, dec func(in
 	return interceptor(ctx, in, info, handler)
 }
 
+func _Dex_ListClients_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(ListClientReq)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(DexServer).ListClients(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: Dex_ListClients_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(DexServer).ListClients(ctx, req.(*ListClientReq))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
 func _Dex_CreatePassword_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
 	in := new(CreatePasswordReq)
 	if err := dec(in); err != nil {
@@ -713,6 +749,10 @@ var Dex_ServiceDesc = grpc.ServiceDesc{
 			MethodName: "DeleteClient",
 			Handler:    _Dex_DeleteClient_Handler,
 		},
+		{
+			MethodName: "ListClients",
+			Handler:    _Dex_ListClients_Handler,
+		},
 		{
 			MethodName: "CreatePassword",
 			Handler:    _Dex_CreatePassword_Handler,
diff --git a/connector/authproxy/authproxy.go b/connector/authproxy/authproxy.go
index 2419d3b7..f3d87fcb 100644
--- a/connector/authproxy/authproxy.go
+++ b/connector/authproxy/authproxy.go
@@ -19,12 +19,13 @@ import (
 // Headers retrieved to fetch user's email and group can be configured
 // with userHeader and groupHeader.
 type Config struct {
-	UserIDHeader   string   `json:"userIDHeader"`
-	UserHeader     string   `json:"userHeader"`
-	UserNameHeader string   `json:"userNameHeader"`
-	EmailHeader    string   `json:"emailHeader"`
-	GroupHeader    string   `json:"groupHeader"`
-	Groups         []string `json:"staticGroups"`
+	UserIDHeader         string   `json:"userIDHeader"`
+	UserHeader           string   `json:"userHeader"`
+	UserNameHeader       string   `json:"userNameHeader"`
+	EmailHeader          string   `json:"emailHeader"`
+	GroupHeader          string   `json:"groupHeader"`
+	GroupHeaderSeparator string   `json:"groupHeaderSeparator"`
+	Groups               []string `json:"staticGroups"`
 }
 
 // Open returns an authentication strategy which requires no user interaction.
@@ -49,30 +50,36 @@ func (c *Config) Open(id string, logger *slog.Logger) (connector.Connector, erro
 	if groupHeader == "" {
 		groupHeader = "X-Remote-Group"
 	}
+	groupHeaderSeparator := c.GroupHeaderSeparator
+	if groupHeaderSeparator == "" {
+		groupHeaderSeparator = ","
+	}
 
 	return &callback{
-		userIDHeader:   userIDHeader,
-		userHeader:     userHeader,
-		userNameHeader: userNameHeader,
-		emailHeader:    emailHeader,
-		groupHeader:    groupHeader,
-		groups:         c.Groups,
-		logger:         logger.With(slog.Group("connector", "type", "authproxy", "id", id)),
-		pathSuffix:     "/" + id,
+		userIDHeader:         userIDHeader,
+		userHeader:           userHeader,
+		userNameHeader:       userNameHeader,
+		emailHeader:          emailHeader,
+		groupHeader:          groupHeader,
+		groupHeaderSeparator: groupHeaderSeparator,
+		groups:               c.Groups,
+		logger:               logger.With(slog.Group("connector", "type", "authproxy", "id", id)),
+		pathSuffix:           "/" + id,
 	}, nil
 }
 
 // Callback is a connector which returns an identity with the HTTP header
 // X-Remote-User as verified email.
 type callback struct {
-	userIDHeader   string
-	userNameHeader string
-	userHeader     string
-	emailHeader    string
-	groupHeader    string
-	groups         []string
-	logger         *slog.Logger
-	pathSuffix     string
+	userIDHeader         string
+	userNameHeader       string
+	userHeader           string
+	emailHeader          string
+	groupHeader          string
+	groupHeaderSeparator string
+	groups               []string
+	logger               *slog.Logger
+	pathSuffix           string
 }
 
 // LoginURL returns the URL to redirect the user to login with.
@@ -109,7 +116,7 @@ func (m *callback) HandleCallback(s connector.Scopes, r *http.Request) (connecto
 	groups := m.groups
 	headerGroup := r.Header.Get(m.groupHeader)
 	if headerGroup != "" {
-		splitheaderGroup := strings.Split(headerGroup, ",")
+		splitheaderGroup := strings.Split(headerGroup, m.groupHeaderSeparator)
 		for i, v := range splitheaderGroup {
 			splitheaderGroup[i] = strings.TrimSpace(v)
 		}
diff --git a/examples/go.mod b/examples/go.mod
index 0b9cc4ce..86185c8d 100644
--- a/examples/go.mod
+++ b/examples/go.mod
@@ -3,11 +3,11 @@ module github.com/dexidp/dex/examples
 go 1.24.0
 
 require (
-	github.com/coreos/go-oidc/v3 v3.14.1
+	github.com/coreos/go-oidc/v3 v3.15.0
 	github.com/dexidp/dex/api/v2 v2.3.0
 	github.com/spf13/cobra v1.9.1
 	golang.org/x/oauth2 v0.30.0
-	google.golang.org/grpc v1.74.0
+	google.golang.org/grpc v1.74.2
 )
 
 require (
diff --git a/examples/go.sum b/examples/go.sum
index 086d2f12..e8325d5c 100644
--- a/examples/go.sum
+++ b/examples/go.sum
@@ -1,5 +1,5 @@
-github.com/coreos/go-oidc/v3 v3.14.1 h1:9ePWwfdwC4QKRlCXsJGou56adA/owXczOzwKdOumLqk=
-github.com/coreos/go-oidc/v3 v3.14.1/go.mod h1:HaZ3szPaZ0e4r6ebqvsLWlk2Tn+aejfmrfah6hnSYEU=
+github.com/coreos/go-oidc/v3 v3.15.0 h1:R6Oz8Z4bqWR7VFQ+sPSvZPQv4x8M+sJkDO5ojgwlyAg=
+github.com/coreos/go-oidc/v3 v3.15.0/go.mod h1:HaZ3szPaZ0e4r6ebqvsLWlk2Tn+aejfmrfah6hnSYEU=
 github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -52,8 +52,8 @@ golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
 golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
 google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a h1:v2PbRU4K3llS09c7zodFpNePeamkAwG3mPrAery9VeE=
 google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
-google.golang.org/grpc v1.74.0 h1:sxRSkyLxlceWQiqDofxDot3d4u7DyoHPc7SBXMj8gGY=
-google.golang.org/grpc v1.74.0/go.mod h1:NZUaK8dAMUfzhK6uxZ+9511LtOrk73UGWOFoNvz7z+s=
+google.golang.org/grpc v1.74.2 h1:WoosgB65DlWVC9FqI82dGsZhWFNBSLjQ84bjROOpMu4=
+google.golang.org/grpc v1.74.2/go.mod h1:CtQ+BGjaAIXHs/5YS3i473GqwBBa1zGQNevxdeBEXrM=
 google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
 google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
diff --git a/examples/grpc-client/README.md b/examples/grpc-client/README.md
index 59629e05..6a78df91 100644
--- a/examples/grpc-client/README.md
+++ b/examples/grpc-client/README.md
@@ -50,6 +50,9 @@ Running the gRPC client will cause the following API calls to be made to the ser
 2. ListPasswords
 3. VerifyPassword
 4. DeletePassword
+5. CreateClient
+6. ListClients
+7. DeleteClient
 
 ## Cleaning up
 
diff --git a/examples/grpc-client/client.go b/examples/grpc-client/client.go
index fb8d4aaf..7bbbac64 100644
--- a/examples/grpc-client/client.go
+++ b/examples/grpc-client/client.go
@@ -58,7 +58,7 @@ func createPassword(cli api.DexClient) error {
 
 	// Create password.
 	if resp, err := cli.CreatePassword(context.TODO(), createReq); err != nil || resp.AlreadyExists {
-		if resp != nil &&  resp.AlreadyExists {
+		if resp != nil && resp.AlreadyExists {
 			return fmt.Errorf("Password %s already exists", createReq.Password.Email)
 		}
 		return fmt.Errorf("failed to create password: %v", err)
@@ -125,6 +125,57 @@ func createPassword(cli api.DexClient) error {
 	return nil
 }
 
+func createAndListClients(cli api.DexClient) error {
+	client := &api.Client{
+		Id:           "example-client",
+		Secret:       "example-secret",
+		RedirectUris: []string{"http://localhost:8080/callback"},
+		TrustedPeers: []string{},
+		Public:       false,
+		Name:         "Example Client",
+		LogoUrl:      "http://example.com/logo.png",
+	}
+
+	createReq := &api.CreateClientReq{
+		Client: client,
+	}
+
+	if resp, err := cli.CreateClient(context.TODO(), createReq); err != nil || resp.AlreadyExists {
+		if resp != nil && resp.AlreadyExists {
+			log.Printf("Client %s already exists", createReq.Client.Id)
+		} else {
+			return fmt.Errorf("failed to create client: %v", err)
+		}
+	} else {
+		log.Printf("Created client with ID %s", createReq.Client.Id)
+	}
+
+	listResp, err := cli.ListClients(context.TODO(), &api.ListClientReq{})
+	if err != nil {
+		return fmt.Errorf("failed to list clients: %v", err)
+	}
+
+	log.Print("Listing Clients:\n")
+	for _, client := range listResp.Clients {
+		log.Printf("ID: %s, Name: %s, Public: %t, RedirectURIs: %v",
+			client.Id, client.Name, client.Public, client.RedirectUris)
+	}
+
+	deleteReq := &api.DeleteClientReq{
+		Id: client.Id,
+	}
+
+	if resp, err := cli.DeleteClient(context.TODO(), deleteReq); err != nil || resp.NotFound {
+		if resp != nil && resp.NotFound {
+			return fmt.Errorf("Client %s not found", deleteReq.Id)
+		}
+		return fmt.Errorf("failed to delete client: %v", err)
+	}
+	log.Printf("Deleted client with ID %s", deleteReq.Id)
+
+	return nil
+}
+
 func main() {
 	caCrt := flag.String("ca-crt", "", "CA certificate")
 	clientCrt := flag.String("client-crt", "", "Client certificate")
@@ -143,4 +194,8 @@ func main() {
 	if err := createPassword(client); err != nil {
 		log.Fatalf("testPassword failed: %v", err)
 	}
+
+	if err := createAndListClients(client); err != nil {
+		log.Fatalf("testClients failed: %v", err)
+	}
 }
diff --git a/go.mod b/go.mod
index 04ca04a6..791d05b4 100644
--- a/go.mod
+++ b/go.mod
@@ -3,7 +3,7 @@ module github.com/dexidp/dex
 go 1.24.0
 
 require (
-	cloud.google.com/go/compute/metadata v0.7.0
+	cloud.google.com/go/compute/metadata v0.8.0
 	entgo.io/ent v0.14.4
 	github.com/AppsFlyer/go-sundheit v0.6.0
 	github.com/Masterminds/semver v1.5.0
@@ -13,7 +13,7 @@ require (
 	github.com/dexidp/dex/api/v2 v2.3.0
 	github.com/fsnotify/fsnotify v1.9.0
 	github.com/ghodss/yaml v1.0.0
-	github.com/go-jose/go-jose/v4 v4.1.1
+	github.com/go-jose/go-jose/v4 v4.1.2
 	github.com/go-ldap/ldap/v3 v3.4.11
 	github.com/go-sql-driver/mysql v1.9.3
 	github.com/google/uuid v1.6.0
@@ -23,27 +23,27 @@ require (
 	github.com/kylelemons/godebug v1.1.0
 	github.com/lib/pq v1.10.9
 	github.com/mattermost/xml-roundtrip-validator v0.1.0
-	github.com/mattn/go-sqlite3 v1.14.28
+	github.com/mattn/go-sqlite3 v1.14.32
 	github.com/oklog/run v1.2.0
 	github.com/pkg/errors v0.9.1
-	github.com/prometheus/client_golang v1.22.0
+	github.com/prometheus/client_golang v1.23.0
 	github.com/russellhaering/goxmldsig v1.5.0
 	github.com/spf13/cobra v1.9.1
 	github.com/stretchr/testify v1.10.0
-	go.etcd.io/etcd/client/pkg/v3 v3.6.2
-	go.etcd.io/etcd/client/v3 v3.6.2
-	golang.org/x/crypto v0.40.0
+	go.etcd.io/etcd/client/pkg/v3 v3.6.4
+	go.etcd.io/etcd/client/v3 v3.6.4
+	golang.org/x/crypto v0.41.0
 	golang.org/x/exp v0.0.0-20221004215720-b9f4876ce741
-	golang.org/x/net v0.41.0
+	golang.org/x/net v0.43.0
 	golang.org/x/oauth2 v0.30.0
-	google.golang.org/api v0.238.0
-	google.golang.org/grpc v1.73.0
+	google.golang.org/api v0.246.0
+	google.golang.org/grpc v1.74.2
 	google.golang.org/protobuf v1.36.6
 )
 
 require (
 	ariga.io/atlas v0.31.1-0.20250212144724-069be8033e83 // indirect
-	cloud.google.com/go/auth v0.16.2 // indirect
+	cloud.google.com/go/auth v0.16.3 // indirect
 	cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
 	dario.cat/mergo v1.0.1 // indirect
 	filippo.io/edwards25519 v1.1.0 // indirect
@@ -61,7 +61,7 @@ require (
 	github.com/davecgh/go-spew v1.1.1 // indirect
 	github.com/felixge/httpsnoop v1.0.4 // indirect
 	github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 // indirect
-	github.com/go-logr/logr v1.4.2 // indirect
+	github.com/go-logr/logr v1.4.3 // indirect
 	github.com/go-logr/stdr v1.2.2 // indirect
 	github.com/go-openapi/inflect v0.19.0 // indirect
 	github.com/gogo/protobuf v1.3.2 // indirect
@@ -69,7 +69,7 @@ require (
 	github.com/google/go-cmp v0.7.0 // indirect
 	github.com/google/s2a-go v0.1.9 // indirect
 	github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect
-	github.com/googleapis/gax-go/v2 v2.14.2 // indirect
+	github.com/googleapis/gax-go/v2 v2.15.0 // indirect
 	github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect
 	github.com/hashicorp/hcl/v2 v2.13.0 // indirect
 	github.com/huandu/xstrings v1.5.0 // indirect
@@ -82,15 +82,15 @@ require (
 	github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
 	github.com/olekukonko/tablewriter v0.0.5 // indirect
 	github.com/pmezard/go-difflib v1.0.0 // indirect
-	github.com/prometheus/client_model v0.6.1 // indirect
-	github.com/prometheus/common v0.62.0 // indirect
-	github.com/prometheus/procfs v0.15.1 // indirect
+	github.com/prometheus/client_model v0.6.2 // indirect
+	github.com/prometheus/common v0.65.0 // indirect
+	github.com/prometheus/procfs v0.16.1 // indirect
 	github.com/shopspring/decimal v1.4.0 // indirect
 	github.com/spf13/cast v1.7.0 // indirect
 	github.com/spf13/pflag v1.0.6 // indirect
 	github.com/zclconf/go-cty v1.14.4 // indirect
 	github.com/zclconf/go-cty-yaml v1.1.0 // indirect
-	go.etcd.io/etcd/api/v3 v3.6.2 // indirect
+	go.etcd.io/etcd/api/v3 v3.6.4 // indirect
 	go.opentelemetry.io/auto/sdk v1.1.0 // indirect
 	go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
 	go.opentelemetry.io/otel v1.36.0 // indirect
@@ -98,13 +98,14 @@ require (
 	go.opentelemetry.io/otel/trace v1.36.0 // indirect
 	go.uber.org/multierr v1.11.0 // indirect
 	go.uber.org/zap v1.27.0 // indirect
-	golang.org/x/mod v0.25.0 // indirect
+	golang.org/x/mod v0.26.0 // indirect
 	golang.org/x/sync v0.16.0 // indirect
-	golang.org/x/sys v0.34.0 // indirect
-	golang.org/x/text v0.27.0 // indirect
-	golang.org/x/tools v0.34.0 // indirect
-	google.golang.org/genproto/googleapis/api v0.0.0-20250505200425-f936aa4a68b2 // indirect
-	google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect
+	golang.org/x/sys v0.35.0 // indirect
+	golang.org/x/text v0.28.0 // indirect
+	golang.org/x/tools v0.35.0 // indirect
+	golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated // indirect
+	google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 // indirect
+	google.golang.org/genproto/googleapis/rpc v0.0.0-20250728155136-f173205681a0 // indirect
 	gopkg.in/yaml.v2 v2.4.0 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
 )
diff --git a/go.sum b/go.sum
index 8ac03a08..6cb6d388 100644
--- a/go.sum
+++ b/go.sum
@@ -1,11 +1,11 @@
 ariga.io/atlas v0.31.1-0.20250212144724-069be8033e83 h1:nX4HXncwIdvQ8/8sIUIf1nyCkK8qdBaHQ7EtzPpuiGE=
 ariga.io/atlas v0.31.1-0.20250212144724-069be8033e83/go.mod h1:Oe1xWPuu5q9LzyrWfbZmEZxFYeu4BHTyzfjeW2aZp/w=
-cloud.google.com/go/auth v0.16.2 h1:QvBAGFPLrDeoiNjyfVunhQ10HKNYuOwZ5noee0M5df4=
-cloud.google.com/go/auth v0.16.2/go.mod h1:sRBas2Y1fB1vZTdurouM0AzuYQBMZinrUYL8EufhtEA=
+cloud.google.com/go/auth v0.16.3 h1:kabzoQ9/bobUmnseYnBO6qQG7q4a/CffFRlJSxv2wCc=
+cloud.google.com/go/auth v0.16.3/go.mod h1:NucRGjaXfzP1ltpcQ7On/VTZ0H4kWB5Jy+Y9Dnm76fA=
 cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc=
 cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c=
-cloud.google.com/go/compute/metadata v0.7.0 h1:PBWF+iiAerVNe8UCHxdOt6eHLVc3ydFeOCw78U8ytSU=
-cloud.google.com/go/compute/metadata v0.7.0/go.mod h1:j5MvL9PprKL39t166CoB1uVHfQMs4tFQZZcKwksXUjo=
+cloud.google.com/go/compute/metadata v0.8.0 h1:HxMRIbao8w17ZX6wBnjhcDkW6lTFpgcaobyVfZWqRLA=
+cloud.google.com/go/compute/metadata v0.8.0/go.mod h1:sYOGTp851OV9bOFJ9CH7elVvyzopvWQFNNghtDQ/Biw=
 dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
 dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
 entgo.io/ent v0.14.4 h1:/DhDraSLXIkBhyiVoJeSshr4ZYi7femzhj6/TckzZuI=
@@ -64,13 +64,13 @@ github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
 github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
 github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 h1:BP4M0CvQ4S3TGls2FvczZtj5Re/2ZzkV9VwqPHH/3Bo=
 github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
-github.com/go-jose/go-jose/v4 v4.1.1 h1:JYhSgy4mXXzAdF3nUx3ygx347LRXJRrpgyU3adRmkAI=
-github.com/go-jose/go-jose/v4 v4.1.1/go.mod h1:BdsZGqgdO3b6tTc6LSE56wcDbMMLuPsw5d4ZD5f94kA=
+github.com/go-jose/go-jose/v4 v4.1.2 h1:TK/7NqRQZfgAh+Td8AlsrvtPoUyiHh0LqVvokh+1vHI=
+github.com/go-jose/go-jose/v4 v4.1.2/go.mod h1:22cg9HWM1pOlnRiY+9cQYJ9XHmya1bYW8OeDM6Ku6Oo=
 github.com/go-ldap/ldap/v3 v3.4.11 h1:4k0Yxweg+a3OyBLjdYn5OKglv18JNvfDykSoI8bW0gU=
 github.com/go-ldap/ldap/v3 v3.4.11/go.mod h1:bY7t0FLK8OAVpp/vV6sSlpz3EQDGcQwc8pF0ujLgKvM=
 github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
-github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
-github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
+github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
+github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
 github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
 github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
 github.com/go-openapi/inflect v0.19.0 h1:9jCH9scKIbHeV9m12SmPilScz6krDxKRasNNSNPXu/4=
@@ -92,8 +92,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
 github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/googleapis/enterprise-certificate-proxy v0.3.6 h1:GW/XbdyBFQ8Qe+YAmFU9uHLo7OnF5tL52HFAgMmyrf4=
 github.com/googleapis/enterprise-certificate-proxy v0.3.6/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA=
-github.com/googleapis/gax-go/v2 v2.14.2 h1:eBLnkZ9635krYIPD+ag1USrOAI0Nr0QYF3+/3GqO0k0=
-github.com/googleapis/gax-go/v2 v2.14.2/go.mod h1:ON64QhlJkhVtSqp4v1uaK92VyZ2gmvDQsweuyLV+8+w=
+github.com/googleapis/gax-go/v2 v2.15.0 h1:SyjDc1mGgZU5LncH8gimWo9lW1DtIfPibOG81vgd/bo=
+github.com/googleapis/gax-go/v2 v2.15.0/go.mod h1:zVVkkxAQHa1RQpg9z2AUCMnKhi0Qld9rcmyfL1OZhoc=
 github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE=
 github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w=
 github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
@@ -143,8 +143,8 @@ github.com/mattermost/xml-roundtrip-validator v0.1.0 h1:RXbVD2UAl7A7nOTR4u7E3ILa
 github.com/mattermost/xml-roundtrip-validator v0.1.0/go.mod h1:qccnGMcpgwcNaBnxqpJpWWUiPNr5H3O8eDgGV9gT5To=
 github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
 github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
-github.com/mattn/go-sqlite3 v1.14.28 h1:ThEiQrnbtumT+QMknw63Befp/ce/nUPgBPMlRFEum7A=
-github.com/mattn/go-sqlite3 v1.14.28/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
+github.com/mattn/go-sqlite3 v1.14.32 h1:JD12Ag3oLy1zQA+BNn74xRgaBbdhbNIDYvQUEuuErjs=
+github.com/mattn/go-sqlite3 v1.14.32/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
 github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
 github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
 github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 h1:DpOJ2HYzCv8LZP15IdmG+YdwD2luVPHITV96TkirNBM=
@@ -162,14 +162,14 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q=
-github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0=
-github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
-github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
-github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io=
-github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
-github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
-github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
+github.com/prometheus/client_golang v1.23.0 h1:ust4zpdl9r4trLY/gSjlm07PuiBq2ynaXXlptpfy8Uc=
+github.com/prometheus/client_golang v1.23.0/go.mod h1:i/o0R9ByOnHX0McrTMTyhYvKE4haaf2mW08I+jGAjEE=
+github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
+github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
+github.com/prometheus/common v0.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2VzE=
+github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8=
+github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg=
+github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=
 github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
 github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
 github.com/russellhaering/goxmldsig v1.5.0 h1:AU2UkkYIUOTyZRbe08XMThaOCelArgvNfYapcmSjBNw=
@@ -199,12 +199,12 @@ github.com/zclconf/go-cty v1.14.4 h1:uXXczd9QDGsgu0i/QFR/hzI5NYCHLf6NQw/atrbnhq8
 github.com/zclconf/go-cty v1.14.4/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=
 github.com/zclconf/go-cty-yaml v1.1.0 h1:nP+jp0qPHv2IhUVqmQSzjvqAWcObN0KBkUl2rWBdig0=
 github.com/zclconf/go-cty-yaml v1.1.0/go.mod h1:9YLUH4g7lOhVWqUbctnVlZ5KLpg7JAprQNgxSZ1Gyxs=
-go.etcd.io/etcd/api/v3 v3.6.2 h1:25aCkIMjUmiiOtnBIp6PhNj4KdcURuBak0hU2P1fgRc=
-go.etcd.io/etcd/api/v3 v3.6.2/go.mod h1:eFhhvfR8Px1P6SEuLT600v+vrhdDTdcfMzmnxVXXSbk=
-go.etcd.io/etcd/client/pkg/v3 v3.6.2 h1:zw+HRghi/G8fKpgKdOcEKpnBTE4OO39T6MegA0RopVU=
-go.etcd.io/etcd/client/pkg/v3 v3.6.2/go.mod h1:sbdzr2cl3HzVmxNw//PH7aLGVtY4QySjQFuaCgcRFAI=
-go.etcd.io/etcd/client/v3 v3.6.2 h1:RgmcLJxkpHqpFvgKNwAQHX3K+wsSARMXKgjmUSpoSKQ=
-go.etcd.io/etcd/client/v3 v3.6.2/go.mod h1:PL7e5QMKzjybn0FosgiWvCUDzvdChpo5UgGR4Sk4Gzc=
+go.etcd.io/etcd/api/v3 v3.6.4 h1:7F6N7toCKcV72QmoUKa23yYLiiljMrT4xCeBL9BmXdo=
+go.etcd.io/etcd/api/v3 v3.6.4/go.mod h1:eFhhvfR8Px1P6SEuLT600v+vrhdDTdcfMzmnxVXXSbk=
+go.etcd.io/etcd/client/pkg/v3 v3.6.4 h1:9HBYrjppeOfFjBjaMTRxT3R7xT0GLK8EJMVC4xg6ok0=
+go.etcd.io/etcd/client/pkg/v3 v3.6.4/go.mod h1:sbdzr2cl3HzVmxNw//PH7aLGVtY4QySjQFuaCgcRFAI=
+go.etcd.io/etcd/client/v3 v3.6.4 h1:YOMrCfMhRzY8NgtzUsHl8hC2EBSnuqbR3dh84Uryl7A=
+go.etcd.io/etcd/client/v3 v3.6.4/go.mod h1:jaNNHCyg2FdALyKWnd7hxZXZxZANb0+KGY+YQaEMISo=
 go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
 go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 h1:q4XOmH/0opmeuJtPsbFNivyl7bCt7yRBbeEm2sC/XtQ=
@@ -230,20 +230,20 @@ go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM=
-golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=
+golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4=
+golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc=
 golang.org/x/exp v0.0.0-20221004215720-b9f4876ce741 h1:fGZugkZk2UgYBxtpKmvub51Yno1LJDeEsRp2xGD+0gY=
 golang.org/x/exp v0.0.0-20221004215720-b9f4876ce741/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
 golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w=
-golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
+golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg=
+golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ=
 golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
-golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
+golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
+golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
 golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
 golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -254,34 +254,38 @@ golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
-golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
+golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
+golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
-golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
+golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
+golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
 golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
 golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
 golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo=
-golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg=
+golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0=
+golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw=
+golang.org/x/tools/go/expect v0.1.0-deprecated h1:jY2C5HGYR5lqex3gEniOQL0r7Dq5+VGVgY1nudX5lXY=
+golang.org/x/tools/go/expect v0.1.0-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY=
+golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated h1:1h2MnaIAIXISqTFKdENegdpAgUXz6NrPEsbIeWaBRvM=
+golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated/go.mod h1:RVAQXBGNv1ib0J382/DPCRS/BPnsGebyM1Gj5VSDpG8=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/api v0.238.0 h1:+EldkglWIg/pWjkq97sd+XxH7PxakNYoe/rkSTbnvOs=
-google.golang.org/api v0.238.0/go.mod h1:cOVEm2TpdAGHL2z+UwyS+kmlGr3bVWQQ6sYEqkKje50=
-google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2 h1:1tXaIXCracvtsRxSBsYDiSBN0cuJvM7QYW+MrpIRY78=
-google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:49MsLSx0oWMOZqcpB3uL8ZOkAh1+TndpJ8ONoCBWiZk=
-google.golang.org/genproto/googleapis/api v0.0.0-20250505200425-f936aa4a68b2 h1:vPV0tzlsK6EzEDHNNH5sa7Hs9bd7iXR7B1tSiPepkV0=
-google.golang.org/genproto/googleapis/api v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:pKLAc5OolXC3ViWGI62vvC0n10CpwAtRcTNCFwTKBEw=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 h1:fc6jSaCT0vBduLYZHYrBBNY4dsWuvgyff9noRNDdBeE=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
-google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok=
-google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc=
+google.golang.org/api v0.246.0 h1:H0ODDs5PnMZVZAEtdLMn2Ul2eQi7QNjqM2DIFp8TlTM=
+google.golang.org/api v0.246.0/go.mod h1:dMVhVcylamkirHdzEBAIQWUCgqY885ivNeZYd7VAVr8=
+google.golang.org/genproto v0.0.0-20250603155806-513f23925822 h1:rHWScKit0gvAPuOnu87KpaYtjK5zBMLcULh7gxkCXu4=
+google.golang.org/genproto v0.0.0-20250603155806-513f23925822/go.mod h1:HubltRL7rMh0LfnQPkMH4NPDFEWp0jw3vixw7jEM53s=
+google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 h1:oWVWY3NzT7KJppx2UKhKmzPq4SRe0LdCijVRwvGeikY=
+google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822/go.mod h1:h3c4v36UTKzUiuaOKQ6gr3S+0hovBtUrXzTG/i3+XEc=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20250728155136-f173205681a0 h1:MAKi5q709QWfnkkpNQ0M12hYJ1+e8qYVDyowc4U1XZM=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20250728155136-f173205681a0/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
+google.golang.org/grpc v1.74.2 h1:WoosgB65DlWVC9FqI82dGsZhWFNBSLjQ84bjROOpMu4=
+google.golang.org/grpc v1.74.2/go.mod h1:CtQ+BGjaAIXHs/5YS3i473GqwBBa1zGQNevxdeBEXrM=
 google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
 google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
diff --git a/server/api.go b/server/api.go
index 5b0abb0b..4fceae96 100644
--- a/server/api.go
+++ b/server/api.go
@@ -18,7 +18,7 @@ import (
 
 // apiVersion increases every time a new call is added to the API. Clients should use this info
 // to determine if the server supports specific features.
-const apiVersion = 2
+const apiVersion = 3
 
 const (
 	// recCost is the recommended bcrypt cost, which balances hash strength and
@@ -145,6 +145,31 @@ func (d dexAPI) DeleteClient(ctx context.Context, req *api.DeleteClientReq) (*ap
 	return &api.DeleteClientResp{}, nil
 }
 
+func (d dexAPI) ListClients(ctx context.Context, req *api.ListClientReq) (*api.ListClientResp, error) {
+	clientList, err := d.s.ListClients(ctx)
+	if err != nil {
+		d.logger.Error("failed to list clients", "err", err)
+		return nil, fmt.Errorf("list clients: %v", err)
+	}
+
+	clients := make([]*api.ClientInfo, 0, len(clientList))
+	for _, client := range clientList {
+		c := api.ClientInfo{
+			Id:           client.ID,
+			Name:         client.Name,
+			RedirectUris: client.RedirectURIs,
+			TrustedPeers: client.TrustedPeers,
+			Public:       client.Public,
+			LogoUrl:      client.LogoURL,
+		}
+		clients = append(clients, &c)
+	}
+
+	return &api.ListClientResp{
+		Clients: clients,
+	}, nil
+}
+
 // checkCost returns an error if the hash provided does not meet lower or upper
 // bound cost requirements.
 func checkCost(hash []byte) error {
diff --git a/server/deviceflowhandlers.go b/server/deviceflowhandlers.go
index 380e40aa..3cbfbf16 100644
--- a/server/deviceflowhandlers.go
+++ b/server/deviceflowhandlers.go
@@ -85,6 +85,12 @@ func (s *Server) handleDeviceCode(w http.ResponseWriter, r *http.Request) {
 			return
 		}
 
+		if len(scopes) == 0 {
+			// per RFC8628 section 3.1, https://datatracker.ietf.org/doc/html/rfc8628#section-3.1
+			// scope is optional but dex requires that it is always at least 'openid' so default it
+			scopes = []string{"openid"}
+		}
+
 		s.logger.InfoContext(r.Context(), "received device request", "client_id", clientID, "scoped", scopes)
 
 		// Make device code
@@ -249,7 +255,7 @@ func (s *Server) handleDeviceToken(w http.ResponseWriter, r *http.Request) {
 		if slowDown {
 			s.tokenErrHelper(w, deviceTokenSlowDown, "", http.StatusBadRequest)
 		} else {
-			s.tokenErrHelper(w, deviceTokenPending, "", http.StatusUnauthorized)
+			s.tokenErrHelper(w, deviceTokenPending, "", http.StatusBadRequest)
 		}
 	case deviceTokenComplete:
 		codeChallengeFromStorage := deviceToken.PKCE.CodeChallenge
diff --git a/server/server.go b/server/server.go
index 0f48fc11..70e8ae75 100644
--- a/server/server.go
+++ b/server/server.go
@@ -464,7 +464,7 @@ func newServer(ctx context.Context, c Config, rotationStrategy rotationStrategy)
 			<h1>Dex IdP</h1>
 			<h3>A Federated OpenID Connect Provider</h3>
 			<p><a href=%q>Discovery</a></p>`,
-			s.issuerURL.String()+"/.well-known/openid-configuration")
+			s.issuerURL.JoinPath(".well-known", "openid-configuration").String())
 		if err != nil {
 			s.logger.Error("failed to write response", "err", err)
 			s.renderError(r, w, http.StatusInternalServerError, "Handling the / path error.")
diff --git a/storage/sql/sqlite_no_cgo.go b/storage/sql/sqlite_no_cgo.go
new file mode 100644
index 00000000..80d14108
--- /dev/null
+++ b/storage/sql/sqlite_no_cgo.go
@@ -0,0 +1,19 @@
+//go:build !cgo
+// +build !cgo
+
+// This is a stub for the no CGO compilation (CGO_ENABLED=0)
+
+package sql
+
+import (
+	"fmt"
+	"log/slog"
+
+	"github.com/dexidp/dex/storage"
+)
+
+type SQLite3 struct{}
+
+func (s *SQLite3) Open(logger *slog.Logger) (storage.Storage, error) {
+	return nil, fmt.Errorf("SQLite storage is not available: binary compiled without CGO support. Recompile with CGO_ENABLED=1 or use a different storage backend.")
+}



Test patch:
diff --git a/connector/authproxy/authproxy_test.go b/connector/authproxy/authproxy_test.go
index cc40b154..fbdd2a5d 100644
--- a/connector/authproxy/authproxy_test.go
+++ b/connector/authproxy/authproxy_test.go
@@ -25,10 +25,10 @@ const (
 var logger = slog.New(slog.DiscardHandler)
 
 func TestUser(t *testing.T) {
-	config := Config{
-		UserHeader: "X-Remote-User",
-	}
-	conn := callback{userHeader: config.UserHeader, logger: logger, pathSuffix: "/test"}
+	config := Config{}
+
+	conn, _ := config.Open("test", logger)
+	callback := conn.(*callback)
 
 	req, err := http.NewRequest("GET", "/", nil)
 	expectNil(t, err)
@@ -36,7 +36,7 @@ func TestUser(t *testing.T) {
 		"X-Remote-User": {testUsername},
 	}
 
-	ident, err := conn.HandleCallback(connector.Scopes{OfflineAccess: true, Groups: true}, req)
+	ident, err := callback.HandleCallback(connector.Scopes{OfflineAccess: true, Groups: true}, req)
 	expectNil(t, err)
 
 	// If not specified, the userID and email should fall back to the remote user
@@ -48,20 +48,10 @@ func TestUser(t *testing.T) {
 }
 
 func TestExtraHeaders(t *testing.T) {
-	config := Config{
-		UserIDHeader:   "X-Remote-User-Id",
-		UserHeader:     "X-Remote-User",
-		UserNameHeader: "X-Remote-User-Name",
-		EmailHeader:    "X-Remote-User-Email",
-	}
-	conn := callback{
-		userHeader:     config.UserHeader,
-		userIDHeader:   config.UserIDHeader,
-		userNameHeader: config.UserNameHeader,
-		emailHeader:    config.EmailHeader,
-		logger:         logger,
-		pathSuffix:     "/test",
-	}
+	config := Config{}
+
+	conn, _ := config.Open("test", logger)
+	callback := conn.(*callback)
 
 	req, err := http.NewRequest("GET", "/", nil)
 	expectNil(t, err)
@@ -72,7 +62,7 @@ func TestExtraHeaders(t *testing.T) {
 		"X-Remote-User-Email": {testEmail},
 	}
 
-	ident, err := conn.HandleCallback(connector.Scopes{OfflineAccess: true, Groups: true}, req)
+	ident, err := callback.HandleCallback(connector.Scopes{OfflineAccess: true, Groups: true}, req)
 	expectNil(t, err)
 
 	expectEquals(t, ident.UserID, testUserID)
@@ -83,12 +73,10 @@ func TestExtraHeaders(t *testing.T) {
 }
 
 func TestSingleGroup(t *testing.T) {
-	config := Config{
-		UserHeader:  "X-Remote-User",
-		GroupHeader: "X-Remote-Group",
-	}
+	config := Config{}
 
-	conn := callback{userHeader: config.UserHeader, groupHeader: config.GroupHeader, logger: logger, pathSuffix: "/test"}
+	conn, _ := config.Open("test", logger)
+	callback := conn.(*callback)
 
 	req, err := http.NewRequest("GET", "/", nil)
 	expectNil(t, err)
@@ -97,7 +85,7 @@ func TestSingleGroup(t *testing.T) {
 		"X-Remote-Group": {testGroup1},
 	}
 
-	ident, err := conn.HandleCallback(connector.Scopes{OfflineAccess: true, Groups: true}, req)
+	ident, err := callback.HandleCallback(connector.Scopes{OfflineAccess: true, Groups: true}, req)
 	expectNil(t, err)
 
 	expectEquals(t, ident.UserID, testEmail)
@@ -106,21 +94,45 @@ func TestSingleGroup(t *testing.T) {
 }
 
 func TestMultipleGroup(t *testing.T) {
+	config := Config{}
+
+	conn, _ := config.Open("test", logger)
+	callback := conn.(*callback)
+
+	req, err := http.NewRequest("GET", "/", nil)
+	expectNil(t, err)
+	req.Header = map[string][]string{
+		"X-Remote-User":  {testEmail},
+		"X-Remote-Group": {testGroup1 + ", " + testGroup2 + ", " + testGroup3 + ", " + testGroup4},
+	}
+
+	ident, err := callback.HandleCallback(connector.Scopes{OfflineAccess: true, Groups: true}, req)
+	expectNil(t, err)
+
+	expectEquals(t, ident.UserID, testEmail)
+	expectEquals(t, len(ident.Groups), 4)
+	expectEquals(t, ident.Groups[0], testGroup1)
+	expectEquals(t, ident.Groups[1], testGroup2)
+	expectEquals(t, ident.Groups[2], testGroup3)
+	expectEquals(t, ident.Groups[3], testGroup4)
+}
+
+func TestMultipleGroupWithCustomSeparator(t *testing.T) {
 	config := Config{
-		UserHeader:  "X-Remote-User",
-		GroupHeader: "X-Remote-Group",
+		GroupHeaderSeparator: ";",
 	}
 
-	conn := callback{userHeader: config.UserHeader, groupHeader: config.GroupHeader, logger: logger, pathSuffix: "/test"}
+	conn, _ := config.Open("test", logger)
+	callback := conn.(*callback)
 
 	req, err := http.NewRequest("GET", "/", nil)
 	expectNil(t, err)
 	req.Header = map[string][]string{
 		"X-Remote-User":  {testEmail},
-		"X-Remote-Group": {testGroup1 + ", " + testGroup2 + ", " + testGroup3 + ", " + testGroup4},
+		"X-Remote-Group": {testGroup1 + ";" + testGroup2 + ";" + testGroup3 + ";" + testGroup4},
 	}
 
-	ident, err := conn.HandleCallback(connector.Scopes{OfflineAccess: true, Groups: true}, req)
+	ident, err := callback.HandleCallback(connector.Scopes{OfflineAccess: true, Groups: true}, req)
 	expectNil(t, err)
 
 	expectEquals(t, ident.UserID, testEmail)
@@ -133,12 +145,11 @@ func TestMultipleGroup(t *testing.T) {
 
 func TestStaticGroup(t *testing.T) {
 	config := Config{
-		UserHeader:  "X-Remote-User",
-		GroupHeader: "X-Remote-Group",
-		Groups:      []string{"static1", "static 2"},
+		Groups: []string{"static1", "static 2"},
 	}
 
-	conn := callback{userHeader: config.UserHeader, groupHeader: config.GroupHeader, groups: config.Groups, logger: logger, pathSuffix: "/test"}
+	conn, _ := config.Open("test", logger)
+	callback := conn.(*callback)
 
 	req, err := http.NewRequest("GET", "/", nil)
 	expectNil(t, err)
@@ -147,7 +158,7 @@ func TestStaticGroup(t *testing.T) {
 		"X-Remote-Group": {testGroup1 + ", " + testGroup2 + ", " + testGroup3 + ", " + testGroup4},
 	}
 
-	ident, err := conn.HandleCallback(connector.Scopes{OfflineAccess: true, Groups: true}, req)
+	ident, err := callback.HandleCallback(connector.Scopes{OfflineAccess: true, Groups: true}, req)
 	expectNil(t, err)
 
 	expectEquals(t, ident.UserID, testEmail)
diff --git a/server/api_test.go b/server/api_test.go
index 10242155..b61e15d3 100644
--- a/server/api_test.go
+++ b/server/api_test.go
@@ -733,3 +733,100 @@ func TestMissingConnectorsCRUDFeatureFlag(t *testing.T) {
 		t.Fatal("ListConnectors should have returned an error")
 	}
 }
+
+func TestListClients(t *testing.T) {
+	logger := slog.New(slog.DiscardHandler)
+
+	s := memory.New(logger)
+	client := newAPI(s, logger, t)
+	defer client.Close()
+
+	ctx := context.Background()
+
+	// List Clients
+	listResp, err := client.ListClients(ctx, &api.ListClientReq{})
+	if err != nil {
+		t.Fatalf("Unable to list clients: %v", err)
+	}
+	if len(listResp.Clients) != 0 {
+		t.Fatalf("Expected 0 clients, got %d", len(listResp.Clients))
+	}
+
+	client1 := &api.Client{
+		Id:           "client1",
+		Secret:       "secret1",
+		RedirectUris: []string{"http://localhost:8080/callback"},
+		TrustedPeers: []string{"peer1"},
+		Public:       false,
+		Name:         "Test Client 1",
+		LogoUrl:      "http://example.com/logo1.png",
+	}
+
+	client2 := &api.Client{
+		Id:           "client2",
+		Secret:       "secret2",
+		RedirectUris: []string{"http://localhost:8081/callback"},
+		TrustedPeers: []string{"peer2"},
+		Public:       true,
+		Name:         "Test Client 2",
+		LogoUrl:      "http://example.com/logo2.png",
+	}
+
+	_, err = client.CreateClient(ctx, &api.CreateClientReq{Client: client1})
+	if err != nil {
+		t.Fatalf("Unable to create client1: %v", err)
+	}
+
+	_, err = client.CreateClient(ctx, &api.CreateClientReq{Client: client2})
+	if err != nil {
+		t.Fatalf("Unable to create client2: %v", err)
+	}
+
+	listResp, err = client.ListClients(ctx, &api.ListClientReq{})
+	if err != nil {
+		t.Fatalf("Unable to list clients: %v", err)
+	}
+
+	if len(listResp.Clients) != 2 {
+		t.Fatalf("Expected 2 clients, got %d", len(listResp.Clients))
+	}
+
+	clientMap := make(map[string]*api.ClientInfo)
+	for _, c := range listResp.Clients {
+		clientMap[c.Id] = c
+	}
+
+	if c1, exists := clientMap["client1"]; !exists {
+		t.Fatal("client1 not found in list")
+	} else {
+		if c1.Name != "Test Client 1" {
+			t.Errorf("Expected client1 name 'Test Client 1', got '%s'", c1.Name)
+		}
+		if len(c1.RedirectUris) != 1 || c1.RedirectUris[0] != "http://localhost:8080/callback" {
+			t.Errorf("Expected client1 redirect URIs ['http://localhost:8080/callback'], got %v", c1.RedirectUris)
+		}
+		if c1.Public != false {
+			t.Errorf("Expected client1 public false, got %v", c1.Public)
+		}
+		if c1.LogoUrl != "http://example.com/logo1.png" {
+			t.Errorf("Expected client1 logo URL 'http://example.com/logo1.png', got '%s'", c1.LogoUrl)
+		}
+	}
+
+	if c2, exists := clientMap["client2"]; !exists {
+		t.Fatal("client2 not found in list")
+	} else {
+		if c2.Name != "Test Client 2" {
+			t.Errorf("Expected client2 name 'Test Client 2', got '%s'", c2.Name)
+		}
+		if len(c2.RedirectUris) != 1 || c2.RedirectUris[0] != "http://localhost:8081/callback" {
+			t.Errorf("Expected client2 redirect URIs ['http://localhost:8081/callback'], got %v", c2.RedirectUris)
+		}
+		if c2.Public != true {
+			t.Errorf("Expected client2 public true, got %v", c2.Public)
+		}
+		if c2.LogoUrl != "http://example.com/logo2.png" {
+			t.Errorf("Expected client2 logo URL 'http://example.com/logo2.png', got '%s'", c2.LogoUrl)
+		}
+	}
+}
diff --git a/server/deviceflowhandlers_test.go b/server/deviceflowhandlers_test.go
index 151c7508..2b4fbbfa 100644
--- a/server/deviceflowhandlers_test.go
+++ b/server/deviceflowhandlers_test.go
@@ -90,6 +90,14 @@ func TestHandleDeviceCode(t *testing.T) {
 			expectedResponseCode: http.StatusBadRequest,
 			expectedContentType:  "application/json",
 		},
+		{
+			testName:             "New Code without scope",
+			clientID:             "test",
+			requestType:          "POST",
+			scopes:               []string{},
+			expectedResponseCode: http.StatusOK,
+			expectedContentType:  "application/json",
+		},
 	}
 	for _, tc := range tests {
 		t.Run(tc.testName, func(t *testing.T) {
@@ -459,7 +467,7 @@ func TestDeviceTokenResponse(t *testing.T) {
 			},
 			testDeviceCode:         "f00bar",
 			expectedServerResponse: deviceTokenPending,
-			expectedResponseCode:   http.StatusUnauthorized,
+			expectedResponseCode:   http.StatusBadRequest,
 		},
 		{
 			testName:          "Invalid Grant Type",