mcp: client registration/token fixes (#5649)

## Summary

Fixes to MCP code registration and token requests. 

1. ease some requirements on fields that are RECOMMENDED 
2. fill in defaults
3. store both request and response in the client registration
4. check client secret in the /token request

## Related issues

- Fixes
https://linear.app/pomerium/issue/ENG-2462/mcp-ignore-unknown-grant-types-in-the-client-registration
- Fixes
https://linear.app/pomerium/issue/ENG-2461/mcp-support-client-secret-in-dynamic-client-registration
 
## User Explanation

<!-- How would you explain this change to the user? If this
change doesn't create any user-facing changes, you can leave
this blank. If filled out, add the `docs` label -->

## Checklist

- [x] reference any related issues
- [x] updated unit tests
- [x] add appropriate label (`enhancement`, `bug`, `breaking`,
`dependencies`, `ci`)
- [ ] ready for review
This commit is contained in:
Denis Mishin 2025-06-11 08:28:24 -07:00 committed by GitHub
parent 200f2e8164
commit 777b3b12d2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 1440 additions and 461 deletions

View file

@ -74,8 +74,8 @@ func (srv *Handler) Authorize(w http.ResponseWriter, r *http.Request) {
return return
} }
if err := oauth21.ValidateAuthorizationRequest(client, v); err != nil { if err := oauth21.ValidateAuthorizationRequest(client.ResponseMetadata, v); err != nil {
log.Ctx(ctx).Error().Err(err).Msg("failed to validate authorization request") log.Ctx(ctx).Error().Err(err).Msg("failed to validate authorization request for a client")
ve := oauth21.Error{Code: oauth21.InvalidRequest} ve := oauth21.Error{Code: oauth21.InvalidRequest}
_ = errors.As(err, &ve) _ = errors.As(err, &ve)
oauth21.ErrorResponse(w, http.StatusBadRequest, ve.Code) oauth21.ErrorResponse(w, http.StatusBadRequest, ve.Code)

View file

@ -119,7 +119,7 @@ func getAuthorizationServerMetadata(host, prefix string) AuthorizationServerMeta
ResponseTypesSupported: []string{"code"}, ResponseTypesSupported: []string{"code"},
CodeChallengeMethodsSupported: []string{"S256"}, CodeChallengeMethodsSupported: []string{"S256"},
TokenEndpoint: P(path.Join(prefix, tokenEndpoint)), TokenEndpoint: P(path.Join(prefix, tokenEndpoint)),
TokenEndpointAuthMethodsSupported: []string{"none"}, TokenEndpointAuthMethodsSupported: []string{"client_secret_basic", "none"},
GrantTypesSupported: []string{"authorization_code", "refresh_token"}, GrantTypesSupported: []string{"authorization_code", "refresh_token"},
RevocationEndpoint: P(path.Join(prefix, revocationEndpoint)), RevocationEndpoint: P(path.Join(prefix, revocationEndpoint)),
RevocationEndpointAuthMethodsSupported: []string{"client_secret_post"}, RevocationEndpointAuthMethodsSupported: []string{"client_secret_post"},

View file

@ -2,15 +2,16 @@ package mcp
import ( import (
"encoding/json" "encoding/json"
"fmt"
"io" "io"
"net/http" "net/http"
"time"
"github.com/bufbuild/protovalidate-go" "google.golang.org/protobuf/proto"
"google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/types/known/timestamppb"
"github.com/pomerium/pomerium/internal/log" "github.com/pomerium/pomerium/internal/log"
rfc7591v1 "github.com/pomerium/pomerium/internal/rfc7591" rfc7591v1 "github.com/pomerium/pomerium/internal/rfc7591"
"github.com/pomerium/pomerium/pkg/cryptutil"
) )
const maxClientRegistrationPayload = 1024 * 1024 // 1MB const maxClientRegistrationPayload = 1024 * 1024 // 1MB
@ -34,44 +35,24 @@ func (srv *Handler) RegisterClient(w http.ResponseWriter, r *http.Request) {
return return
} }
v := new(rfc7591v1.ClientMetadata) clientRegistration, err := createClientRegistrationFromMetadata(data)
err = protojson.UnmarshalOptions{DiscardUnknown: true}.Unmarshal(data, v)
if err != nil { if err != nil {
log.Ctx(ctx).Error().Err(err).Msg("failed to unmarshal request body") log.Ctx(ctx).Error().
http.Error(w, "failed to unmarshal request body", http.StatusBadRequest) Str("request", string(data)).
return Err(err).Msg("create client registration")
}
err = protovalidate.Validate(v)
if err != nil {
log.Ctx(ctx).Error().Err(err).Msg("failed to validate request body")
clientRegistrationBadRequest(w, err) clientRegistrationBadRequest(w, err)
return return
} }
id, err := srv.storage.RegisterClient(ctx, v) id, err := srv.storage.RegisterClient(ctx, clientRegistration)
if err != nil { if err != nil {
log.Ctx(ctx).Error().Err(err).Msg("failed to register client") log.Ctx(ctx).Error().Err(err).Msg("failed to register client")
http.Error(w, "failed to register client", http.StatusInternalServerError) http.Error(w, "failed to register client", http.StatusInternalServerError)
} }
resp := struct {
*rfc7591v1.ClientMetadata
ClientID string `json:"client_id"`
ClientIDIssuedAt int64 `json:"client_id_issued_at"`
}{
ClientMetadata: v,
ClientID: id,
ClientIDIssuedAt: time.Now().Unix(),
}
data, err = json.Marshal(resp)
if err != nil {
log.Ctx(ctx).Error().Err(err).Msg("failed to marshal response")
http.Error(w, "failed to marshal response", http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
_, err = w.Write(data) err = rfc7591v1.WriteRegistrationResponse(w, id,
clientRegistration.ClientSecret, clientRegistration.ResponseMetadata)
if err != nil { if err != nil {
log.Ctx(ctx).Error().Err(err).Msg("failed to write response") log.Ctx(ctx).Error().Err(err).Msg("failed to write response")
return return
@ -93,3 +74,34 @@ func clientRegistrationBadRequest(w http.ResponseWriter, err error) {
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
_, _ = w.Write(data) _, _ = w.Write(data)
} }
func createClientRegistrationFromMetadata(
requestMetadataText []byte,
) (*rfc7591v1.ClientRegistration, error) {
requestMetadata, err := rfc7591v1.ParseMetadata(requestMetadataText)
if err != nil {
return nil, fmt.Errorf("parse: %w", err)
}
err = requestMetadata.Validate()
if err != nil {
return nil, fmt.Errorf("validate: %w", err)
}
responseMetadata := proto.CloneOf(requestMetadata)
responseMetadata.SetDefaults()
registration := &rfc7591v1.ClientRegistration{
RequestMetadata: requestMetadata,
ResponseMetadata: responseMetadata,
}
if requestMetadata.GetTokenEndpointAuthMethod() != rfc7591v1.TokenEndpointAuthMethodNone {
registration.ClientSecret = &rfc7591v1.ClientSecret{
Value: cryptutil.NewRandomStringN(32),
CreatedAt: timestamppb.Now(),
}
}
return registration, nil
}

View file

@ -2,6 +2,7 @@ package mcp
import ( import (
"encoding/json" "encoding/json"
"fmt"
"net/http" "net/http"
"time" "time"
@ -12,6 +13,7 @@ import (
"github.com/pomerium/pomerium/internal/log" "github.com/pomerium/pomerium/internal/log"
"github.com/pomerium/pomerium/internal/oauth21" "github.com/pomerium/pomerium/internal/oauth21"
oauth21proto "github.com/pomerium/pomerium/internal/oauth21/gen" oauth21proto "github.com/pomerium/pomerium/internal/oauth21/gen"
rfc7591v1 "github.com/pomerium/pomerium/internal/rfc7591"
) )
// Token handles the /token endpoint. // Token handles the /token endpoint.
@ -21,54 +23,65 @@ func (srv *Handler) Token(w http.ResponseWriter, r *http.Request) {
return return
} }
req, err := oauth21.ParseTokenRequest(r) ctx := r.Context()
req, err := srv.getTokenRequest(r)
if err != nil { if err != nil {
log.Ctx(r.Context()).Error().Err(err).Msg("failed to parse token request") log.Ctx(ctx).Error().Err(err).Msg("get token request failed")
oauth21.ErrorResponse(w, http.StatusBadRequest, oauth21.InvalidRequest) oauth21.ErrorResponse(w, http.StatusBadRequest, oauth21.InvalidRequest)
return return
} }
switch req.GrantType { switch req.GrantType {
case "authorization_code": case "authorization_code":
log.Ctx(ctx).Debug().Msg("handling authorization_code token request")
srv.handleAuthorizationCodeToken(w, r, req) srv.handleAuthorizationCodeToken(w, r, req)
default: default:
log.Ctx(ctx).Error().Msgf("unsupported grant type: %s", req.GrantType)
oauth21.ErrorResponse(w, http.StatusBadRequest, oauth21.UnsupportedGrantType) oauth21.ErrorResponse(w, http.StatusBadRequest, oauth21.UnsupportedGrantType)
return return
} }
} }
func (srv *Handler) handleAuthorizationCodeToken(w http.ResponseWriter, r *http.Request, req *oauth21proto.TokenRequest) { func (srv *Handler) handleAuthorizationCodeToken(w http.ResponseWriter, r *http.Request, tokenReq *oauth21proto.TokenRequest) {
ctx := r.Context() ctx := r.Context()
if req.ClientId == nil { if tokenReq.ClientId == nil {
log.Ctx(ctx).Error().Msg("missing client_id in token request")
oauth21.ErrorResponse(w, http.StatusBadRequest, oauth21.InvalidClient) oauth21.ErrorResponse(w, http.StatusBadRequest, oauth21.InvalidClient)
return return
} }
if req.Code == nil { if tokenReq.Code == nil {
log.Ctx(ctx).Error().Msg("missing code in token request")
oauth21.ErrorResponse(w, http.StatusBadRequest, oauth21.InvalidGrant) oauth21.ErrorResponse(w, http.StatusBadRequest, oauth21.InvalidGrant)
return return
} }
code, err := DecryptCode(CodeTypeAuthorization, *req.Code, srv.cipher, *req.ClientId, time.Now()) code, err := DecryptCode(CodeTypeAuthorization, *tokenReq.Code, srv.cipher, *tokenReq.ClientId, time.Now())
if err != nil { if err != nil {
log.Ctx(ctx).Error().Err(err).Msg("failed to decrypt authorization code")
oauth21.ErrorResponse(w, http.StatusBadRequest, oauth21.InvalidGrant) oauth21.ErrorResponse(w, http.StatusBadRequest, oauth21.InvalidGrant)
return return
} }
authReq, err := srv.storage.GetAuthorizationRequest(ctx, code.Id) authReq, err := srv.storage.GetAuthorizationRequest(ctx, code.Id)
if status.Code(err) == codes.NotFound { if status.Code(err) == codes.NotFound {
log.Ctx(ctx).Error().Msg("authorization request not found")
oauth21.ErrorResponse(w, http.StatusBadRequest, oauth21.InvalidGrant) oauth21.ErrorResponse(w, http.StatusBadRequest, oauth21.InvalidGrant)
return return
} }
if err != nil { if err != nil {
log.Ctx(ctx).Error().Err(err).Msg("failed to get authorization request and client")
http.Error(w, "internal error", http.StatusInternalServerError) http.Error(w, "internal error", http.StatusInternalServerError)
} }
if *req.ClientId != authReq.ClientId { if *tokenReq.ClientId != authReq.ClientId {
log.Ctx(ctx).Error().Msgf("client ID mismatch: %s != %s", *tokenReq.ClientId, authReq.ClientId)
oauth21.ErrorResponse(w, http.StatusBadRequest, oauth21.InvalidGrant) oauth21.ErrorResponse(w, http.StatusBadRequest, oauth21.InvalidGrant)
return
} }
err = CheckPKCE(authReq.GetCodeChallengeMethod(), authReq.GetCodeChallenge(), req.GetCodeVerifier()) err = CheckPKCE(authReq.GetCodeChallengeMethod(), authReq.GetCodeChallenge(), tokenReq.GetCodeVerifier())
if err != nil { if err != nil {
log.Ctx(ctx).Error().Err(err).Msg("failed to check PKCE")
oauth21.ErrorResponse(w, http.StatusBadRequest, oauth21.InvalidGrant) oauth21.ErrorResponse(w, http.StatusBadRequest, oauth21.InvalidGrant)
return return
} }
@ -77,24 +90,28 @@ func (srv *Handler) handleAuthorizationCodeToken(w http.ResponseWriter, r *http.
// https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-12#section-4.1.3 // https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-12#section-4.1.3
err = srv.storage.DeleteAuthorizationRequest(ctx, code.Id) err = srv.storage.DeleteAuthorizationRequest(ctx, code.Id)
if err != nil { if err != nil {
log.Ctx(ctx).Error().Err(err).Msg("failed to delete authorization request")
http.Error(w, "internal error", http.StatusInternalServerError) http.Error(w, "internal error", http.StatusInternalServerError)
return return
} }
session, err := srv.storage.GetSession(ctx, authReq.SessionId) session, err := srv.storage.GetSession(ctx, authReq.SessionId)
if status.Code(err) == codes.NotFound { if status.Code(err) == codes.NotFound {
log.Ctx(ctx).Error().Msg("session not found")
oauth21.ErrorResponse(w, http.StatusBadRequest, oauth21.InvalidGrant) oauth21.ErrorResponse(w, http.StatusBadRequest, oauth21.InvalidGrant)
return return
} }
accessToken, err := srv.GetAccessTokenForSession(session.Id, session.ExpiresAt.AsTime()) accessToken, err := srv.GetAccessTokenForSession(session.Id, session.ExpiresAt.AsTime())
if err != nil { if err != nil {
log.Ctx(ctx).Error().Err(err).Msg("failed to get access token for session")
http.Error(w, "internal error", http.StatusInternalServerError) http.Error(w, "internal error", http.StatusInternalServerError)
return return
} }
expiresIn := time.Until(session.ExpiresAt.AsTime()) expiresIn := time.Until(session.ExpiresAt.AsTime())
if expiresIn < 0 { if expiresIn < 0 {
log.Ctx(ctx).Error().Msg("session has already expired")
oauth21.ErrorResponse(w, http.StatusBadRequest, oauth21.InvalidGrant) oauth21.ErrorResponse(w, http.StatusBadRequest, oauth21.InvalidGrant)
return return
} }
@ -107,6 +124,7 @@ func (srv *Handler) handleAuthorizationCodeToken(w http.ResponseWriter, r *http.
data, err := json.Marshal(resp) // not using protojson.Marshal here because it emits numbers as strings, which is valid, but for some reason Node.js / mcp typescript SDK doesn't like it data, err := json.Marshal(resp) // not using protojson.Marshal here because it emits numbers as strings, which is valid, but for some reason Node.js / mcp typescript SDK doesn't like it
if err != nil { if err != nil {
log.Ctx(ctx).Error().Err(err).Msg("failed to marshal token response")
http.Error(w, "internal error", http.StatusInternalServerError) http.Error(w, "internal error", http.StatusInternalServerError)
return return
} }
@ -116,3 +134,46 @@ func (srv *Handler) handleAuthorizationCodeToken(w http.ResponseWriter, r *http.
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
_, _ = w.Write(data) _, _ = w.Write(data)
} }
func (srv *Handler) getTokenRequest(
r *http.Request,
) (*oauth21proto.TokenRequest, error) {
tokenReq, err := oauth21.ParseTokenRequest(r)
if err != nil {
return nil, fmt.Errorf("failed to parse token request: %w", err)
}
ctx := r.Context()
clientReg, err := srv.storage.GetClient(ctx, tokenReq.GetClientId())
if err != nil {
return nil, fmt.Errorf("failed to get client registration: %w", err)
}
m := clientReg.ResponseMetadata.GetTokenEndpointAuthMethod()
if m == rfc7591v1.TokenEndpointAuthMethodNone {
return tokenReq, nil
}
secret := clientReg.ClientSecret
if secret == nil {
return nil, fmt.Errorf("client registration does not have a client secret")
}
if expires := secret.ExpiresAt; expires != nil && expires.AsTime().Before(time.Now()) {
return nil, fmt.Errorf("client registration client secret has expired")
}
switch m {
case rfc7591v1.TokenEndpointAuthMethodClientSecretBasic:
case rfc7591v1.TokenEndpointAuthMethodClientSecretPost:
if tokenReq.ClientSecret == nil {
return nil, fmt.Errorf("client_secret was not provided")
}
if tokenReq.GetClientSecret() != secret.Value {
return nil, fmt.Errorf("client secret mismatch")
}
default:
return nil, fmt.Errorf("unsupported token endpoint authentication method: %s", m)
}
return tokenReq, nil
}

View file

@ -31,7 +31,7 @@ func NewStorage(
func (storage *Storage) RegisterClient( func (storage *Storage) RegisterClient(
ctx context.Context, ctx context.Context,
req *rfc7591v1.ClientMetadata, req *rfc7591v1.ClientRegistration,
) (string, error) { ) (string, error) {
data := protoutil.NewAny(req) data := protoutil.NewAny(req)
id := uuid.NewString() id := uuid.NewString()
@ -51,8 +51,8 @@ func (storage *Storage) RegisterClient(
func (storage *Storage) GetClient( func (storage *Storage) GetClient(
ctx context.Context, ctx context.Context,
id string, id string,
) (*rfc7591v1.ClientMetadata, error) { ) (*rfc7591v1.ClientRegistration, error) {
v := new(rfc7591v1.ClientMetadata) v := new(rfc7591v1.ClientRegistration)
rec, err := storage.client.Get(ctx, &databroker.GetRequest{ rec, err := storage.client.Get(ctx, &databroker.GetRequest{
Type: protoutil.GetTypeURL(v), Type: protoutil.GetTypeURL(v),
Id: id, Id: id,

View file

@ -62,7 +62,7 @@ func TestStorage(t *testing.T) {
t.Run("client registration", func(t *testing.T) { t.Run("client registration", func(t *testing.T) {
t.Parallel() t.Parallel()
id, err := storage.RegisterClient(ctx, &rfc7591v1.ClientMetadata{}) id, err := storage.RegisterClient(ctx, &rfc7591v1.ClientRegistration{})
require.NoError(t, err) require.NoError(t, err)
require.NotEmpty(t, id) require.NotEmpty(t, id)

View file

@ -20,7 +20,7 @@ func ParseCodeGrantAuthorizeRequest(r *http.Request) (*gen.AuthorizationRequest,
RedirectUri: optionalFormParam(r, "redirect_uri"), RedirectUri: optionalFormParam(r, "redirect_uri"),
ResponseType: r.Form.Get("response_type"), ResponseType: r.Form.Get("response_type"),
State: optionalFormParam(r, "state"), State: optionalFormParam(r, "state"),
CodeChallenge: r.Form.Get("code_challenge"), CodeChallenge: optionalFormParam(r, "code_challenge"),
CodeChallengeMethod: optionalFormParam(r, "code_challenge_method"), CodeChallengeMethod: optionalFormParam(r, "code_challenge_method"),
} }

View file

@ -2,5 +2,5 @@
version: v2 version: v2
deps: deps:
- name: buf.build/bufbuild/protovalidate - name: buf.build/bufbuild/protovalidate
commit: 8976f5be98c146529b1cc15cd2012b60 commit: b52ab10f44684cb19d1fbcad56aedd36
digest: b5:5d513af91a439d9e78cacac0c9455c7cb885a8737d30405d0b91974fe05276d19c07a876a51a107213a3d01b83ecc912996cdad4cddf7231f91379079cf7488d digest: b5:5f464399f5ea7546eb3c6a4e822a306da538298f3d87e9f974f4523d4955de396eb2b8b52a2f3f06ac290764d80cecbaa0a4c96560558e43d9b1c722e61a9d5c

View file

@ -43,8 +43,9 @@ type AuthorizationRequest struct {
State *string `protobuf:"bytes,4,opt,name=state,proto3,oneof" json:"state,omitempty"` State *string `protobuf:"bytes,4,opt,name=state,proto3,oneof" json:"state,omitempty"`
// OPTIONAL. The scope of the access request as described by Section 1.4.1. // OPTIONAL. The scope of the access request as described by Section 1.4.1.
Scopes []string `protobuf:"bytes,5,rep,name=scopes,proto3" json:"scopes,omitempty"` Scopes []string `protobuf:"bytes,5,rep,name=scopes,proto3" json:"scopes,omitempty"`
// REQUIRED, assumes https://www.rfc-editor.org/rfc/rfc7636.html#section-4.1 // REQUIRED or RECOMMENDED, assumes https://www.rfc-editor.org/rfc/rfc7636.html#section-4.1
CodeChallenge string `protobuf:"bytes,6,opt,name=code_challenge,json=codeChallenge,proto3" json:"code_challenge,omitempty"` // subject to whether the client is public or confidential.
CodeChallenge *string `protobuf:"bytes,6,opt,name=code_challenge,json=codeChallenge,proto3,oneof" json:"code_challenge,omitempty"`
// OPTIONAL, defaults to plain if not present in the request. Code verifier // OPTIONAL, defaults to plain if not present in the request. Code verifier
// transformation method is S256 or plain. // transformation method is S256 or plain.
CodeChallengeMethod *string `protobuf:"bytes,7,opt,name=code_challenge_method,json=codeChallengeMethod,proto3,oneof" json:"code_challenge_method,omitempty"` CodeChallengeMethod *string `protobuf:"bytes,7,opt,name=code_challenge_method,json=codeChallengeMethod,proto3,oneof" json:"code_challenge_method,omitempty"`
@ -124,8 +125,8 @@ func (x *AuthorizationRequest) GetScopes() []string {
} }
func (x *AuthorizationRequest) GetCodeChallenge() string { func (x *AuthorizationRequest) GetCodeChallenge() string {
if x != nil { if x != nil && x.CodeChallenge != nil {
return x.CodeChallenge return *x.CodeChallenge
} }
return "" return ""
} }
@ -158,7 +159,7 @@ var file_authorization_request_proto_rawDesc = string([]byte{
0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x07, 0x6f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x07, 0x6f,
0x61, 0x75, 0x74, 0x68, 0x32, 0x31, 0x1a, 0x1b, 0x62, 0x75, 0x66, 0x2f, 0x76, 0x61, 0x6c, 0x69, 0x61, 0x75, 0x74, 0x68, 0x32, 0x31, 0x1a, 0x1b, 0x62, 0x75, 0x66, 0x2f, 0x76, 0x61, 0x6c, 0x69,
0x64, 0x61, 0x74, 0x65, 0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x72, 0x64, 0x61, 0x74, 0x65, 0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x22, 0xcb, 0x03, 0x0a, 0x14, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x6f, 0x74, 0x6f, 0x22, 0xe0, 0x03, 0x0a, 0x14, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x23, 0x0a, 0x09, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x23, 0x0a, 0x09,
0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42,
0x06, 0xba, 0x48, 0x03, 0xc8, 0x01, 0x01, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x06, 0xba, 0x48, 0x03, 0xc8, 0x01, 0x01, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49,
@ -171,33 +172,34 @@ var file_authorization_request_proto_rawDesc = string([]byte{
0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52,
0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x88, 0x01, 0x01, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x63, 0x6f, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x88, 0x01, 0x01, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x63, 0x6f,
0x70, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x70, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x73, 0x63, 0x6f, 0x70, 0x65,
0x73, 0x12, 0x34, 0x0a, 0x0e, 0x63, 0x6f, 0x64, 0x65, 0x5f, 0x63, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x73, 0x12, 0x36, 0x0a, 0x0e, 0x63, 0x6f, 0x64, 0x65, 0x5f, 0x63, 0x68, 0x61, 0x6c, 0x6c, 0x65,
0x6e, 0x67, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0d, 0xba, 0x48, 0x0a, 0xc8, 0x01, 0x6e, 0x67, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xba, 0x48, 0x07, 0x72, 0x05,
0x01, 0x72, 0x05, 0x10, 0x2b, 0x18, 0x80, 0x01, 0x52, 0x0d, 0x63, 0x6f, 0x64, 0x65, 0x43, 0x68, 0x10, 0x2b, 0x18, 0x80, 0x01, 0x48, 0x02, 0x52, 0x0d, 0x63, 0x6f, 0x64, 0x65, 0x43, 0x68, 0x61,
0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x12, 0x4b, 0x0a, 0x15, 0x63, 0x6f, 0x64, 0x65, 0x5f, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x88, 0x01, 0x01, 0x12, 0x4b, 0x0a, 0x15, 0x63, 0x6f, 0x64,
0x63, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x65, 0x5f, 0x63, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x68,
0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x42, 0x12, 0xba, 0x48, 0x0f, 0x72, 0x0d, 0x52, 0x04, 0x53, 0x6f, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x42, 0x12, 0xba, 0x48, 0x0f, 0x72, 0x0d, 0x52,
0x32, 0x35, 0x36, 0x52, 0x05, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x48, 0x02, 0x52, 0x13, 0x63, 0x6f, 0x04, 0x53, 0x32, 0x35, 0x36, 0x52, 0x05, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x48, 0x03, 0x52, 0x13,
0x64, 0x65, 0x43, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x63, 0x6f, 0x64, 0x65, 0x43, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x4d, 0x65, 0x74,
0x64, 0x88, 0x01, 0x01, 0x12, 0x25, 0x0a, 0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x68, 0x6f, 0x64, 0x88, 0x01, 0x01, 0x12, 0x25, 0x0a, 0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f,
0x69, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x42, 0x06, 0xba, 0x48, 0x03, 0xc8, 0x01, 0x01, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x42, 0x06, 0xba, 0x48, 0x03, 0xc8,
0x52, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x07, 0x75, 0x01, 0x01, 0x52, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x1f, 0x0a,
0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x42, 0x06, 0xba, 0x48, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x42, 0x06,
0x03, 0xc8, 0x01, 0x01, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x42, 0x0f, 0x0a, 0x0d, 0xba, 0x48, 0x03, 0xc8, 0x01, 0x01, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x42, 0x0f,
0x5f, 0x72, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x5f, 0x75, 0x72, 0x69, 0x42, 0x08, 0x0a, 0x0a, 0x0d, 0x5f, 0x72, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x5f, 0x75, 0x72, 0x69, 0x42,
0x06, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x42, 0x18, 0x0a, 0x16, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x08, 0x0a, 0x06, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x42, 0x11, 0x0a, 0x0f, 0x5f, 0x63, 0x6f,
0x5f, 0x63, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x65, 0x5f, 0x63, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x42, 0x18, 0x0a, 0x16,
0x64, 0x42, 0x97, 0x01, 0x0a, 0x0b, 0x63, 0x6f, 0x6d, 0x2e, 0x6f, 0x61, 0x75, 0x74, 0x68, 0x32, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x5f, 0x63, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x5f,
0x31, 0x42, 0x19, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x42, 0x97, 0x01, 0x0a, 0x0b, 0x63, 0x6f, 0x6d, 0x2e, 0x6f,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x31, 0x61, 0x75, 0x74, 0x68, 0x32, 0x31, 0x42, 0x19, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a,
0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x6f, 0x6d, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x74,
0x69, 0x75, 0x6d, 0x2f, 0x70, 0x6f, 0x6d, 0x65, 0x72, 0x69, 0x75, 0x6d, 0x2f, 0x69, 0x6e, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x31, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x6f, 0x61, 0x75, 0x74, 0x68, 0x32, 0x31, 0x2f, 0x67, 0x65, 0x70, 0x6f, 0x6d, 0x65, 0x72, 0x69, 0x75, 0x6d, 0x2f, 0x70, 0x6f, 0x6d, 0x65, 0x72, 0x69, 0x75,
0x6e, 0xa2, 0x02, 0x03, 0x4f, 0x58, 0x58, 0xaa, 0x02, 0x07, 0x4f, 0x61, 0x75, 0x74, 0x68, 0x32, 0x6d, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x6f, 0x61, 0x75, 0x74, 0x68,
0x31, 0xca, 0x02, 0x07, 0x4f, 0x61, 0x75, 0x74, 0x68, 0x32, 0x31, 0xe2, 0x02, 0x13, 0x4f, 0x61, 0x32, 0x31, 0x2f, 0x67, 0x65, 0x6e, 0xa2, 0x02, 0x03, 0x4f, 0x58, 0x58, 0xaa, 0x02, 0x07, 0x4f,
0x75, 0x74, 0x68, 0x32, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x75, 0x74, 0x68, 0x32, 0x31, 0xca, 0x02, 0x07, 0x4f, 0x61, 0x75, 0x74, 0x68, 0x32, 0x31,
0x61, 0xea, 0x02, 0x07, 0x4f, 0x61, 0x75, 0x74, 0x68, 0x32, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0xe2, 0x02, 0x13, 0x4f, 0x61, 0x75, 0x74, 0x68, 0x32, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65,
0x74, 0x6f, 0x33, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x07, 0x4f, 0x61, 0x75, 0x74, 0x68, 0x32, 0x31,
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}) })
var ( var (

View file

@ -34,10 +34,10 @@ message AuthorizationRequest {
// OPTIONAL. The scope of the access request as described by Section 1.4.1. // OPTIONAL. The scope of the access request as described by Section 1.4.1.
repeated string scopes = 5; repeated string scopes = 5;
// REQUIRED, assumes https://www.rfc-editor.org/rfc/rfc7636.html#section-4.1 // REQUIRED or RECOMMENDED, assumes https://www.rfc-editor.org/rfc/rfc7636.html#section-4.1
string code_challenge = 6 [ // subject to whether the client is public or confidential.
(buf.validate.field).required = true, optional string code_challenge = 6 [
(buf.validate.field).string = {min_len: 43, max_len: 128} (buf.validate.field).string = {min_len: 43, max_len: 128}
]; ];
// OPTIONAL, defaults to plain if not present in the request. Code verifier // OPTIONAL, defaults to plain if not present in the request. Code verifier

View file

@ -15,6 +15,9 @@ func ParseTokenRequest(r *http.Request) (*gen.TokenRequest, error) {
return nil, fmt.Errorf("failed to parse form: %w", err) return nil, fmt.Errorf("failed to parse form: %w", err)
} }
// extract client credentials from HTTP Basic Authorization header, if present
basicID, basicSecret, basicOK := r.BasicAuth()
v := &gen.TokenRequest{ v := &gen.TokenRequest{
GrantType: r.Form.Get("grant_type"), GrantType: r.Form.Get("grant_type"),
Code: optionalFormParam(r, "code"), Code: optionalFormParam(r, "code"),
@ -25,6 +28,15 @@ func ParseTokenRequest(r *http.Request) (*gen.TokenRequest, error) {
ClientSecret: optionalFormParam(r, "client_secret"), ClientSecret: optionalFormParam(r, "client_secret"),
} }
if basicOK {
if v.ClientId == nil && basicID != "" {
v.ClientId = &basicID
}
if v.ClientSecret == nil && basicSecret != "" {
v.ClientSecret = &basicSecret
}
}
err = protovalidate.Validate(v) err = protovalidate.Validate(v)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to validate token request: %w", err) return nil, fmt.Errorf("failed to validate token request: %w", err)

View file

@ -0,0 +1,48 @@
package oauth21_test
import (
"net/http"
"net/url"
"strings"
"testing"
"github.com/stretchr/testify/require"
"github.com/pomerium/pomerium/internal/oauth21"
)
func TestParseTokenRequest_BasicAuth(t *testing.T) {
form := url.Values{}
form.Set("grant_type", "authorization_code")
form.Set("code", "abc")
req, err := http.NewRequest(http.MethodPost, "/token", strings.NewReader(form.Encode()))
require.NoError(t, err)
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
req.SetBasicAuth("myclient", "secret")
tr, err := oauth21.ParseTokenRequest(req)
require.NoError(t, err)
require.NotNil(t, tr.ClientId)
require.Equal(t, "myclient", *tr.ClientId)
require.NotNil(t, tr.ClientSecret)
require.Equal(t, "secret", *tr.ClientSecret)
}
func TestParseTokenRequest_BasicAuthWithBodyOverride(t *testing.T) {
form := url.Values{}
form.Set("grant_type", "authorization_code")
form.Set("code", "abc")
form.Set("client_id", "bodyid")
form.Set("client_secret", "bodysecret")
req, err := http.NewRequest(http.MethodPost, "/token", strings.NewReader(form.Encode()))
require.NoError(t, err)
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
req.SetBasicAuth("basicid", "basicsecret")
tr, err := oauth21.ParseTokenRequest(req)
require.NoError(t, err)
require.NotNil(t, tr.ClientId)
require.Equal(t, "bodyid", *tr.ClientId) // body should win
require.NotNil(t, tr.ClientSecret)
require.Equal(t, "bodysecret", *tr.ClientSecret)
}

View file

@ -1,6 +1,7 @@
package oauth21 package oauth21
import ( import (
"fmt"
"slices" "slices"
"github.com/pomerium/pomerium/internal/oauth21/gen" "github.com/pomerium/pomerium/internal/oauth21/gen"
@ -8,17 +9,45 @@ import (
) )
func ValidateAuthorizationRequest( func ValidateAuthorizationRequest(
client *rfc7591v1.ClientMetadata, client *rfc7591v1.Metadata,
req *gen.AuthorizationRequest, req *gen.AuthorizationRequest,
) error { ) error {
if err := ValidateAuthorizationRequestRedirectURI(client, req.RedirectUri); err != nil { if err := ValidateAuthorizationRequestRedirectURI(client, req.RedirectUri); err != nil {
return err return err
} }
if err := ValidateAuthorizationRequestCodeChallenge(client, req); err != nil {
return err
}
return nil
}
func ValidateAuthorizationRequestCodeChallenge(
client *rfc7591v1.Metadata,
req *gen.AuthorizationRequest,
) error {
m := client.GetTokenEndpointAuthMethod()
switch m {
case rfc7591v1.TokenEndpointAuthMethodNone:
if req.GetCodeChallenge() == "" {
return Error{
Code: InvalidRequest,
Description: "code challenge are required when token endpoint auth method is 'none'",
}
}
case rfc7591v1.TokenEndpointAuthMethodClientSecretBasic,
rfc7591v1.TokenEndpointAuthMethodClientSecretPost:
// code challenge is recommended but not required for these methods
default:
return Error{
Code: InvalidRequest,
Description: fmt.Sprintf("unsupported token endpoint auth method: %s", m),
}
}
return nil return nil
} }
func ValidateAuthorizationRequestRedirectURI( func ValidateAuthorizationRequestRedirectURI(
client *rfc7591v1.ClientMetadata, client *rfc7591v1.Metadata,
redirectURI *string, redirectURI *string,
) error { ) error {
if len(client.RedirectUris) == 0 { if len(client.RedirectUris) == 0 {

View file

@ -13,17 +13,67 @@ import (
func TestValidateRequest(t *testing.T) { func TestValidateRequest(t *testing.T) {
t.Parallel() t.Parallel()
clientBasic := rfc7591v1.TokenEndpointAuthMethodClientSecretBasic
clientNone := rfc7591v1.TokenEndpointAuthMethodNone
for _, tc := range []struct { for _, tc := range []struct {
name string name string
client *rfc7591v1.ClientMetadata client *rfc7591v1.Metadata
req *gen.AuthorizationRequest req *gen.AuthorizationRequest
err bool err bool
}{ }{
{ {
"optional redirect_uri, multiple redirect_uris", "default token auth method, no code challenge",
&rfc7591v1.ClientMetadata{ &rfc7591v1.Metadata{
RedirectUris: []string{"https://example.com/callback", "https://example.com/other-callback"}, RedirectUris: []string{"https://example.com/callback", "https://example.com/other-callback"},
}, },
&gen.AuthorizationRequest{
RedirectUri: proto.String("https://example.com/callback"),
},
true,
},
{
"none token auth method, no code challenge",
&rfc7591v1.Metadata{
RedirectUris: []string{"https://example.com/callback", "https://example.com/other-callback"},
TokenEndpointAuthMethod: &clientNone,
},
&gen.AuthorizationRequest{
RedirectUri: proto.String("https://example.com/callback"),
},
true,
},
{
"none token auth method, code challenge is provided",
&rfc7591v1.Metadata{
RedirectUris: []string{"https://example.com/callback", "https://example.com/other-callback"},
TokenEndpointAuthMethod: &clientNone,
},
&gen.AuthorizationRequest{
RedirectUri: proto.String("https://example.com/callback"),
CodeChallenge: proto.String("challenge"),
},
false,
},
{
"none token auth method, code challenge and method are provided",
&rfc7591v1.Metadata{
RedirectUris: []string{"https://example.com/callback", "https://example.com/other-callback"},
TokenEndpointAuthMethod: &clientNone,
},
&gen.AuthorizationRequest{
RedirectUri: proto.String("https://example.com/callback"),
CodeChallenge: proto.String("challenge"),
CodeChallengeMethod: proto.String("S256"),
},
false,
},
{
"optional redirect_uri, multiple redirect_uris",
&rfc7591v1.Metadata{
RedirectUris: []string{"https://example.com/callback", "https://example.com/other-callback"},
TokenEndpointAuthMethod: &clientBasic,
},
&gen.AuthorizationRequest{ &gen.AuthorizationRequest{
RedirectUri: nil, RedirectUri: nil,
}, },
@ -31,8 +81,9 @@ func TestValidateRequest(t *testing.T) {
}, },
{ {
"optional redirect_uri, single redirect_uri", "optional redirect_uri, single redirect_uri",
&rfc7591v1.ClientMetadata{ &rfc7591v1.Metadata{
RedirectUris: []string{"https://example.com/callback"}, RedirectUris: []string{"https://example.com/callback"},
TokenEndpointAuthMethod: &clientBasic,
}, },
&gen.AuthorizationRequest{ &gen.AuthorizationRequest{
RedirectUri: nil, RedirectUri: nil,
@ -41,8 +92,9 @@ func TestValidateRequest(t *testing.T) {
}, },
{ {
"matching redirect_uri", "matching redirect_uri",
&rfc7591v1.ClientMetadata{ &rfc7591v1.Metadata{
RedirectUris: []string{"https://example.com/callback", "https://example.com/other-callback"}, RedirectUris: []string{"https://example.com/callback", "https://example.com/other-callback"},
TokenEndpointAuthMethod: &clientBasic,
}, },
&gen.AuthorizationRequest{ &gen.AuthorizationRequest{
RedirectUri: proto.String("https://example.com/callback"), RedirectUri: proto.String("https://example.com/callback"),
@ -51,8 +103,9 @@ func TestValidateRequest(t *testing.T) {
}, },
{ {
"non-matching redirect_uri", "non-matching redirect_uri",
&rfc7591v1.ClientMetadata{ &rfc7591v1.Metadata{
RedirectUris: []string{"https://example.com/callback", "https://example.com/other-callback"}, RedirectUris: []string{"https://example.com/callback", "https://example.com/other-callback"},
TokenEndpointAuthMethod: &clientBasic,
}, },
&gen.AuthorizationRequest{ &gen.AuthorizationRequest{
RedirectUri: proto.String("https://example.com/invalid-callback"), RedirectUri: proto.String("https://example.com/invalid-callback"),

View file

@ -2,5 +2,5 @@
version: v2 version: v2
deps: deps:
- name: buf.build/bufbuild/protovalidate - name: buf.build/bufbuild/protovalidate
commit: 7712fb530c574b95bc1d57c0877543c3 commit: b52ab10f44684cb19d1fbcad56aedd36
digest: b5:b3e9c9428384357e3b73e4d5a4614328b0a4b1595b10163bbe9483fa16204749274c41797bd49b0d716479c855aa35c1172a94f471fa120ba8369637fd138829 digest: b5:5f464399f5ea7546eb3c6a4e822a306da538298f3d87e9f974f4523d4955de396eb2b8b52a2f3f06ac290764d80cecbaa0a4c96560558e43d9b1c722e61a9d5c

103
internal/rfc7591/format.go Normal file
View file

@ -0,0 +1,103 @@
package rfc7591v1
import (
"encoding/json"
"fmt"
"io"
"github.com/bufbuild/protovalidate-go"
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/proto"
)
const (
TokenEndpointAuthMethodNone = "none"
TokenEndpointAuthMethodClientSecretBasic = "client_secret_basic"
TokenEndpointAuthMethodClientSecretPost = "client_secret_post"
GrantTypesAuthorizationCode = "authorization_code"
GrantTypesImplicit = "implicit"
GrantTypesPassword = "password"
GrantTypesClientCredentials = "client_credentials"
GrantTypesRefreshToken = "refresh_token"
GrantTypesJWTBearer = "urn:ietf:params:oauth:grant-type:jwt-bearer" //nolint:gosec
GrantTypesSAML2Bearer = "urn:ietf:params:oauth:grant-type:saml2-bearer" //nolint:gosec
GrantTypesDeviceCode = "urn:ietf:params:oauth:grant-type:device_code" //nolint:gosec
ResponseTypesCode = "code"
ResponseTypeToken = "token"
)
func (v *Metadata) SetDefaults() {
if v.TokenEndpointAuthMethod == nil {
v.TokenEndpointAuthMethod = proto.String(TokenEndpointAuthMethodClientSecretBasic)
}
if len(v.GrantTypes) == 0 {
v.GrantTypes = []string{GrantTypesAuthorizationCode}
}
if len(v.ResponseTypes) == 0 {
v.ResponseTypes = []string{ResponseTypesCode}
}
}
func (v *Metadata) Validate() error {
return protovalidate.Validate(v)
}
func ParseMetadata(
data []byte,
) (*Metadata, error) {
v := new(Metadata)
err := protojson.UnmarshalOptions{
AllowPartial: false,
DiscardUnknown: true,
}.Unmarshal(data, v)
if err != nil {
return nil, err
}
return v, nil
}
func WriteRegistrationResponse(
w io.Writer,
clientID string,
clientSecret *ClientSecret,
metadata *Metadata,
) error {
var metadataJSON map[string]any
if metadata == nil {
return fmt.Errorf("metadata cannot be nil")
}
metadataBytes, err := protojson.MarshalOptions{
UseProtoNames: true,
EmitUnpopulated: false,
}.Marshal(metadata)
if err != nil {
return err
}
if err := json.Unmarshal(metadataBytes, &metadataJSON); err != nil {
return err
}
metadataJSON["client_id"] = clientID
if clientSecret != nil {
metadataJSON["client_secret"] = clientSecret.Value
if clientSecret.CreatedAt != nil {
metadataJSON["client_id_issued_at"] = clientSecret.CreatedAt.Seconds
}
// Per RFC 7591: client_secret_expires_at is REQUIRED if client_secret is issued
// Value should be 0 if the secret doesn't expire
if clientSecret.ExpiresAt != nil {
metadataJSON["client_secret_expires_at"] = clientSecret.ExpiresAt.Seconds
} else {
metadataJSON["client_secret_expires_at"] = int64(0)
}
}
return json.NewEncoder(w).Encode(metadataJSON)
}

View file

@ -0,0 +1,540 @@
package rfc7591v1
import (
"bytes"
"encoding/json"
"strings"
"testing"
"time"
"github.com/google/go-cmp/cmp"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/testing/protocmp"
timestamppb "google.golang.org/protobuf/types/known/timestamppb"
)
func TestParseMetadata(t *testing.T) {
tests := []struct {
name string
input string
want *Metadata
wantErr bool
}{
{
name: "minimal valid metadata",
input: `{
"redirect_uris": ["https://example.com/callback"]
}`,
want: &Metadata{
RedirectUris: []string{"https://example.com/callback"},
TokenEndpointAuthMethod: proto.String(TokenEndpointAuthMethodClientSecretBasic),
GrantTypes: []string{GrantTypesAuthorizationCode},
ResponseTypes: []string{ResponseTypesCode},
},
wantErr: false,
},
{
name: "full metadata with all fields",
input: `{
"redirect_uris": ["https://example.com/callback", "https://example.com/callback2"],
"token_endpoint_auth_method": "client_secret_post",
"grant_types": ["authorization_code", "refresh_token"],
"response_types": ["code"],
"client_name": "Test Client",
"client_name_localized": {"en": "Test Client", "es": "Cliente de Prueba"},
"client_uri": "https://example.com",
"client_uri_localized": {"en": "https://example.com/en"},
"logo_uri": "https://example.com/logo.png",
"scope": "openid profile email",
"contacts": ["admin@example.com", "support@example.com"],
"tos_uri": "https://example.com/tos",
"policy_uri": "https://example.com/privacy",
"jwks_uri": "https://example.com/.well-known/jwks.json",
"software_id": "test-client-v1",
"software_version": "1.0.0"
}`,
want: &Metadata{
RedirectUris: []string{"https://example.com/callback", "https://example.com/callback2"},
TokenEndpointAuthMethod: proto.String("client_secret_post"),
GrantTypes: []string{"authorization_code", "refresh_token"},
ResponseTypes: []string{"code"},
ClientName: proto.String("Test Client"),
ClientNameLocalized: map[string]string{
"en": "Test Client",
"es": "Cliente de Prueba",
},
ClientUri: proto.String("https://example.com"),
ClientUriLocalized: map[string]string{
"en": "https://example.com/en",
},
LogoUri: proto.String("https://example.com/logo.png"),
Scope: proto.String("openid profile email"),
Contacts: []string{"admin@example.com", "support@example.com"},
TosUri: proto.String("https://example.com/tos"),
PolicyUri: proto.String("https://example.com/privacy"),
JwksUri: proto.String("https://example.com/.well-known/jwks.json"),
SoftwareId: proto.String("test-client-v1"),
SoftwareVersion: proto.String("1.0.0"),
},
wantErr: false,
},
{
name: "metadata with jwks instead of jwks_uri",
input: `{
"redirect_uris": ["https://example.com/callback"],
"jwks": {
"keys": [{
"kty": "RSA",
"rsa_params": {
"n": "example-modulus",
"e": "AQAB"
}
}]
}
}`,
want: &Metadata{
RedirectUris: []string{"https://example.com/callback"},
TokenEndpointAuthMethod: proto.String(TokenEndpointAuthMethodClientSecretBasic),
GrantTypes: []string{GrantTypesAuthorizationCode},
ResponseTypes: []string{ResponseTypesCode},
Jwks: &JsonWebKeySet{
Keys: []*JsonWebKey{{
Kty: "RSA",
KeyTypeParameters: &JsonWebKey_RsaParams{
RsaParams: &RsaKeyParameters{
N: "example-modulus",
E: "AQAB",
},
},
}},
},
},
wantErr: false,
},
{
name: "explicit token_endpoint_auth_method none",
input: `{
"redirect_uris": ["https://example.com/callback"],
"token_endpoint_auth_method": "none"
}`,
want: &Metadata{
RedirectUris: []string{"https://example.com/callback"},
TokenEndpointAuthMethod: proto.String("none"),
GrantTypes: []string{GrantTypesAuthorizationCode},
ResponseTypes: []string{ResponseTypesCode},
},
wantErr: false,
},
{
name: "custom grant and response types",
input: `{
"redirect_uris": ["https://example.com/callback"],
"grant_types": ["implicit", "client_credentials"],
"response_types": ["token", "code"]
}`,
want: &Metadata{
RedirectUris: []string{"https://example.com/callback"},
TokenEndpointAuthMethod: proto.String(TokenEndpointAuthMethodClientSecretBasic),
GrantTypes: []string{"implicit", "client_credentials"},
ResponseTypes: []string{"token", "code"},
},
wantErr: false,
},
{
name: "empty input",
input: "",
wantErr: true,
},
{
name: "invalid JSON",
input: `{"redirect_uris": [}`,
wantErr: true,
},
{
name: "missing required redirect_uris",
input: `{
"client_name": "Test Client"
}`,
wantErr: true,
},
{
name: "empty redirect_uris array",
input: `{
"redirect_uris": []
}`,
wantErr: true,
},
{
name: "invalid redirect_uri",
input: `{
"redirect_uris": ["not-a-uri"]
}`,
wantErr: true,
},
{
name: "invalid token_endpoint_auth_method",
input: `{
"redirect_uris": ["https://example.com/callback"],
"token_endpoint_auth_method": "invalid_method"
}`,
wantErr: true,
},
{
name: "invalid email in contacts",
input: `{
"redirect_uris": ["https://example.com/callback"],
"contacts": ["not-an-email"]
}`,
wantErr: true,
},
{
name: "invalid scope format",
input: `{
"redirect_uris": ["https://example.com/callback"],
"scope": " invalid spaces "
}`,
wantErr: true,
},
{
name: "both jwks and jwks_uri provided",
input: `{
"redirect_uris": ["https://example.com/callback"],
"jwks_uri": "https://example.com/.well-known/jwks.json",
"jwks": {
"keys": [{
"kty": "RSA",
"rsa_params": {
"n": "example-modulus",
"e": "AQAB"
}
}]
}
}`,
wantErr: true,
},
{
name: "client_name too long",
input: `{
"redirect_uris": ["https://example.com/callback"],
"client_name": "` + strings.Repeat("a", 256) + `"
}`,
wantErr: true,
},
{
name: "discard unknown fields",
input: `{
"redirect_uris": ["https://example.com/callback"],
"unknown_field": "should be ignored",
"another_unknown": 123
}`,
want: &Metadata{
RedirectUris: []string{"https://example.com/callback"},
TokenEndpointAuthMethod: proto.String(TokenEndpointAuthMethodClientSecretBasic),
GrantTypes: []string{GrantTypesAuthorizationCode},
ResponseTypes: []string{ResponseTypesCode},
},
wantErr: false,
},
{
name: "invalid BCP 47 language tag - segment too long",
input: `{
"redirect_uris": ["https://example.com/callback"],
"client_name_localized": {"toolongtagsegment": "Test Client"}
}`,
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := ParseMetadata([]byte(tt.input))
if err == nil && got != nil {
got.SetDefaults()
err = got.Validate()
}
if tt.wantErr {
if err == nil {
t.Fatal("expected error, got nil")
}
return
}
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if diff := cmp.Diff(tt.want, got, protocmp.Transform()); diff != "" {
t.Errorf("ParseMetadata() mismatch (-want +got):\n%s", diff)
}
})
}
}
func TestWriteRegistrationResponse(t *testing.T) {
// Test timestamp for consistent testing
testTime := time.Date(2023, 1, 1, 12, 0, 0, 0, time.UTC)
testTimestamp := timestamppb.New(testTime)
tests := []struct {
name string
clientID string
clientSecret *ClientSecret
metadata *Metadata
want map[string]any
wantErr bool
}{
{
name: "minimal response without client secret",
clientID: "test-client-123",
metadata: &Metadata{
RedirectUris: []string{"https://example.com/callback"},
TokenEndpointAuthMethod: proto.String(TokenEndpointAuthMethodNone),
GrantTypes: []string{GrantTypesAuthorizationCode},
ResponseTypes: []string{ResponseTypesCode},
},
want: map[string]any{
"client_id": "test-client-123",
"redirect_uris": []any{"https://example.com/callback"},
"token_endpoint_auth_method": TokenEndpointAuthMethodNone,
"grant_types": []any{GrantTypesAuthorizationCode},
"response_types": []any{ResponseTypesCode},
},
},
{
name: "response with client secret and timestamps",
clientID: "test-client-456",
clientSecret: &ClientSecret{
Value: "super-secret-value",
CreatedAt: testTimestamp,
ExpiresAt: timestamppb.New(testTime.Add(24 * time.Hour)),
},
metadata: &Metadata{
RedirectUris: []string{"https://example.com/callback"},
TokenEndpointAuthMethod: proto.String(TokenEndpointAuthMethodClientSecretPost),
GrantTypes: []string{GrantTypesAuthorizationCode, GrantTypesRefreshToken},
ResponseTypes: []string{ResponseTypesCode},
ClientName: proto.String("Test Client"),
Scope: proto.String("openid profile email"),
},
want: map[string]any{
"client_id": "test-client-456",
"client_secret": "super-secret-value",
"client_id_issued_at": float64(testTime.Unix()),
"client_secret_expires_at": float64(testTime.Add(24 * time.Hour).Unix()),
"redirect_uris": []any{"https://example.com/callback"},
"token_endpoint_auth_method": TokenEndpointAuthMethodClientSecretPost,
"grant_types": []any{GrantTypesAuthorizationCode, GrantTypesRefreshToken},
"response_types": []any{ResponseTypesCode},
"client_name": "Test Client",
"scope": "openid profile email",
},
},
{
name: "response with client secret but no timestamps",
clientID: "test-client-789",
clientSecret: &ClientSecret{
Value: "another-secret",
// CreatedAt and ExpiresAt are nil
},
metadata: &Metadata{
RedirectUris: []string{"https://example.com/callback"},
TokenEndpointAuthMethod: proto.String(TokenEndpointAuthMethodClientSecretBasic),
GrantTypes: []string{GrantTypesClientCredentials},
ResponseTypes: []string{ResponseTypesCode},
},
want: map[string]any{
"client_id": "test-client-789",
"client_secret": "another-secret",
"client_secret_expires_at": float64(0), // Required per RFC when client_secret is present
"redirect_uris": []any{"https://example.com/callback"},
"token_endpoint_auth_method": TokenEndpointAuthMethodClientSecretBasic,
"grant_types": []any{GrantTypesClientCredentials},
"response_types": []any{ResponseTypesCode},
},
},
{
name: "response with full metadata",
clientID: "full-client-id",
clientSecret: &ClientSecret{
Value: "full-secret",
CreatedAt: testTimestamp,
},
metadata: &Metadata{
RedirectUris: []string{"https://example.com/cb1", "https://example.com/cb2"},
TokenEndpointAuthMethod: proto.String(TokenEndpointAuthMethodClientSecretPost),
GrantTypes: []string{GrantTypesAuthorizationCode, GrantTypesImplicit},
ResponseTypes: []string{ResponseTypesCode, ResponseTypeToken},
ClientName: proto.String("Full Test Client"),
ClientNameLocalized: map[string]string{
"en": "Full Test Client",
"es": "Cliente de Prueba Completo",
},
ClientUri: proto.String("https://example.com"),
ClientUriLocalized: map[string]string{
"en": "https://example.com/en",
},
LogoUri: proto.String("https://example.com/logo.png"),
Scope: proto.String("openid profile email offline_access"),
Contacts: []string{"admin@example.com", "support@example.com"},
TosUri: proto.String("https://example.com/tos"),
PolicyUri: proto.String("https://example.com/privacy"),
JwksUri: proto.String("https://example.com/.well-known/jwks.json"),
SoftwareId: proto.String("test-software-v1"),
SoftwareVersion: proto.String("1.2.3"),
},
want: map[string]any{
"client_id": "full-client-id",
"client_secret": "full-secret",
"client_id_issued_at": float64(testTime.Unix()),
"client_secret_expires_at": float64(0), // Required per RFC, 0 means no expiration
"redirect_uris": []any{"https://example.com/cb1", "https://example.com/cb2"},
"token_endpoint_auth_method": TokenEndpointAuthMethodClientSecretPost,
"grant_types": []any{GrantTypesAuthorizationCode, GrantTypesImplicit},
"response_types": []any{ResponseTypesCode, ResponseTypeToken},
"client_name": "Full Test Client",
"client_name_localized": map[string]any{
"en": "Full Test Client",
"es": "Cliente de Prueba Completo",
},
"client_uri": "https://example.com",
"client_uri_localized": map[string]any{
"en": "https://example.com/en",
},
"logo_uri": "https://example.com/logo.png",
"scope": "openid profile email offline_access",
"contacts": []any{"admin@example.com", "support@example.com"},
"tos_uri": "https://example.com/tos",
"policy_uri": "https://example.com/privacy",
"jwks_uri": "https://example.com/.well-known/jwks.json",
"software_id": "test-software-v1",
"software_version": "1.2.3",
},
},
{
name: "response with jwks instead of jwks_uri",
clientID: "jwks-client",
metadata: &Metadata{
RedirectUris: []string{"https://example.com/callback"},
TokenEndpointAuthMethod: proto.String(TokenEndpointAuthMethodNone),
GrantTypes: []string{GrantTypesAuthorizationCode},
ResponseTypes: []string{ResponseTypesCode},
Jwks: &JsonWebKeySet{
Keys: []*JsonWebKey{{
Kty: "RSA",
KeyTypeParameters: &JsonWebKey_RsaParams{
RsaParams: &RsaKeyParameters{
N: "example-modulus",
E: "AQAB",
},
},
}},
},
},
want: map[string]any{
"client_id": "jwks-client",
"redirect_uris": []any{"https://example.com/callback"},
"token_endpoint_auth_method": TokenEndpointAuthMethodNone,
"grant_types": []any{GrantTypesAuthorizationCode},
"response_types": []any{ResponseTypesCode},
"jwks": map[string]any{
"keys": []any{
map[string]any{
"kty": "RSA",
"rsa_params": map[string]any{
"n": "example-modulus",
"e": "AQAB",
},
},
},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var buf bytes.Buffer
err := WriteRegistrationResponse(&buf, tt.clientID, tt.clientSecret, tt.metadata)
if tt.wantErr {
if err == nil {
t.Fatal("expected error, got nil")
}
return
}
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
// Parse the JSON output
var got map[string]any
if err := json.Unmarshal(buf.Bytes(), &got); err != nil {
t.Fatalf("failed to parse JSON output: %v", err)
}
// Compare the result
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("WriteRegistrationResponse() mismatch (-want +got):\n%s", diff)
}
// Verify that the output is valid JSON
if !json.Valid(buf.Bytes()) {
t.Error("output is not valid JSON")
}
// Verify that client_secret is only present when expected
_, hasClientSecret := got["client_secret"]
expectedHasSecret := tt.clientSecret != nil
if hasClientSecret != expectedHasSecret {
t.Errorf("client_secret presence mismatch: got %v, want %v", hasClientSecret, expectedHasSecret)
}
// Verify timestamp fields presence per RFC 7591
_, hasIssuedAt := got["client_id_issued_at"]
_, hasExpiresAt := got["client_secret_expires_at"]
expectedHasIssuedAt := tt.clientSecret != nil && tt.clientSecret.CreatedAt != nil
// Per RFC 7591: client_secret_expires_at is REQUIRED if client_secret is issued
expectedHasExpiresAt := tt.clientSecret != nil
if hasIssuedAt != expectedHasIssuedAt {
t.Errorf("client_id_issued_at presence mismatch: got %v, want %v", hasIssuedAt, expectedHasIssuedAt)
}
if hasExpiresAt != expectedHasExpiresAt {
t.Errorf("client_secret_expires_at presence mismatch: got %v, want %v", hasExpiresAt, expectedHasExpiresAt)
}
})
}
}
func TestWriteRegistrationResponseEdgeCases(t *testing.T) {
t.Run("nil metadata", func(t *testing.T) {
var buf bytes.Buffer
err := WriteRegistrationResponse(&buf, "test-client", nil, nil)
if err == nil {
t.Fatalf("expected error with nil metadata: %v", err)
}
})
t.Run("empty client ID", func(t *testing.T) {
var buf bytes.Buffer
metadata := &Metadata{
RedirectUris: []string{"https://example.com/callback"},
}
err := WriteRegistrationResponse(&buf, "", nil, metadata)
if err != nil {
t.Fatalf("unexpected error with empty client ID: %v", err)
}
var got map[string]any
if err := json.Unmarshal(buf.Bytes(), &got); err != nil {
t.Fatalf("failed to parse JSON output: %v", err)
}
if got["client_id"] != "" {
t.Errorf("expected empty client_id, got %v", got["client_id"])
}
})
}

View file

@ -10,6 +10,7 @@ import (
_ "buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go/buf/validate" _ "buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go/buf/validate"
protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl" protoimpl "google.golang.org/protobuf/runtime/protoimpl"
timestamppb "google.golang.org/protobuf/types/known/timestamppb"
reflect "reflect" reflect "reflect"
sync "sync" sync "sync"
unsafe "unsafe" unsafe "unsafe"
@ -470,7 +471,7 @@ func (x *OkpKeyParameters) GetX() string {
// Represents the client metadata fields defined in RFC 7591 Section 2. // Represents the client metadata fields defined in RFC 7591 Section 2.
// These values are used both as input to registration requests and output in // These values are used both as input to registration requests and output in
// registration responses. // registration responses.
type ClientMetadata struct { type Metadata struct {
state protoimpl.MessageState `protogen:"open.v1"` state protoimpl.MessageState `protogen:"open.v1"`
// Array of redirection URI strings. REQUIRED for clients using flows with // Array of redirection URI strings. REQUIRED for clients using flows with
// redirection. // redirection.
@ -525,20 +526,20 @@ type ClientMetadata struct {
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
} }
func (x *ClientMetadata) Reset() { func (x *Metadata) Reset() {
*x = ClientMetadata{} *x = Metadata{}
mi := &file_types_proto_msgTypes[6] mi := &file_types_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
func (x *ClientMetadata) String() string { func (x *Metadata) String() string {
return protoimpl.X.MessageStringOf(x) return protoimpl.X.MessageStringOf(x)
} }
func (*ClientMetadata) ProtoMessage() {} func (*Metadata) ProtoMessage() {}
func (x *ClientMetadata) ProtoReflect() protoreflect.Message { func (x *Metadata) ProtoReflect() protoreflect.Message {
mi := &file_types_proto_msgTypes[6] mi := &file_types_proto_msgTypes[6]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
@ -550,414 +551,554 @@ func (x *ClientMetadata) ProtoReflect() protoreflect.Message {
return mi.MessageOf(x) return mi.MessageOf(x)
} }
// Deprecated: Use ClientMetadata.ProtoReflect.Descriptor instead. // Deprecated: Use Metadata.ProtoReflect.Descriptor instead.
func (*ClientMetadata) Descriptor() ([]byte, []int) { func (*Metadata) Descriptor() ([]byte, []int) {
return file_types_proto_rawDescGZIP(), []int{6} return file_types_proto_rawDescGZIP(), []int{6}
} }
func (x *ClientMetadata) GetRedirectUris() []string { func (x *Metadata) GetRedirectUris() []string {
if x != nil { if x != nil {
return x.RedirectUris return x.RedirectUris
} }
return nil return nil
} }
func (x *ClientMetadata) GetTokenEndpointAuthMethod() string { func (x *Metadata) GetTokenEndpointAuthMethod() string {
if x != nil && x.TokenEndpointAuthMethod != nil { if x != nil && x.TokenEndpointAuthMethod != nil {
return *x.TokenEndpointAuthMethod return *x.TokenEndpointAuthMethod
} }
return "" return ""
} }
func (x *ClientMetadata) GetGrantTypes() []string { func (x *Metadata) GetGrantTypes() []string {
if x != nil { if x != nil {
return x.GrantTypes return x.GrantTypes
} }
return nil return nil
} }
func (x *ClientMetadata) GetResponseTypes() []string { func (x *Metadata) GetResponseTypes() []string {
if x != nil { if x != nil {
return x.ResponseTypes return x.ResponseTypes
} }
return nil return nil
} }
func (x *ClientMetadata) GetClientName() string { func (x *Metadata) GetClientName() string {
if x != nil && x.ClientName != nil { if x != nil && x.ClientName != nil {
return *x.ClientName return *x.ClientName
} }
return "" return ""
} }
func (x *ClientMetadata) GetClientNameLocalized() map[string]string { func (x *Metadata) GetClientNameLocalized() map[string]string {
if x != nil { if x != nil {
return x.ClientNameLocalized return x.ClientNameLocalized
} }
return nil return nil
} }
func (x *ClientMetadata) GetClientUri() string { func (x *Metadata) GetClientUri() string {
if x != nil && x.ClientUri != nil { if x != nil && x.ClientUri != nil {
return *x.ClientUri return *x.ClientUri
} }
return "" return ""
} }
func (x *ClientMetadata) GetClientUriLocalized() map[string]string { func (x *Metadata) GetClientUriLocalized() map[string]string {
if x != nil { if x != nil {
return x.ClientUriLocalized return x.ClientUriLocalized
} }
return nil return nil
} }
func (x *ClientMetadata) GetLogoUri() string { func (x *Metadata) GetLogoUri() string {
if x != nil && x.LogoUri != nil { if x != nil && x.LogoUri != nil {
return *x.LogoUri return *x.LogoUri
} }
return "" return ""
} }
func (x *ClientMetadata) GetLogoUriLocalized() map[string]string { func (x *Metadata) GetLogoUriLocalized() map[string]string {
if x != nil { if x != nil {
return x.LogoUriLocalized return x.LogoUriLocalized
} }
return nil return nil
} }
func (x *ClientMetadata) GetScope() string { func (x *Metadata) GetScope() string {
if x != nil && x.Scope != nil { if x != nil && x.Scope != nil {
return *x.Scope return *x.Scope
} }
return "" return ""
} }
func (x *ClientMetadata) GetContacts() []string { func (x *Metadata) GetContacts() []string {
if x != nil { if x != nil {
return x.Contacts return x.Contacts
} }
return nil return nil
} }
func (x *ClientMetadata) GetTosUri() string { func (x *Metadata) GetTosUri() string {
if x != nil && x.TosUri != nil { if x != nil && x.TosUri != nil {
return *x.TosUri return *x.TosUri
} }
return "" return ""
} }
func (x *ClientMetadata) GetTosUriLocalized() map[string]string { func (x *Metadata) GetTosUriLocalized() map[string]string {
if x != nil { if x != nil {
return x.TosUriLocalized return x.TosUriLocalized
} }
return nil return nil
} }
func (x *ClientMetadata) GetPolicyUri() string { func (x *Metadata) GetPolicyUri() string {
if x != nil && x.PolicyUri != nil { if x != nil && x.PolicyUri != nil {
return *x.PolicyUri return *x.PolicyUri
} }
return "" return ""
} }
func (x *ClientMetadata) GetPolicyUriLocalized() map[string]string { func (x *Metadata) GetPolicyUriLocalized() map[string]string {
if x != nil { if x != nil {
return x.PolicyUriLocalized return x.PolicyUriLocalized
} }
return nil return nil
} }
func (x *ClientMetadata) GetJwksUri() string { func (x *Metadata) GetJwksUri() string {
if x != nil && x.JwksUri != nil { if x != nil && x.JwksUri != nil {
return *x.JwksUri return *x.JwksUri
} }
return "" return ""
} }
func (x *ClientMetadata) GetJwks() *JsonWebKeySet { func (x *Metadata) GetJwks() *JsonWebKeySet {
if x != nil { if x != nil {
return x.Jwks return x.Jwks
} }
return nil return nil
} }
func (x *ClientMetadata) GetSoftwareId() string { func (x *Metadata) GetSoftwareId() string {
if x != nil && x.SoftwareId != nil { if x != nil && x.SoftwareId != nil {
return *x.SoftwareId return *x.SoftwareId
} }
return "" return ""
} }
func (x *ClientMetadata) GetSoftwareVersion() string { func (x *Metadata) GetSoftwareVersion() string {
if x != nil && x.SoftwareVersion != nil { if x != nil && x.SoftwareVersion != nil {
return *x.SoftwareVersion return *x.SoftwareVersion
} }
return "" return ""
} }
type ClientSecret struct {
state protoimpl.MessageState `protogen:"open.v1"`
// REQUIRED. The client secret value.
Value string `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"`
// OPTIONAL. The expiration time of the client secret.
ExpiresAt *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=expires_at,json=expiresAt,proto3,oneof" json:"expires_at,omitempty"`
CreatedAt *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ClientSecret) Reset() {
*x = ClientSecret{}
mi := &file_types_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ClientSecret) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ClientSecret) ProtoMessage() {}
func (x *ClientSecret) ProtoReflect() protoreflect.Message {
mi := &file_types_proto_msgTypes[7]
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 ClientSecret.ProtoReflect.Descriptor instead.
func (*ClientSecret) Descriptor() ([]byte, []int) {
return file_types_proto_rawDescGZIP(), []int{7}
}
func (x *ClientSecret) GetValue() string {
if x != nil {
return x.Value
}
return ""
}
func (x *ClientSecret) GetExpiresAt() *timestamppb.Timestamp {
if x != nil {
return x.ExpiresAt
}
return nil
}
func (x *ClientSecret) GetCreatedAt() *timestamppb.Timestamp {
if x != nil {
return x.CreatedAt
}
return nil
}
// Represents the client registration storage structure.
type ClientRegistration struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Contains the client metadata as requested by the client.
RequestMetadata *Metadata `protobuf:"bytes,1,opt,name=request_metadata,json=requestMetadata,proto3" json:"request_metadata,omitempty"`
// Contains the client metadata as was returned by the server.
ResponseMetadata *Metadata `protobuf:"bytes,2,opt,name=response_metadata,json=responseMetadata,proto3" json:"response_metadata,omitempty"`
// OPTIONAL. The "client_secret" parameter is the secret used by the client
ClientSecret *ClientSecret `protobuf:"bytes,3,opt,name=client_secret,json=clientSecret,proto3" json:"client_secret,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ClientRegistration) Reset() {
*x = ClientRegistration{}
mi := &file_types_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ClientRegistration) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ClientRegistration) ProtoMessage() {}
func (x *ClientRegistration) ProtoReflect() protoreflect.Message {
mi := &file_types_proto_msgTypes[8]
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 ClientRegistration.ProtoReflect.Descriptor instead.
func (*ClientRegistration) Descriptor() ([]byte, []int) {
return file_types_proto_rawDescGZIP(), []int{8}
}
func (x *ClientRegistration) GetRequestMetadata() *Metadata {
if x != nil {
return x.RequestMetadata
}
return nil
}
func (x *ClientRegistration) GetResponseMetadata() *Metadata {
if x != nil {
return x.ResponseMetadata
}
return nil
}
func (x *ClientRegistration) GetClientSecret() *ClientSecret {
if x != nil {
return x.ClientSecret
}
return nil
}
var File_types_proto protoreflect.FileDescriptor var File_types_proto protoreflect.FileDescriptor
var file_types_proto_rawDesc = string([]byte{ var file_types_proto_rawDesc = string([]byte{
0x0a, 0x0b, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0f, 0x69, 0x0a, 0x0b, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0f, 0x69,
0x65, 0x74, 0x66, 0x2e, 0x72, 0x66, 0x63, 0x37, 0x35, 0x39, 0x31, 0x2e, 0x76, 0x31, 0x1a, 0x1b, 0x65, 0x74, 0x66, 0x2e, 0x72, 0x66, 0x63, 0x37, 0x35, 0x39, 0x31, 0x2e, 0x76, 0x31, 0x1a, 0x1b,
0x62, 0x75, 0x66, 0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2f, 0x76, 0x61, 0x6c, 0x62, 0x75, 0x66, 0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2f, 0x76, 0x61, 0x6c,
0x69, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x4d, 0x0a, 0x0d, 0x4a, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f,
0x73, 0x6f, 0x6e, 0x57, 0x65, 0x62, 0x4b, 0x65, 0x79, 0x53, 0x65, 0x74, 0x12, 0x3c, 0x0a, 0x04, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d,
0x6b, 0x65, 0x79, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x69, 0x65, 0x74, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x4d, 0x0a, 0x0d,
0x66, 0x2e, 0x72, 0x66, 0x63, 0x37, 0x35, 0x39, 0x31, 0x2e, 0x76, 0x31, 0x2e, 0x4a, 0x73, 0x6f, 0x4a, 0x73, 0x6f, 0x6e, 0x57, 0x65, 0x62, 0x4b, 0x65, 0x79, 0x53, 0x65, 0x74, 0x12, 0x3c, 0x0a,
0x6e, 0x57, 0x65, 0x62, 0x4b, 0x65, 0x79, 0x42, 0x0b, 0xba, 0x48, 0x08, 0xc8, 0x01, 0x01, 0x92, 0x04, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x69, 0x65,
0x01, 0x02, 0x08, 0x01, 0x52, 0x04, 0x6b, 0x65, 0x79, 0x73, 0x22, 0xcf, 0x07, 0x0a, 0x0a, 0x4a,
0x73, 0x6f, 0x6e, 0x57, 0x65, 0x62, 0x4b, 0x65, 0x79, 0x12, 0x2f, 0x0a, 0x03, 0x6b, 0x74, 0x79,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x1d, 0xba, 0x48, 0x1a, 0xc8, 0x01, 0x01, 0x72, 0x15,
0x10, 0x01, 0x52, 0x03, 0x52, 0x53, 0x41, 0x52, 0x02, 0x45, 0x43, 0x52, 0x03, 0x6f, 0x63, 0x74,
0x52, 0x03, 0x4f, 0x4b, 0x50, 0x52, 0x03, 0x6b, 0x74, 0x79, 0x12, 0x26, 0x0a, 0x03, 0x75, 0x73,
0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0f, 0xba, 0x48, 0x0c, 0x72, 0x0a, 0x52, 0x03,
0x73, 0x69, 0x67, 0x52, 0x03, 0x65, 0x6e, 0x63, 0x48, 0x01, 0x52, 0x03, 0x75, 0x73, 0x65, 0x88,
0x01, 0x01, 0x12, 0x25, 0x0a, 0x07, 0x6b, 0x65, 0x79, 0x5f, 0x6f, 0x70, 0x73, 0x18, 0x03, 0x20,
0x03, 0x28, 0x09, 0x42, 0x0c, 0xba, 0x48, 0x09, 0x92, 0x01, 0x06, 0x22, 0x04, 0x72, 0x02, 0x10,
0x01, 0x52, 0x06, 0x6b, 0x65, 0x79, 0x4f, 0x70, 0x73, 0x12, 0x1e, 0x0a, 0x03, 0x61, 0x6c, 0x67,
0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xba, 0x48, 0x04, 0x72, 0x02, 0x10, 0x01, 0x48,
0x02, 0x52, 0x03, 0x61, 0x6c, 0x67, 0x88, 0x01, 0x01, 0x12, 0x1e, 0x0a, 0x03, 0x6b, 0x69, 0x64,
0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xba, 0x48, 0x04, 0x72, 0x02, 0x10, 0x01, 0x48,
0x03, 0x52, 0x03, 0x6b, 0x69, 0x64, 0x88, 0x01, 0x01, 0x12, 0x42, 0x0a, 0x0a, 0x72, 0x73, 0x61,
0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e,
0x69, 0x65, 0x74, 0x66, 0x2e, 0x72, 0x66, 0x63, 0x37, 0x35, 0x39, 0x31, 0x2e, 0x76, 0x31, 0x2e,
0x52, 0x73, 0x61, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73,
0x48, 0x00, 0x52, 0x09, 0x72, 0x73, 0x61, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x3f, 0x0a,
0x09, 0x65, 0x63, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x20, 0x2e, 0x69, 0x65, 0x74, 0x66, 0x2e, 0x72, 0x66, 0x63, 0x37, 0x35, 0x39, 0x31, 0x2e,
0x76, 0x31, 0x2e, 0x45, 0x63, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65,
0x72, 0x73, 0x48, 0x00, 0x52, 0x08, 0x65, 0x63, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x54,
0x0a, 0x10, 0x73, 0x79, 0x6d, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x5f, 0x70, 0x61, 0x72, 0x61,
0x6d, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x69, 0x65, 0x74, 0x66, 0x2e,
0x72, 0x66, 0x63, 0x37, 0x35, 0x39, 0x31, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x79, 0x6d, 0x6d, 0x65,
0x74, 0x72, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72,
0x73, 0x48, 0x00, 0x52, 0x0f, 0x73, 0x79, 0x6d, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x50, 0x61,
0x72, 0x61, 0x6d, 0x73, 0x12, 0x42, 0x0a, 0x0a, 0x6f, 0x6b, 0x70, 0x5f, 0x70, 0x61, 0x72, 0x61,
0x6d, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x69, 0x65, 0x74, 0x66, 0x2e,
0x72, 0x66, 0x63, 0x37, 0x35, 0x39, 0x31, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x6b, 0x70, 0x4b, 0x65,
0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x48, 0x00, 0x52, 0x09, 0x6f,
0x6b, 0x70, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x3a, 0xab, 0x03, 0xba, 0x48, 0xa7, 0x03, 0x1a,
0x66, 0x0a, 0x12, 0x6a, 0x77, 0x6b, 0x2e, 0x6b, 0x74, 0x79, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d,
0x73, 0x2e, 0x72, 0x73, 0x61, 0x12, 0x25, 0x72, 0x73, 0x61, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d,
0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x20, 0x66,
0x6f, 0x72, 0x20, 0x6b, 0x74, 0x79, 0x20, 0x27, 0x52, 0x53, 0x41, 0x27, 0x1a, 0x29, 0x74, 0x68,
0x69, 0x73, 0x2e, 0x6b, 0x74, 0x79, 0x20, 0x21, 0x3d, 0x20, 0x27, 0x52, 0x53, 0x41, 0x27, 0x20,
0x7c, 0x7c, 0x20, 0x68, 0x61, 0x73, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x72, 0x73, 0x61, 0x5f,
0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x29, 0x1a, 0x61, 0x0a, 0x11, 0x6a, 0x77, 0x6b, 0x2e, 0x6b,
0x74, 0x79, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x2e, 0x65, 0x63, 0x12, 0x23, 0x65, 0x63,
0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x72, 0x65, 0x71, 0x75,
0x69, 0x72, 0x65, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x6b, 0x74, 0x79, 0x20, 0x27, 0x45, 0x43,
0x27, 0x1a, 0x27, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6b, 0x74, 0x79, 0x20, 0x21, 0x3d, 0x20, 0x27,
0x45, 0x43, 0x27, 0x20, 0x7c, 0x7c, 0x20, 0x68, 0x61, 0x73, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2e,
0x65, 0x63, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x29, 0x1a, 0x72, 0x0a, 0x12, 0x6a, 0x77,
0x6b, 0x2e, 0x6b, 0x74, 0x79, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x2e, 0x6f, 0x63, 0x74,
0x12, 0x2b, 0x73, 0x79, 0x6d, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x5f, 0x70, 0x61, 0x72, 0x61,
0x6d, 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x20,
0x66, 0x6f, 0x72, 0x20, 0x6b, 0x74, 0x79, 0x20, 0x27, 0x6f, 0x63, 0x74, 0x27, 0x1a, 0x2f, 0x74,
0x68, 0x69, 0x73, 0x2e, 0x6b, 0x74, 0x79, 0x20, 0x21, 0x3d, 0x20, 0x27, 0x6f, 0x63, 0x74, 0x27,
0x20, 0x7c, 0x7c, 0x20, 0x68, 0x61, 0x73, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x73, 0x79, 0x6d,
0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x29, 0x1a, 0x66,
0x0a, 0x12, 0x6a, 0x77, 0x6b, 0x2e, 0x6b, 0x74, 0x79, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73,
0x2e, 0x6f, 0x6b, 0x70, 0x12, 0x25, 0x6f, 0x6b, 0x70, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73,
0x20, 0x61, 0x72, 0x65, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x20, 0x66, 0x6f,
0x72, 0x20, 0x6b, 0x74, 0x79, 0x20, 0x27, 0x4f, 0x4b, 0x50, 0x27, 0x1a, 0x29, 0x74, 0x68, 0x69,
0x73, 0x2e, 0x6b, 0x74, 0x79, 0x20, 0x21, 0x3d, 0x20, 0x27, 0x4f, 0x4b, 0x50, 0x27, 0x20, 0x7c,
0x7c, 0x20, 0x68, 0x61, 0x73, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6f, 0x6b, 0x70, 0x5f, 0x70,
0x61, 0x72, 0x61, 0x6d, 0x73, 0x29, 0x42, 0x1c, 0x0a, 0x13, 0x6b, 0x65, 0x79, 0x5f, 0x74, 0x79,
0x70, 0x65, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x12, 0x05, 0xba,
0x48, 0x02, 0x08, 0x00, 0x42, 0x06, 0x0a, 0x04, 0x5f, 0x75, 0x73, 0x65, 0x42, 0x06, 0x0a, 0x04,
0x5f, 0x61, 0x6c, 0x67, 0x42, 0x06, 0x0a, 0x04, 0x5f, 0x6b, 0x69, 0x64, 0x22, 0x46, 0x0a, 0x10,
0x52, 0x73, 0x61, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73,
0x12, 0x18, 0x0a, 0x01, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xba, 0x48, 0x07,
0xc8, 0x01, 0x01, 0x72, 0x02, 0x10, 0x01, 0x52, 0x01, 0x6e, 0x12, 0x18, 0x0a, 0x01, 0x65, 0x18,
0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xba, 0x48, 0x07, 0xc8, 0x01, 0x01, 0x72, 0x02, 0x10,
0x01, 0x52, 0x01, 0x65, 0x22, 0x76, 0x0a, 0x0f, 0x45, 0x63, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x72,
0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x12, 0x2f, 0x0a, 0x03, 0x63, 0x72, 0x76, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x42, 0x1d, 0xba, 0x48, 0x1a, 0xc8, 0x01, 0x01, 0x72, 0x15, 0x52, 0x05,
0x50, 0x2d, 0x32, 0x35, 0x36, 0x52, 0x05, 0x50, 0x2d, 0x33, 0x38, 0x34, 0x52, 0x05, 0x50, 0x2d,
0x35, 0x32, 0x31, 0x52, 0x03, 0x63, 0x72, 0x76, 0x12, 0x18, 0x0a, 0x01, 0x78, 0x18, 0x02, 0x20,
0x01, 0x28, 0x09, 0x42, 0x0a, 0xba, 0x48, 0x07, 0xc8, 0x01, 0x01, 0x72, 0x02, 0x10, 0x01, 0x52,
0x01, 0x78, 0x12, 0x18, 0x0a, 0x01, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xba,
0x48, 0x07, 0xc8, 0x01, 0x01, 0x72, 0x02, 0x10, 0x01, 0x52, 0x01, 0x79, 0x22, 0x32, 0x0a, 0x16,
0x53, 0x79, 0x6d, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x72, 0x61,
0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x12, 0x18, 0x0a, 0x01, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28,
0x09, 0x42, 0x0a, 0xba, 0x48, 0x07, 0xc8, 0x01, 0x01, 0x72, 0x02, 0x10, 0x01, 0x52, 0x01, 0x6b,
0x22, 0x7e, 0x0a, 0x10, 0x4f, 0x6b, 0x70, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65,
0x74, 0x65, 0x72, 0x73, 0x12, 0x38, 0x0a, 0x03, 0x63, 0x72, 0x76, 0x18, 0x01, 0x20, 0x01, 0x28,
0x09, 0x42, 0x26, 0xba, 0x48, 0x23, 0xc8, 0x01, 0x01, 0x72, 0x1e, 0x52, 0x07, 0x45, 0x64, 0x32,
0x35, 0x35, 0x31, 0x39, 0x52, 0x05, 0x45, 0x64, 0x34, 0x34, 0x38, 0x52, 0x06, 0x58, 0x32, 0x35,
0x35, 0x31, 0x39, 0x52, 0x04, 0x58, 0x34, 0x34, 0x38, 0x52, 0x03, 0x63, 0x72, 0x76, 0x12, 0x30,
0x0a, 0x01, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x22, 0xba, 0x48, 0x1f, 0xc8, 0x01,
0x01, 0x72, 0x1a, 0x10, 0x01, 0x32, 0x16, 0x5e, 0x5b, 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x30,
0x2d, 0x39, 0x2d, 0x5f, 0x5d, 0x2b, 0x3d, 0x7b, 0x30, 0x2c, 0x32, 0x7d, 0x24, 0x52, 0x01, 0x78,
0x22, 0x9b, 0x13, 0x0a, 0x0e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64,
0x61, 0x74, 0x61, 0x12, 0x36, 0x0a, 0x0d, 0x72, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x5f,
0x75, 0x72, 0x69, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x42, 0x11, 0xba, 0x48, 0x0e, 0x92,
0x01, 0x0b, 0x08, 0x01, 0x22, 0x07, 0x72, 0x05, 0x10, 0x01, 0x88, 0x01, 0x01, 0x52, 0x0c, 0x72,
0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x55, 0x72, 0x69, 0x73, 0x12, 0x76, 0x0a, 0x1a, 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, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42,
0x34, 0xba, 0x48, 0x31, 0x72, 0x2f, 0x52, 0x04, 0x6e, 0x6f, 0x6e, 0x65, 0x52, 0x12, 0x63, 0x6c,
0x69, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x5f, 0x70, 0x6f, 0x73, 0x74,
0x52, 0x13, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x5f,
0x62, 0x61, 0x73, 0x69, 0x63, 0x48, 0x00, 0x52, 0x17, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x45, 0x6e,
0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64,
0x88, 0x01, 0x01, 0x12, 0xd7, 0x01, 0x0a, 0x0b, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x5f, 0x74, 0x79,
0x70, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x42, 0xb5, 0x01, 0xba, 0x48, 0xb1, 0x01,
0x92, 0x01, 0xad, 0x01, 0x22, 0xaa, 0x01, 0x72, 0xa7, 0x01, 0x52, 0x12, 0x61, 0x75, 0x74, 0x68,
0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x52, 0x08,
0x69, 0x6d, 0x70, 0x6c, 0x69, 0x63, 0x69, 0x74, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f,
0x72, 0x64, 0x52, 0x12, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x72, 0x65, 0x64, 0x65,
0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x52, 0x0d, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x5f,
0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x2b, 0x75, 0x72, 0x6e, 0x3a, 0x69, 0x65, 0x74, 0x66, 0x3a,
0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x3a, 0x6f, 0x61, 0x75, 0x74, 0x68, 0x3a, 0x67, 0x72, 0x61,
0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x6a, 0x77, 0x74, 0x2d, 0x62, 0x65, 0x61, 0x72,
0x65, 0x72, 0x52, 0x2d, 0x75, 0x72, 0x6e, 0x3a, 0x69, 0x65, 0x74, 0x66, 0x3a, 0x70, 0x61, 0x72,
0x61, 0x6d, 0x73, 0x3a, 0x6f, 0x61, 0x75, 0x74, 0x68, 0x3a, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x2d,
0x74, 0x79, 0x70, 0x65, 0x3a, 0x73, 0x61, 0x6d, 0x6c, 0x32, 0x2d, 0x62, 0x65, 0x61, 0x72, 0x65,
0x72, 0x52, 0x0a, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x73, 0x12, 0x3e, 0x0a,
0x0e, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x18,
0x04, 0x20, 0x03, 0x28, 0x09, 0x42, 0x17, 0xba, 0x48, 0x14, 0x92, 0x01, 0x11, 0x22, 0x0f, 0x72,
0x0d, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x0d,
0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x12, 0x30, 0x0a,
0x0b, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01,
0x28, 0x09, 0x42, 0x0a, 0xba, 0x48, 0x07, 0x72, 0x05, 0x10, 0x01, 0x18, 0xff, 0x01, 0x48, 0x01,
0x52, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x88, 0x01, 0x01, 0x12,
0xa6, 0x01, 0x0a, 0x15, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x5f,
0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32,
0x38, 0x2e, 0x69, 0x65, 0x74, 0x66, 0x2e, 0x72, 0x66, 0x63, 0x37, 0x35, 0x39, 0x31, 0x2e, 0x76,
0x31, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x4c, 0x6f, 0x63, 0x61, 0x6c,
0x69, 0x7a, 0x65, 0x64, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x42, 0x38, 0xba, 0x48, 0x35, 0x9a, 0x01,
0x32, 0x22, 0x27, 0x72, 0x25, 0x32, 0x23, 0x5e, 0x5b, 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x5d,
0x7b, 0x31, 0x2c, 0x38, 0x7d, 0x28, 0x2d, 0x5b, 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x30, 0x2d,
0x39, 0x5d, 0x7b, 0x31, 0x2c, 0x38, 0x7d, 0x29, 0x2a, 0x24, 0x2a, 0x07, 0x72, 0x05, 0x10, 0x01,
0x18, 0xff, 0x01, 0x52, 0x13, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x4c,
0x6f, 0x63, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x12, 0x2c, 0x0a, 0x0a, 0x63, 0x6c, 0x69, 0x65,
0x6e, 0x74, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xba, 0x48,
0x05, 0x72, 0x03, 0x88, 0x01, 0x01, 0x48, 0x02, 0x52, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74,
0x55, 0x72, 0x69, 0x88, 0x01, 0x01, 0x12, 0xa1, 0x01, 0x0a, 0x14, 0x63, 0x6c, 0x69, 0x65, 0x6e,
0x74, 0x5f, 0x75, 0x72, 0x69, 0x5f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x18,
0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x37, 0x2e, 0x69, 0x65, 0x74, 0x66, 0x2e, 0x72, 0x66, 0x63,
0x37, 0x35, 0x39, 0x31, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4d, 0x65,
0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x55, 0x72, 0x69,
0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x42, 0x36,
0xba, 0x48, 0x33, 0x9a, 0x01, 0x30, 0x22, 0x27, 0x72, 0x25, 0x32, 0x23, 0x5e, 0x5b, 0x61, 0x2d,
0x7a, 0x41, 0x2d, 0x5a, 0x5d, 0x7b, 0x31, 0x2c, 0x38, 0x7d, 0x28, 0x2d, 0x5b, 0x61, 0x2d, 0x7a,
0x41, 0x2d, 0x5a, 0x30, 0x2d, 0x39, 0x5d, 0x7b, 0x31, 0x2c, 0x38, 0x7d, 0x29, 0x2a, 0x24, 0x2a,
0x05, 0x72, 0x03, 0x88, 0x01, 0x01, 0x52, 0x12, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x55, 0x72,
0x69, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x12, 0x28, 0x0a, 0x08, 0x6c, 0x6f,
0x67, 0x6f, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xba, 0x48,
0x05, 0x72, 0x03, 0x88, 0x01, 0x01, 0x48, 0x03, 0x52, 0x07, 0x6c, 0x6f, 0x67, 0x6f, 0x55, 0x72,
0x69, 0x88, 0x01, 0x01, 0x12, 0x9b, 0x01, 0x0a, 0x12, 0x6c, 0x6f, 0x67, 0x6f, 0x5f, 0x75, 0x72,
0x69, 0x5f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x18, 0x0a, 0x20, 0x03, 0x28,
0x0b, 0x32, 0x35, 0x2e, 0x69, 0x65, 0x74, 0x66, 0x2e, 0x72, 0x66, 0x63, 0x37, 0x35, 0x39, 0x31,
0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61,
0x74, 0x61, 0x2e, 0x4c, 0x6f, 0x67, 0x6f, 0x55, 0x72, 0x69, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x69,
0x7a, 0x65, 0x64, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x42, 0x36, 0xba, 0x48, 0x33, 0x9a, 0x01, 0x30,
0x22, 0x27, 0x72, 0x25, 0x32, 0x23, 0x5e, 0x5b, 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x5d, 0x7b,
0x31, 0x2c, 0x38, 0x7d, 0x28, 0x2d, 0x5b, 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x30, 0x2d, 0x39,
0x5d, 0x7b, 0x31, 0x2c, 0x38, 0x7d, 0x29, 0x2a, 0x24, 0x2a, 0x05, 0x72, 0x03, 0x88, 0x01, 0x01,
0x52, 0x10, 0x6c, 0x6f, 0x67, 0x6f, 0x55, 0x72, 0x69, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x69, 0x7a,
0x65, 0x64, 0x12, 0x30, 0x0a, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28,
0x09, 0x42, 0x15, 0xba, 0x48, 0x12, 0x72, 0x10, 0x10, 0x01, 0x32, 0x0c, 0x5e, 0x5c, 0x53, 0x2b,
0x28, 0x20, 0x5c, 0x53, 0x2b, 0x29, 0x2a, 0x24, 0x48, 0x04, 0x52, 0x05, 0x73, 0x63, 0x6f, 0x70,
0x65, 0x88, 0x01, 0x01, 0x12, 0x28, 0x0a, 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x73,
0x18, 0x0c, 0x20, 0x03, 0x28, 0x09, 0x42, 0x0c, 0xba, 0x48, 0x09, 0x92, 0x01, 0x06, 0x22, 0x04,
0x72, 0x02, 0x60, 0x01, 0x52, 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x73, 0x12, 0x26,
0x0a, 0x07, 0x74, 0x6f, 0x73, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x42,
0x08, 0xba, 0x48, 0x05, 0x72, 0x03, 0x88, 0x01, 0x01, 0x48, 0x05, 0x52, 0x06, 0x74, 0x6f, 0x73,
0x55, 0x72, 0x69, 0x88, 0x01, 0x01, 0x12, 0x98, 0x01, 0x0a, 0x11, 0x74, 0x6f, 0x73, 0x5f, 0x75,
0x72, 0x69, 0x5f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x18, 0x0e, 0x20, 0x03,
0x28, 0x0b, 0x32, 0x34, 0x2e, 0x69, 0x65, 0x74, 0x66, 0x2e, 0x72, 0x66, 0x63, 0x37, 0x35, 0x39,
0x31, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64,
0x61, 0x74, 0x61, 0x2e, 0x54, 0x6f, 0x73, 0x55, 0x72, 0x69, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x69,
0x7a, 0x65, 0x64, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x42, 0x36, 0xba, 0x48, 0x33, 0x9a, 0x01, 0x30,
0x22, 0x27, 0x72, 0x25, 0x32, 0x23, 0x5e, 0x5b, 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x5d, 0x7b,
0x31, 0x2c, 0x38, 0x7d, 0x28, 0x2d, 0x5b, 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x30, 0x2d, 0x39,
0x5d, 0x7b, 0x31, 0x2c, 0x38, 0x7d, 0x29, 0x2a, 0x24, 0x2a, 0x05, 0x72, 0x03, 0x88, 0x01, 0x01,
0x52, 0x0f, 0x74, 0x6f, 0x73, 0x55, 0x72, 0x69, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x69, 0x7a, 0x65,
0x64, 0x12, 0x2c, 0x0a, 0x0a, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5f, 0x75, 0x72, 0x69, 0x18,
0x0f, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xba, 0x48, 0x05, 0x72, 0x03, 0x88, 0x01, 0x01, 0x48,
0x06, 0x52, 0x09, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x55, 0x72, 0x69, 0x88, 0x01, 0x01, 0x12,
0xa1, 0x01, 0x0a, 0x14, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5f, 0x75, 0x72, 0x69, 0x5f, 0x6c,
0x6f, 0x63, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x18, 0x10, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x37,
0x2e, 0x69, 0x65, 0x74, 0x66, 0x2e, 0x72, 0x66, 0x63, 0x37, 0x35, 0x39, 0x31, 0x2e, 0x76, 0x31,
0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e,
0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x55, 0x72, 0x69, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x69, 0x7a,
0x65, 0x64, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x42, 0x36, 0xba, 0x48, 0x33, 0x9a, 0x01, 0x30, 0x22,
0x27, 0x72, 0x25, 0x32, 0x23, 0x5e, 0x5b, 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x5d, 0x7b, 0x31,
0x2c, 0x38, 0x7d, 0x28, 0x2d, 0x5b, 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x30, 0x2d, 0x39, 0x5d,
0x7b, 0x31, 0x2c, 0x38, 0x7d, 0x29, 0x2a, 0x24, 0x2a, 0x05, 0x72, 0x03, 0x88, 0x01, 0x01, 0x52,
0x12, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x55, 0x72, 0x69, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x69,
0x7a, 0x65, 0x64, 0x12, 0x28, 0x0a, 0x08, 0x6a, 0x77, 0x6b, 0x73, 0x5f, 0x75, 0x72, 0x69, 0x18,
0x11, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xba, 0x48, 0x05, 0x72, 0x03, 0x88, 0x01, 0x01, 0x48,
0x07, 0x52, 0x07, 0x6a, 0x77, 0x6b, 0x73, 0x55, 0x72, 0x69, 0x88, 0x01, 0x01, 0x12, 0x37, 0x0a,
0x04, 0x6a, 0x77, 0x6b, 0x73, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x69, 0x65,
0x74, 0x66, 0x2e, 0x72, 0x66, 0x63, 0x37, 0x35, 0x39, 0x31, 0x2e, 0x76, 0x31, 0x2e, 0x4a, 0x73, 0x74, 0x66, 0x2e, 0x72, 0x66, 0x63, 0x37, 0x35, 0x39, 0x31, 0x2e, 0x76, 0x31, 0x2e, 0x4a, 0x73,
0x6f, 0x6e, 0x57, 0x65, 0x62, 0x4b, 0x65, 0x79, 0x53, 0x65, 0x74, 0x48, 0x08, 0x52, 0x04, 0x6a, 0x6f, 0x6e, 0x57, 0x65, 0x62, 0x4b, 0x65, 0x79, 0x42, 0x0b, 0xba, 0x48, 0x08, 0xc8, 0x01, 0x01,
0x77, 0x6b, 0x73, 0x88, 0x01, 0x01, 0x12, 0x30, 0x0a, 0x0b, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x92, 0x01, 0x02, 0x08, 0x01, 0x52, 0x04, 0x6b, 0x65, 0x79, 0x73, 0x22, 0xcf, 0x07, 0x0a, 0x0a,
0x72, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x13, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xba, 0x48, 0x07, 0x4a, 0x73, 0x6f, 0x6e, 0x57, 0x65, 0x62, 0x4b, 0x65, 0x79, 0x12, 0x2f, 0x0a, 0x03, 0x6b, 0x74,
0x72, 0x05, 0x10, 0x01, 0x18, 0xff, 0x01, 0x48, 0x09, 0x52, 0x0a, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x1d, 0xba, 0x48, 0x1a, 0xc8, 0x01, 0x01, 0x72,
0x61, 0x72, 0x65, 0x49, 0x64, 0x88, 0x01, 0x01, 0x12, 0x3a, 0x0a, 0x10, 0x73, 0x6f, 0x66, 0x74, 0x15, 0x10, 0x01, 0x52, 0x03, 0x52, 0x53, 0x41, 0x52, 0x02, 0x45, 0x43, 0x52, 0x03, 0x6f, 0x63,
0x77, 0x61, 0x72, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x14, 0x20, 0x01, 0x74, 0x52, 0x03, 0x4f, 0x4b, 0x50, 0x52, 0x03, 0x6b, 0x74, 0x79, 0x12, 0x26, 0x0a, 0x03, 0x75,
0x28, 0x09, 0x42, 0x0a, 0xba, 0x48, 0x07, 0x72, 0x05, 0x10, 0x01, 0x18, 0xff, 0x01, 0x48, 0x0a, 0x73, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0f, 0xba, 0x48, 0x0c, 0x72, 0x0a, 0x52,
0x52, 0x0f, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x03, 0x73, 0x69, 0x67, 0x52, 0x03, 0x65, 0x6e, 0x63, 0x48, 0x01, 0x52, 0x03, 0x75, 0x73, 0x65,
0x6e, 0x88, 0x01, 0x01, 0x1a, 0x46, 0x0a, 0x18, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4e, 0x61, 0x88, 0x01, 0x01, 0x12, 0x25, 0x0a, 0x07, 0x6b, 0x65, 0x79, 0x5f, 0x6f, 0x70, 0x73, 0x18, 0x03,
0x6d, 0x65, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x20, 0x03, 0x28, 0x09, 0x42, 0x0c, 0xba, 0x48, 0x09, 0x92, 0x01, 0x06, 0x22, 0x04, 0x72, 0x02,
0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x10, 0x01, 0x52, 0x06, 0x6b, 0x65, 0x79, 0x4f, 0x70, 0x73, 0x12, 0x1e, 0x0a, 0x03, 0x61, 0x6c,
0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xba, 0x48, 0x04, 0x72, 0x02, 0x10, 0x01,
0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x45, 0x0a, 0x17, 0x48, 0x02, 0x52, 0x03, 0x61, 0x6c, 0x67, 0x88, 0x01, 0x01, 0x12, 0x1e, 0x0a, 0x03, 0x6b, 0x69,
0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x55, 0x72, 0x69, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x69, 0x7a, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xba, 0x48, 0x04, 0x72, 0x02, 0x10, 0x01,
0x48, 0x03, 0x52, 0x03, 0x6b, 0x69, 0x64, 0x88, 0x01, 0x01, 0x12, 0x42, 0x0a, 0x0a, 0x72, 0x73,
0x61, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21,
0x2e, 0x69, 0x65, 0x74, 0x66, 0x2e, 0x72, 0x66, 0x63, 0x37, 0x35, 0x39, 0x31, 0x2e, 0x76, 0x31,
0x2e, 0x52, 0x73, 0x61, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72,
0x73, 0x48, 0x00, 0x52, 0x09, 0x72, 0x73, 0x61, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x3f,
0x0a, 0x09, 0x65, 0x63, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x20, 0x2e, 0x69, 0x65, 0x74, 0x66, 0x2e, 0x72, 0x66, 0x63, 0x37, 0x35, 0x39, 0x31,
0x2e, 0x76, 0x31, 0x2e, 0x45, 0x63, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74,
0x65, 0x72, 0x73, 0x48, 0x00, 0x52, 0x08, 0x65, 0x63, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12,
0x54, 0x0a, 0x10, 0x73, 0x79, 0x6d, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x5f, 0x70, 0x61, 0x72,
0x61, 0x6d, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x69, 0x65, 0x74, 0x66,
0x2e, 0x72, 0x66, 0x63, 0x37, 0x35, 0x39, 0x31, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x79, 0x6d, 0x6d,
0x65, 0x74, 0x72, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65,
0x72, 0x73, 0x48, 0x00, 0x52, 0x0f, 0x73, 0x79, 0x6d, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x50,
0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x42, 0x0a, 0x0a, 0x6f, 0x6b, 0x70, 0x5f, 0x70, 0x61, 0x72,
0x61, 0x6d, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x69, 0x65, 0x74, 0x66,
0x2e, 0x72, 0x66, 0x63, 0x37, 0x35, 0x39, 0x31, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x6b, 0x70, 0x4b,
0x65, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x48, 0x00, 0x52, 0x09,
0x6f, 0x6b, 0x70, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x3a, 0xab, 0x03, 0xba, 0x48, 0xa7, 0x03,
0x1a, 0x66, 0x0a, 0x12, 0x6a, 0x77, 0x6b, 0x2e, 0x6b, 0x74, 0x79, 0x5f, 0x70, 0x61, 0x72, 0x61,
0x6d, 0x73, 0x2e, 0x72, 0x73, 0x61, 0x12, 0x25, 0x72, 0x73, 0x61, 0x5f, 0x70, 0x61, 0x72, 0x61,
0x6d, 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x20,
0x66, 0x6f, 0x72, 0x20, 0x6b, 0x74, 0x79, 0x20, 0x27, 0x52, 0x53, 0x41, 0x27, 0x1a, 0x29, 0x74,
0x68, 0x69, 0x73, 0x2e, 0x6b, 0x74, 0x79, 0x20, 0x21, 0x3d, 0x20, 0x27, 0x52, 0x53, 0x41, 0x27,
0x20, 0x7c, 0x7c, 0x20, 0x68, 0x61, 0x73, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x72, 0x73, 0x61,
0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x29, 0x1a, 0x61, 0x0a, 0x11, 0x6a, 0x77, 0x6b, 0x2e,
0x6b, 0x74, 0x79, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x2e, 0x65, 0x63, 0x12, 0x23, 0x65,
0x63, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x72, 0x65, 0x71,
0x75, 0x69, 0x72, 0x65, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x6b, 0x74, 0x79, 0x20, 0x27, 0x45,
0x43, 0x27, 0x1a, 0x27, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6b, 0x74, 0x79, 0x20, 0x21, 0x3d, 0x20,
0x27, 0x45, 0x43, 0x27, 0x20, 0x7c, 0x7c, 0x20, 0x68, 0x61, 0x73, 0x28, 0x74, 0x68, 0x69, 0x73,
0x2e, 0x65, 0x63, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x29, 0x1a, 0x72, 0x0a, 0x12, 0x6a,
0x77, 0x6b, 0x2e, 0x6b, 0x74, 0x79, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x2e, 0x6f, 0x63,
0x74, 0x12, 0x2b, 0x73, 0x79, 0x6d, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x5f, 0x70, 0x61, 0x72,
0x61, 0x6d, 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64,
0x20, 0x66, 0x6f, 0x72, 0x20, 0x6b, 0x74, 0x79, 0x20, 0x27, 0x6f, 0x63, 0x74, 0x27, 0x1a, 0x2f,
0x74, 0x68, 0x69, 0x73, 0x2e, 0x6b, 0x74, 0x79, 0x20, 0x21, 0x3d, 0x20, 0x27, 0x6f, 0x63, 0x74,
0x27, 0x20, 0x7c, 0x7c, 0x20, 0x68, 0x61, 0x73, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x73, 0x79,
0x6d, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x29, 0x1a,
0x66, 0x0a, 0x12, 0x6a, 0x77, 0x6b, 0x2e, 0x6b, 0x74, 0x79, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d,
0x73, 0x2e, 0x6f, 0x6b, 0x70, 0x12, 0x25, 0x6f, 0x6b, 0x70, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d,
0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x20, 0x66,
0x6f, 0x72, 0x20, 0x6b, 0x74, 0x79, 0x20, 0x27, 0x4f, 0x4b, 0x50, 0x27, 0x1a, 0x29, 0x74, 0x68,
0x69, 0x73, 0x2e, 0x6b, 0x74, 0x79, 0x20, 0x21, 0x3d, 0x20, 0x27, 0x4f, 0x4b, 0x50, 0x27, 0x20,
0x7c, 0x7c, 0x20, 0x68, 0x61, 0x73, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6f, 0x6b, 0x70, 0x5f,
0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x29, 0x42, 0x1c, 0x0a, 0x13, 0x6b, 0x65, 0x79, 0x5f, 0x74,
0x79, 0x70, 0x65, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x12, 0x05,
0xba, 0x48, 0x02, 0x08, 0x00, 0x42, 0x06, 0x0a, 0x04, 0x5f, 0x75, 0x73, 0x65, 0x42, 0x06, 0x0a,
0x04, 0x5f, 0x61, 0x6c, 0x67, 0x42, 0x06, 0x0a, 0x04, 0x5f, 0x6b, 0x69, 0x64, 0x22, 0x46, 0x0a,
0x10, 0x52, 0x73, 0x61, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72,
0x73, 0x12, 0x18, 0x0a, 0x01, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xba, 0x48,
0x07, 0xc8, 0x01, 0x01, 0x72, 0x02, 0x10, 0x01, 0x52, 0x01, 0x6e, 0x12, 0x18, 0x0a, 0x01, 0x65,
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xba, 0x48, 0x07, 0xc8, 0x01, 0x01, 0x72, 0x02,
0x10, 0x01, 0x52, 0x01, 0x65, 0x22, 0x76, 0x0a, 0x0f, 0x45, 0x63, 0x4b, 0x65, 0x79, 0x50, 0x61,
0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x12, 0x2f, 0x0a, 0x03, 0x63, 0x72, 0x76, 0x18,
0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x1d, 0xba, 0x48, 0x1a, 0xc8, 0x01, 0x01, 0x72, 0x15, 0x52,
0x05, 0x50, 0x2d, 0x32, 0x35, 0x36, 0x52, 0x05, 0x50, 0x2d, 0x33, 0x38, 0x34, 0x52, 0x05, 0x50,
0x2d, 0x35, 0x32, 0x31, 0x52, 0x03, 0x63, 0x72, 0x76, 0x12, 0x18, 0x0a, 0x01, 0x78, 0x18, 0x02,
0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xba, 0x48, 0x07, 0xc8, 0x01, 0x01, 0x72, 0x02, 0x10, 0x01,
0x52, 0x01, 0x78, 0x12, 0x18, 0x0a, 0x01, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a,
0xba, 0x48, 0x07, 0xc8, 0x01, 0x01, 0x72, 0x02, 0x10, 0x01, 0x52, 0x01, 0x79, 0x22, 0x32, 0x0a,
0x16, 0x53, 0x79, 0x6d, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x72,
0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x12, 0x18, 0x0a, 0x01, 0x6b, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x42, 0x0a, 0xba, 0x48, 0x07, 0xc8, 0x01, 0x01, 0x72, 0x02, 0x10, 0x01, 0x52, 0x01,
0x6b, 0x22, 0x7e, 0x0a, 0x10, 0x4f, 0x6b, 0x70, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d,
0x65, 0x74, 0x65, 0x72, 0x73, 0x12, 0x38, 0x0a, 0x03, 0x63, 0x72, 0x76, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x42, 0x26, 0xba, 0x48, 0x23, 0xc8, 0x01, 0x01, 0x72, 0x1e, 0x52, 0x07, 0x45, 0x64,
0x32, 0x35, 0x35, 0x31, 0x39, 0x52, 0x05, 0x45, 0x64, 0x34, 0x34, 0x38, 0x52, 0x06, 0x58, 0x32,
0x35, 0x35, 0x31, 0x39, 0x52, 0x04, 0x58, 0x34, 0x34, 0x38, 0x52, 0x03, 0x63, 0x72, 0x76, 0x12,
0x30, 0x0a, 0x01, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x22, 0xba, 0x48, 0x1f, 0xc8,
0x01, 0x01, 0x72, 0x1a, 0x10, 0x01, 0x32, 0x16, 0x5e, 0x5b, 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a,
0x30, 0x2d, 0x39, 0x2d, 0x5f, 0x5d, 0x2b, 0x3d, 0x7b, 0x30, 0x2c, 0x32, 0x7d, 0x24, 0x52, 0x01,
0x78, 0x22, 0xa5, 0x11, 0x0a, 0x08, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x36,
0x0a, 0x0d, 0x72, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x5f, 0x75, 0x72, 0x69, 0x73, 0x18,
0x01, 0x20, 0x03, 0x28, 0x09, 0x42, 0x11, 0xba, 0x48, 0x0e, 0x92, 0x01, 0x0b, 0x08, 0x01, 0x22,
0x07, 0x72, 0x05, 0x10, 0x01, 0x88, 0x01, 0x01, 0x52, 0x0c, 0x72, 0x65, 0x64, 0x69, 0x72, 0x65,
0x63, 0x74, 0x55, 0x72, 0x69, 0x73, 0x12, 0x76, 0x0a, 0x1a, 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, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x34, 0xba, 0x48, 0x31, 0x72,
0x2f, 0x52, 0x04, 0x6e, 0x6f, 0x6e, 0x65, 0x52, 0x12, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f,
0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x5f, 0x70, 0x6f, 0x73, 0x74, 0x52, 0x13, 0x63, 0x6c, 0x69,
0x65, 0x6e, 0x74, 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x5f, 0x62, 0x61, 0x73, 0x69, 0x63,
0x48, 0x00, 0x52, 0x17, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e,
0x74, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x88, 0x01, 0x01, 0x12, 0x1f,
0x0a, 0x0b, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, 0x03, 0x20,
0x03, 0x28, 0x09, 0x52, 0x0a, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x73, 0x12,
0x25, 0x0a, 0x0e, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65,
0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x12, 0x30, 0x0a, 0x0b, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74,
0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xba, 0x48, 0x07,
0x72, 0x05, 0x10, 0x01, 0x18, 0xff, 0x01, 0x48, 0x01, 0x52, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e,
0x74, 0x4e, 0x61, 0x6d, 0x65, 0x88, 0x01, 0x01, 0x12, 0xa0, 0x01, 0x0a, 0x15, 0x63, 0x6c, 0x69,
0x65, 0x6e, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x69, 0x7a,
0x65, 0x64, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x69, 0x65, 0x74, 0x66, 0x2e,
0x72, 0x66, 0x63, 0x37, 0x35, 0x39, 0x31, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64,
0x61, 0x74, 0x61, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x4c, 0x6f,
0x63, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x42, 0x38, 0xba, 0x48,
0x35, 0x9a, 0x01, 0x32, 0x22, 0x27, 0x72, 0x25, 0x32, 0x23, 0x5e, 0x5b, 0x61, 0x2d, 0x7a, 0x41,
0x2d, 0x5a, 0x5d, 0x7b, 0x31, 0x2c, 0x38, 0x7d, 0x28, 0x2d, 0x5b, 0x61, 0x2d, 0x7a, 0x41, 0x2d,
0x5a, 0x30, 0x2d, 0x39, 0x5d, 0x7b, 0x31, 0x2c, 0x38, 0x7d, 0x29, 0x2a, 0x24, 0x2a, 0x07, 0x72,
0x05, 0x10, 0x01, 0x18, 0xff, 0x01, 0x52, 0x13, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4e, 0x61,
0x6d, 0x65, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x12, 0x2c, 0x0a, 0x0a, 0x63,
0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x42,
0x08, 0xba, 0x48, 0x05, 0x72, 0x03, 0x88, 0x01, 0x01, 0x48, 0x02, 0x52, 0x09, 0x63, 0x6c, 0x69,
0x65, 0x6e, 0x74, 0x55, 0x72, 0x69, 0x88, 0x01, 0x01, 0x12, 0x9b, 0x01, 0x0a, 0x14, 0x63, 0x6c,
0x69, 0x65, 0x6e, 0x74, 0x5f, 0x75, 0x72, 0x69, 0x5f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x69, 0x7a,
0x65, 0x64, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x69, 0x65, 0x74, 0x66, 0x2e,
0x72, 0x66, 0x63, 0x37, 0x35, 0x39, 0x31, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64,
0x61, 0x74, 0x61, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x55, 0x72, 0x69, 0x4c, 0x6f, 0x63,
0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x42, 0x36, 0xba, 0x48, 0x33,
0x9a, 0x01, 0x30, 0x22, 0x27, 0x72, 0x25, 0x32, 0x23, 0x5e, 0x5b, 0x61, 0x2d, 0x7a, 0x41, 0x2d,
0x5a, 0x5d, 0x7b, 0x31, 0x2c, 0x38, 0x7d, 0x28, 0x2d, 0x5b, 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a,
0x30, 0x2d, 0x39, 0x5d, 0x7b, 0x31, 0x2c, 0x38, 0x7d, 0x29, 0x2a, 0x24, 0x2a, 0x05, 0x72, 0x03,
0x88, 0x01, 0x01, 0x52, 0x12, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x55, 0x72, 0x69, 0x4c, 0x6f,
0x63, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x12, 0x28, 0x0a, 0x08, 0x6c, 0x6f, 0x67, 0x6f, 0x5f,
0x75, 0x72, 0x69, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xba, 0x48, 0x05, 0x72, 0x03,
0x88, 0x01, 0x01, 0x48, 0x03, 0x52, 0x07, 0x6c, 0x6f, 0x67, 0x6f, 0x55, 0x72, 0x69, 0x88, 0x01,
0x01, 0x12, 0x95, 0x01, 0x0a, 0x12, 0x6c, 0x6f, 0x67, 0x6f, 0x5f, 0x75, 0x72, 0x69, 0x5f, 0x6c,
0x6f, 0x63, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f,
0x2e, 0x69, 0x65, 0x74, 0x66, 0x2e, 0x72, 0x66, 0x63, 0x37, 0x35, 0x39, 0x31, 0x2e, 0x76, 0x31,
0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x4c, 0x6f, 0x67, 0x6f, 0x55, 0x72,
0x69, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x42,
0x36, 0xba, 0x48, 0x33, 0x9a, 0x01, 0x30, 0x22, 0x27, 0x72, 0x25, 0x32, 0x23, 0x5e, 0x5b, 0x61,
0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x5d, 0x7b, 0x31, 0x2c, 0x38, 0x7d, 0x28, 0x2d, 0x5b, 0x61, 0x2d,
0x7a, 0x41, 0x2d, 0x5a, 0x30, 0x2d, 0x39, 0x5d, 0x7b, 0x31, 0x2c, 0x38, 0x7d, 0x29, 0x2a, 0x24,
0x2a, 0x05, 0x72, 0x03, 0x88, 0x01, 0x01, 0x52, 0x10, 0x6c, 0x6f, 0x67, 0x6f, 0x55, 0x72, 0x69,
0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x12, 0x30, 0x0a, 0x05, 0x73, 0x63, 0x6f,
0x70, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x42, 0x15, 0xba, 0x48, 0x12, 0x72, 0x10, 0x10,
0x01, 0x32, 0x0c, 0x5e, 0x5c, 0x53, 0x2b, 0x28, 0x20, 0x5c, 0x53, 0x2b, 0x29, 0x2a, 0x24, 0x48,
0x04, 0x52, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x88, 0x01, 0x01, 0x12, 0x28, 0x0a, 0x08, 0x63,
0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x73, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x09, 0x42, 0x0c, 0xba,
0x48, 0x09, 0x92, 0x01, 0x06, 0x22, 0x04, 0x72, 0x02, 0x60, 0x01, 0x52, 0x08, 0x63, 0x6f, 0x6e,
0x74, 0x61, 0x63, 0x74, 0x73, 0x12, 0x26, 0x0a, 0x07, 0x74, 0x6f, 0x73, 0x5f, 0x75, 0x72, 0x69,
0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xba, 0x48, 0x05, 0x72, 0x03, 0x88, 0x01, 0x01,
0x48, 0x05, 0x52, 0x06, 0x74, 0x6f, 0x73, 0x55, 0x72, 0x69, 0x88, 0x01, 0x01, 0x12, 0x92, 0x01,
0x0a, 0x11, 0x74, 0x6f, 0x73, 0x5f, 0x75, 0x72, 0x69, 0x5f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x69,
0x7a, 0x65, 0x64, 0x18, 0x0e, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x69, 0x65, 0x74, 0x66,
0x2e, 0x72, 0x66, 0x63, 0x37, 0x35, 0x39, 0x31, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x61,
0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x6f, 0x73, 0x55, 0x72, 0x69, 0x4c, 0x6f, 0x63, 0x61, 0x6c,
0x69, 0x7a, 0x65, 0x64, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x42, 0x36, 0xba, 0x48, 0x33, 0x9a, 0x01,
0x30, 0x22, 0x27, 0x72, 0x25, 0x32, 0x23, 0x5e, 0x5b, 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x5d,
0x7b, 0x31, 0x2c, 0x38, 0x7d, 0x28, 0x2d, 0x5b, 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x30, 0x2d,
0x39, 0x5d, 0x7b, 0x31, 0x2c, 0x38, 0x7d, 0x29, 0x2a, 0x24, 0x2a, 0x05, 0x72, 0x03, 0x88, 0x01,
0x01, 0x52, 0x0f, 0x74, 0x6f, 0x73, 0x55, 0x72, 0x69, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x69, 0x7a,
0x65, 0x64, 0x12, 0x2c, 0x0a, 0x0a, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5f, 0x75, 0x72, 0x69,
0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xba, 0x48, 0x05, 0x72, 0x03, 0x88, 0x01, 0x01,
0x48, 0x06, 0x52, 0x09, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x55, 0x72, 0x69, 0x88, 0x01, 0x01,
0x12, 0x9b, 0x01, 0x0a, 0x14, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5f, 0x75, 0x72, 0x69, 0x5f,
0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x18, 0x10, 0x20, 0x03, 0x28, 0x0b, 0x32,
0x31, 0x2e, 0x69, 0x65, 0x74, 0x66, 0x2e, 0x72, 0x66, 0x63, 0x37, 0x35, 0x39, 0x31, 0x2e, 0x76,
0x31, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63,
0x79, 0x55, 0x72, 0x69, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x45, 0x6e, 0x74,
0x72, 0x79, 0x42, 0x36, 0xba, 0x48, 0x33, 0x9a, 0x01, 0x30, 0x22, 0x27, 0x72, 0x25, 0x32, 0x23,
0x5e, 0x5b, 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x5d, 0x7b, 0x31, 0x2c, 0x38, 0x7d, 0x28, 0x2d,
0x5b, 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x30, 0x2d, 0x39, 0x5d, 0x7b, 0x31, 0x2c, 0x38, 0x7d,
0x29, 0x2a, 0x24, 0x2a, 0x05, 0x72, 0x03, 0x88, 0x01, 0x01, 0x52, 0x12, 0x70, 0x6f, 0x6c, 0x69,
0x63, 0x79, 0x55, 0x72, 0x69, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x12, 0x28,
0x0a, 0x08, 0x6a, 0x77, 0x6b, 0x73, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x11, 0x20, 0x01, 0x28, 0x09,
0x42, 0x08, 0xba, 0x48, 0x05, 0x72, 0x03, 0x88, 0x01, 0x01, 0x48, 0x07, 0x52, 0x07, 0x6a, 0x77,
0x6b, 0x73, 0x55, 0x72, 0x69, 0x88, 0x01, 0x01, 0x12, 0x37, 0x0a, 0x04, 0x6a, 0x77, 0x6b, 0x73,
0x18, 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x69, 0x65, 0x74, 0x66, 0x2e, 0x72, 0x66,
0x63, 0x37, 0x35, 0x39, 0x31, 0x2e, 0x76, 0x31, 0x2e, 0x4a, 0x73, 0x6f, 0x6e, 0x57, 0x65, 0x62,
0x4b, 0x65, 0x79, 0x53, 0x65, 0x74, 0x48, 0x08, 0x52, 0x04, 0x6a, 0x77, 0x6b, 0x73, 0x88, 0x01,
0x01, 0x12, 0x30, 0x0a, 0x0b, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x5f, 0x69, 0x64,
0x18, 0x13, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xba, 0x48, 0x07, 0x72, 0x05, 0x10, 0x01, 0x18,
0xff, 0x01, 0x48, 0x09, 0x52, 0x0a, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x49, 0x64,
0x88, 0x01, 0x01, 0x12, 0x3a, 0x0a, 0x10, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x5f,
0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xba,
0x48, 0x07, 0x72, 0x05, 0x10, 0x01, 0x18, 0xff, 0x01, 0x48, 0x0a, 0x52, 0x0f, 0x73, 0x6f, 0x66,
0x74, 0x77, 0x61, 0x72, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x1a,
0x46, 0x0a, 0x18, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x4c, 0x6f, 0x63,
0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b,
0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a,
0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61,
0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x45, 0x0a, 0x17, 0x43, 0x6c, 0x69, 0x65, 0x6e,
0x74, 0x55, 0x72, 0x69, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x45, 0x6e, 0x74,
0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20,
0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x43,
0x0a, 0x15, 0x4c, 0x6f, 0x67, 0x6f, 0x55, 0x72, 0x69, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x69, 0x7a,
0x65, 0x64, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x65, 0x64, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c,
0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a,
0x02, 0x38, 0x01, 0x1a, 0x43, 0x0a, 0x15, 0x4c, 0x6f, 0x67, 0x6f, 0x55, 0x72, 0x69, 0x4c, 0x6f, 0x02, 0x38, 0x01, 0x1a, 0x42, 0x0a, 0x14, 0x54, 0x6f, 0x73, 0x55, 0x72, 0x69, 0x4c, 0x6f, 0x63,
0x63, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b,
0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a,
0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61,
0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x42, 0x0a, 0x14, 0x54, 0x6f, 0x73, 0x55, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x45, 0x0a, 0x17, 0x50, 0x6f, 0x6c, 0x69, 0x63,
0x72, 0x69, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x79, 0x55, 0x72, 0x69, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x45, 0x6e, 0x74,
0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20,
0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x45, 0x0a, 0x17, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x3a, 0x7e,
0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x55, 0x72, 0x69, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x69, 0x7a, 0xba, 0x48, 0x7b, 0x1a, 0x79, 0x0a, 0x25, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x65,
0x65, 0x64, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x6a, 0x77, 0x6b, 0x73, 0x5f, 0x6d, 0x75, 0x74, 0x75,
0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x61, 0x6c, 0x5f, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x28, 0x6a, 0x77,
0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x6b, 0x73, 0x5f, 0x75, 0x72, 0x69, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6a, 0x77, 0x6b, 0x73, 0x20,
0x02, 0x38, 0x01, 0x3a, 0x7e, 0xba, 0x48, 0x7b, 0x1a, 0x79, 0x0a, 0x25, 0x63, 0x6c, 0x69, 0x65, 0x61, 0x72, 0x65, 0x20, 0x6d, 0x75, 0x74, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x20, 0x65, 0x78, 0x63,
0x6e, 0x74, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x6a, 0x77, 0x6b, 0x73, 0x6c, 0x75, 0x73, 0x69, 0x76, 0x65, 0x1a, 0x26, 0x21, 0x68, 0x61, 0x73, 0x28, 0x74, 0x68, 0x69,
0x5f, 0x6d, 0x75, 0x74, 0x75, 0x61, 0x6c, 0x5f, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x6f, 0x73, 0x2e, 0x6a, 0x77, 0x6b, 0x73, 0x5f, 0x75, 0x72, 0x69, 0x29, 0x20, 0x7c, 0x7c, 0x20, 0x21,
0x6e, 0x12, 0x28, 0x6a, 0x77, 0x6b, 0x73, 0x5f, 0x75, 0x72, 0x69, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x68, 0x61, 0x73, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6a, 0x77, 0x6b, 0x73, 0x29, 0x42, 0x1d,
0x6a, 0x77, 0x6b, 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x6d, 0x75, 0x74, 0x75, 0x61, 0x6c, 0x6c, 0x0a, 0x1b, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e,
0x79, 0x20, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x76, 0x65, 0x1a, 0x26, 0x21, 0x68, 0x61, 0x74, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x42, 0x0e, 0x0a,
0x73, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6a, 0x77, 0x6b, 0x73, 0x5f, 0x75, 0x72, 0x69, 0x29, 0x0c, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x42, 0x0d, 0x0a,
0x20, 0x7c, 0x7c, 0x20, 0x21, 0x68, 0x61, 0x73, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6a, 0x77, 0x0b, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x75, 0x72, 0x69, 0x42, 0x0b, 0x0a, 0x09,
0x6b, 0x73, 0x29, 0x42, 0x1d, 0x0a, 0x1b, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x65, 0x6e, 0x5f, 0x6c, 0x6f, 0x67, 0x6f, 0x5f, 0x75, 0x72, 0x69, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x73, 0x63,
0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x70, 0x65, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x74, 0x6f, 0x73, 0x5f, 0x75, 0x72, 0x69, 0x42,
0x6f, 0x64, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x6e, 0x61, 0x0d, 0x0a, 0x0b, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5f, 0x75, 0x72, 0x69, 0x42, 0x0b,
0x6d, 0x65, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x75, 0x72, 0x0a, 0x09, 0x5f, 0x6a, 0x77, 0x6b, 0x73, 0x5f, 0x75, 0x72, 0x69, 0x42, 0x07, 0x0a, 0x05, 0x5f,
0x69, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x6c, 0x6f, 0x67, 0x6f, 0x5f, 0x75, 0x72, 0x69, 0x42, 0x08, 0x6a, 0x77, 0x6b, 0x73, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72,
0x0a, 0x06, 0x5f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x74, 0x6f, 0x73, 0x65, 0x5f, 0x69, 0x64, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72,
0x5f, 0x75, 0x72, 0x69, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5f, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0xc2, 0x01, 0x0a, 0x0c, 0x43, 0x6c,
0x75, 0x72, 0x69, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x6a, 0x77, 0x6b, 0x73, 0x5f, 0x75, 0x72, 0x69, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x20, 0x0a, 0x05, 0x76, 0x61,
0x42, 0x07, 0x0a, 0x05, 0x5f, 0x6a, 0x77, 0x6b, 0x73, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x73, 0x6f, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xba, 0x48, 0x07, 0xc8, 0x01,
0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x5f, 0x69, 0x64, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x73, 0x6f, 0x01, 0x72, 0x02, 0x10, 0x01, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x3e, 0x0a, 0x0a,
0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x42, 0xba, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x5f, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,
0x01, 0x0a, 0x13, 0x63, 0x6f, 0x6d, 0x2e, 0x69, 0x65, 0x74, 0x66, 0x2e, 0x72, 0x66, 0x63, 0x37, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
0x35, 0x39, 0x31, 0x2e, 0x76, 0x31, 0x42, 0x0a, 0x54, 0x79, 0x70, 0x65, 0x73, 0x50, 0x72, 0x6f, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x48, 0x00, 0x52, 0x09,
0x74, 0x6f, 0x50, 0x01, 0x5a, 0x39, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x41, 0x74, 0x88, 0x01, 0x01, 0x12, 0x41, 0x0a, 0x0a,
0x2f, 0x70, 0x6f, 0x6d, 0x65, 0x72, 0x69, 0x75, 0x6d, 0x2f, 0x70, 0x6f, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b,
0x75, 0x6d, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x72, 0x66, 0x63, 0x37, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
0x35, 0x39, 0x31, 0x76, 0x31, 0x3b, 0x72, 0x66, 0x63, 0x37, 0x35, 0x39, 0x31, 0x76, 0x31, 0xa2, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x42, 0x06, 0xba, 0x48,
0x02, 0x03, 0x49, 0x52, 0x58, 0xaa, 0x02, 0x0f, 0x49, 0x65, 0x74, 0x66, 0x2e, 0x52, 0x66, 0x63, 0x03, 0xc8, 0x01, 0x01, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x42,
0x37, 0x35, 0x39, 0x31, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x0f, 0x49, 0x65, 0x74, 0x66, 0x5c, 0x52, 0x0d, 0x0a, 0x0b, 0x5f, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x5f, 0x61, 0x74, 0x22, 0xf6,
0x66, 0x63, 0x37, 0x35, 0x39, 0x31, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x1b, 0x49, 0x65, 0x74, 0x66, 0x01, 0x0a, 0x12, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72,
0x5c, 0x52, 0x66, 0x63, 0x37, 0x35, 0x39, 0x31, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4c, 0x0a, 0x10, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x11, 0x49, 0x65, 0x74, 0x66, 0x3a, 0x3a, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x52, 0x66, 0x63, 0x37, 0x35, 0x39, 0x31, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x19, 0x2e, 0x69, 0x65, 0x74, 0x66, 0x2e, 0x72, 0x66, 0x63, 0x37, 0x35, 0x39, 0x31, 0x2e, 0x76,
0x74, 0x6f, 0x33, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x42, 0x06, 0xba, 0x48, 0x03, 0xc8,
0x01, 0x01, 0x52, 0x0f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64,
0x61, 0x74, 0x61, 0x12, 0x4e, 0x0a, 0x11, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f,
0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19,
0x2e, 0x69, 0x65, 0x74, 0x66, 0x2e, 0x72, 0x66, 0x63, 0x37, 0x35, 0x39, 0x31, 0x2e, 0x76, 0x31,
0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x42, 0x06, 0xba, 0x48, 0x03, 0xc8, 0x01,
0x01, 0x52, 0x10, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64,
0x61, 0x74, 0x61, 0x12, 0x42, 0x0a, 0x0d, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x65,
0x63, 0x72, 0x65, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x69, 0x65, 0x74,
0x66, 0x2e, 0x72, 0x66, 0x63, 0x37, 0x35, 0x39, 0x31, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x69,
0x65, 0x6e, 0x74, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x52, 0x0c, 0x63, 0x6c, 0x69, 0x65, 0x6e,
0x74, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x42, 0xba, 0x01, 0x0a, 0x13, 0x63, 0x6f, 0x6d, 0x2e,
0x69, 0x65, 0x74, 0x66, 0x2e, 0x72, 0x66, 0x63, 0x37, 0x35, 0x39, 0x31, 0x2e, 0x76, 0x31, 0x42,
0x0a, 0x54, 0x79, 0x70, 0x65, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x39, 0x67,
0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x6f, 0x6d, 0x65, 0x72, 0x69,
0x75, 0x6d, 0x2f, 0x70, 0x6f, 0x6d, 0x65, 0x72, 0x69, 0x75, 0x6d, 0x2f, 0x69, 0x6e, 0x74, 0x65,
0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x72, 0x66, 0x63, 0x37, 0x35, 0x39, 0x31, 0x76, 0x31, 0x3b, 0x72,
0x66, 0x63, 0x37, 0x35, 0x39, 0x31, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x49, 0x52, 0x58, 0xaa, 0x02,
0x0f, 0x49, 0x65, 0x74, 0x66, 0x2e, 0x52, 0x66, 0x63, 0x37, 0x35, 0x39, 0x31, 0x2e, 0x56, 0x31,
0xca, 0x02, 0x0f, 0x49, 0x65, 0x74, 0x66, 0x5c, 0x52, 0x66, 0x63, 0x37, 0x35, 0x39, 0x31, 0x5c,
0x56, 0x31, 0xe2, 0x02, 0x1b, 0x49, 0x65, 0x74, 0x66, 0x5c, 0x52, 0x66, 0x63, 0x37, 0x35, 0x39,
0x31, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
0xea, 0x02, 0x11, 0x49, 0x65, 0x74, 0x66, 0x3a, 0x3a, 0x52, 0x66, 0x63, 0x37, 0x35, 0x39, 0x31,
0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}) })
var ( var (
@ -972,7 +1113,7 @@ func file_types_proto_rawDescGZIP() []byte {
return file_types_proto_rawDescData return file_types_proto_rawDescData
} }
var file_types_proto_msgTypes = make([]protoimpl.MessageInfo, 12) var file_types_proto_msgTypes = make([]protoimpl.MessageInfo, 14)
var file_types_proto_goTypes = []any{ var file_types_proto_goTypes = []any{
(*JsonWebKeySet)(nil), // 0: ietf.rfc7591.v1.JsonWebKeySet (*JsonWebKeySet)(nil), // 0: ietf.rfc7591.v1.JsonWebKeySet
(*JsonWebKey)(nil), // 1: ietf.rfc7591.v1.JsonWebKey (*JsonWebKey)(nil), // 1: ietf.rfc7591.v1.JsonWebKey
@ -980,12 +1121,15 @@ var file_types_proto_goTypes = []any{
(*EcKeyParameters)(nil), // 3: ietf.rfc7591.v1.EcKeyParameters (*EcKeyParameters)(nil), // 3: ietf.rfc7591.v1.EcKeyParameters
(*SymmetricKeyParameters)(nil), // 4: ietf.rfc7591.v1.SymmetricKeyParameters (*SymmetricKeyParameters)(nil), // 4: ietf.rfc7591.v1.SymmetricKeyParameters
(*OkpKeyParameters)(nil), // 5: ietf.rfc7591.v1.OkpKeyParameters (*OkpKeyParameters)(nil), // 5: ietf.rfc7591.v1.OkpKeyParameters
(*ClientMetadata)(nil), // 6: ietf.rfc7591.v1.ClientMetadata (*Metadata)(nil), // 6: ietf.rfc7591.v1.Metadata
nil, // 7: ietf.rfc7591.v1.ClientMetadata.ClientNameLocalizedEntry (*ClientSecret)(nil), // 7: ietf.rfc7591.v1.ClientSecret
nil, // 8: ietf.rfc7591.v1.ClientMetadata.ClientUriLocalizedEntry (*ClientRegistration)(nil), // 8: ietf.rfc7591.v1.ClientRegistration
nil, // 9: ietf.rfc7591.v1.ClientMetadata.LogoUriLocalizedEntry nil, // 9: ietf.rfc7591.v1.Metadata.ClientNameLocalizedEntry
nil, // 10: ietf.rfc7591.v1.ClientMetadata.TosUriLocalizedEntry nil, // 10: ietf.rfc7591.v1.Metadata.ClientUriLocalizedEntry
nil, // 11: ietf.rfc7591.v1.ClientMetadata.PolicyUriLocalizedEntry nil, // 11: ietf.rfc7591.v1.Metadata.LogoUriLocalizedEntry
nil, // 12: ietf.rfc7591.v1.Metadata.TosUriLocalizedEntry
nil, // 13: ietf.rfc7591.v1.Metadata.PolicyUriLocalizedEntry
(*timestamppb.Timestamp)(nil), // 14: google.protobuf.Timestamp
} }
var file_types_proto_depIdxs = []int32{ var file_types_proto_depIdxs = []int32{
1, // 0: ietf.rfc7591.v1.JsonWebKeySet.keys:type_name -> ietf.rfc7591.v1.JsonWebKey 1, // 0: ietf.rfc7591.v1.JsonWebKeySet.keys:type_name -> ietf.rfc7591.v1.JsonWebKey
@ -993,17 +1137,22 @@ var file_types_proto_depIdxs = []int32{
3, // 2: ietf.rfc7591.v1.JsonWebKey.ec_params:type_name -> ietf.rfc7591.v1.EcKeyParameters 3, // 2: ietf.rfc7591.v1.JsonWebKey.ec_params:type_name -> ietf.rfc7591.v1.EcKeyParameters
4, // 3: ietf.rfc7591.v1.JsonWebKey.symmetric_params:type_name -> ietf.rfc7591.v1.SymmetricKeyParameters 4, // 3: ietf.rfc7591.v1.JsonWebKey.symmetric_params:type_name -> ietf.rfc7591.v1.SymmetricKeyParameters
5, // 4: ietf.rfc7591.v1.JsonWebKey.okp_params:type_name -> ietf.rfc7591.v1.OkpKeyParameters 5, // 4: ietf.rfc7591.v1.JsonWebKey.okp_params:type_name -> ietf.rfc7591.v1.OkpKeyParameters
7, // 5: ietf.rfc7591.v1.ClientMetadata.client_name_localized:type_name -> ietf.rfc7591.v1.ClientMetadata.ClientNameLocalizedEntry 9, // 5: ietf.rfc7591.v1.Metadata.client_name_localized:type_name -> ietf.rfc7591.v1.Metadata.ClientNameLocalizedEntry
8, // 6: ietf.rfc7591.v1.ClientMetadata.client_uri_localized:type_name -> ietf.rfc7591.v1.ClientMetadata.ClientUriLocalizedEntry 10, // 6: ietf.rfc7591.v1.Metadata.client_uri_localized:type_name -> ietf.rfc7591.v1.Metadata.ClientUriLocalizedEntry
9, // 7: ietf.rfc7591.v1.ClientMetadata.logo_uri_localized:type_name -> ietf.rfc7591.v1.ClientMetadata.LogoUriLocalizedEntry 11, // 7: ietf.rfc7591.v1.Metadata.logo_uri_localized:type_name -> ietf.rfc7591.v1.Metadata.LogoUriLocalizedEntry
10, // 8: ietf.rfc7591.v1.ClientMetadata.tos_uri_localized:type_name -> ietf.rfc7591.v1.ClientMetadata.TosUriLocalizedEntry 12, // 8: ietf.rfc7591.v1.Metadata.tos_uri_localized:type_name -> ietf.rfc7591.v1.Metadata.TosUriLocalizedEntry
11, // 9: ietf.rfc7591.v1.ClientMetadata.policy_uri_localized:type_name -> ietf.rfc7591.v1.ClientMetadata.PolicyUriLocalizedEntry 13, // 9: ietf.rfc7591.v1.Metadata.policy_uri_localized:type_name -> ietf.rfc7591.v1.Metadata.PolicyUriLocalizedEntry
0, // 10: ietf.rfc7591.v1.ClientMetadata.jwks:type_name -> ietf.rfc7591.v1.JsonWebKeySet 0, // 10: ietf.rfc7591.v1.Metadata.jwks:type_name -> ietf.rfc7591.v1.JsonWebKeySet
11, // [11:11] is the sub-list for method output_type 14, // 11: ietf.rfc7591.v1.ClientSecret.expires_at:type_name -> google.protobuf.Timestamp
11, // [11:11] is the sub-list for method input_type 14, // 12: ietf.rfc7591.v1.ClientSecret.created_at:type_name -> google.protobuf.Timestamp
11, // [11:11] is the sub-list for extension type_name 6, // 13: ietf.rfc7591.v1.ClientRegistration.request_metadata:type_name -> ietf.rfc7591.v1.Metadata
11, // [11:11] is the sub-list for extension extendee 6, // 14: ietf.rfc7591.v1.ClientRegistration.response_metadata:type_name -> ietf.rfc7591.v1.Metadata
0, // [0:11] is the sub-list for field type_name 7, // 15: ietf.rfc7591.v1.ClientRegistration.client_secret:type_name -> ietf.rfc7591.v1.ClientSecret
16, // [16:16] is the sub-list for method output_type
16, // [16:16] is the sub-list for method input_type
16, // [16:16] is the sub-list for extension type_name
16, // [16:16] is the sub-list for extension extendee
0, // [0:16] is the sub-list for field type_name
} }
func init() { file_types_proto_init() } func init() { file_types_proto_init() }
@ -1018,13 +1167,14 @@ func file_types_proto_init() {
(*JsonWebKey_OkpParams)(nil), (*JsonWebKey_OkpParams)(nil),
} }
file_types_proto_msgTypes[6].OneofWrappers = []any{} file_types_proto_msgTypes[6].OneofWrappers = []any{}
file_types_proto_msgTypes[7].OneofWrappers = []any{}
type x struct{} type x struct{}
out := protoimpl.TypeBuilder{ out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{ File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(), GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_types_proto_rawDesc), len(file_types_proto_rawDesc)), RawDescriptor: unsafe.Slice(unsafe.StringData(file_types_proto_rawDesc), len(file_types_proto_rawDesc)),
NumEnums: 0, NumEnums: 0,
NumMessages: 12, NumMessages: 14,
NumExtensions: 0, NumExtensions: 0,
NumServices: 0, NumServices: 0,
}, },

View file

@ -3,6 +3,7 @@ syntax = "proto3";
package ietf.rfc7591.v1; package ietf.rfc7591.v1;
import "buf/validate/validate.proto"; import "buf/validate/validate.proto";
import "google/protobuf/timestamp.proto";
option go_package = "github.com/pomerium/pomerium/internal/rfc7591"; option go_package = "github.com/pomerium/pomerium/internal/rfc7591";
@ -153,7 +154,7 @@ message OkpKeyParameters {
// Represents the client metadata fields defined in RFC 7591 Section 2. // Represents the client metadata fields defined in RFC 7591 Section 2.
// These values are used both as input to registration requests and output in // These values are used both as input to registration requests and output in
// registration responses. // registration responses.
message ClientMetadata { message Metadata {
// Array of redirection URI strings. REQUIRED for clients using flows with // Array of redirection URI strings. REQUIRED for clients using flows with
// redirection. // redirection.
repeated string redirect_uris = 1 [(buf.validate.field).repeated = { repeated string redirect_uris = 1 [(buf.validate.field).repeated = {
@ -169,23 +170,11 @@ message ClientMetadata {
// OPTIONAL. Array of OAuth 2.0 grant type strings that the client can use. // OPTIONAL. Array of OAuth 2.0 grant type strings that the client can use.
// If omitted, defaults to ["authorization_code"]. // If omitted, defaults to ["authorization_code"].
repeated string grant_types = 3 [(buf.validate.field).repeated.items.string = { repeated string grant_types = 3;
in: [
"authorization_code",
"implicit",
"password",
"client_credentials",
"refresh_token",
"urn:ietf:params:oauth:grant-type:jwt-bearer",
"urn:ietf:params:oauth:grant-type:saml2-bearer"
],
}];
// OPTIONAL. Array of the OAuth 2.0 response type strings that the client can // OPTIONAL. Array of the OAuth 2.0 response type strings that the client can
// use. If omitted, defaults to ["code"]. // use. If omitted, defaults to ["code"].
repeated string response_types = 4 [(buf.validate.field).repeated.items.string = { repeated string response_types = 4;
in: ["code", "token"],
}];
// OPTIONAL. Human-readable string name of the client. RECOMMENDED. // OPTIONAL. Human-readable string name of the client. RECOMMENDED.
optional string client_name = 5 [(buf.validate.field).string = {min_len: 1, max_len: 255}]; optional string client_name = 5 [(buf.validate.field).string = {min_len: 1, max_len: 255}];
@ -266,3 +255,32 @@ message ClientMetadata {
message: "jwks_uri and jwks are mutually exclusive", message: "jwks_uri and jwks are mutually exclusive",
}; };
} }
message ClientSecret {
// REQUIRED. The client secret value.
string value = 1 [
(buf.validate.field).required = true,
(buf.validate.field).string.min_len = 1
];
// OPTIONAL. The expiration time of the client secret.
optional google.protobuf.Timestamp expires_at = 2;
google.protobuf.Timestamp created_at = 3 [
(buf.validate.field).required = true
];
}
// Represents the client registration storage structure.
message ClientRegistration {
// Contains the client metadata as requested by the client.
Metadata request_metadata = 1 [
(buf.validate.field).required = true
];
// Contains the client metadata as was returned by the server.
Metadata response_metadata = 2 [
(buf.validate.field).required = true
];
// OPTIONAL. The "client_secret" parameter is the secret used by the client
ClientSecret client_secret = 3;
}

View file

@ -1,49 +0,0 @@
package rfc7591v1_test
import (
"testing"
"github.com/bufbuild/protovalidate-go"
"github.com/google/go-cmp/cmp"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/testing/protocmp"
rfc7591 "github.com/pomerium/pomerium/internal/rfc7591"
)
func TestValidation(t *testing.T) {
v := &rfc7591.JsonWebKey{Kty: "Invalid"}
require.ErrorContains(t, protovalidate.Validate(v), `kty: value must be in list [RSA, EC, oct, OKP] [string.in]`)
}
func TestJSONMarshal(t *testing.T) {
data := `
{
"redirect_uris": [
"http://localhost:8002/oauth/callback"
],
"token_endpoint_auth_method": "none",
"grant_types": [
"authorization_code",
"refresh_token"
],
"response_types": [
"code"
],
"client_name": "MCP Inspector",
"client_uri": "https://github.com/modelcontextprotocol/inspector"
}`
v := &rfc7591.ClientMetadata{}
require.NoError(t, protojson.Unmarshal([]byte(data), v))
diff := cmp.Diff(&rfc7591.ClientMetadata{
RedirectUris: []string{"http://localhost:8002/oauth/callback"},
TokenEndpointAuthMethod: proto.String("none"),
GrantTypes: []string{"authorization_code", "refresh_token"},
ResponseTypes: []string{"code"},
ClientName: proto.String("MCP Inspector"),
ClientUri: proto.String("https://github.com/modelcontextprotocol/inspector"),
}, v, protocmp.Transform())
require.Empty(t, diff)
}