github.com/pachyderm/pachyderm@v1.13.4/src/client/admin/v1_11/auth/auth.proto (about) 1 syntax = "proto3"; 2 3 package auth_1_11; 4 option go_package = "github.com/pachyderm/pachyderm/src/client/admin/v1_11/auth"; 5 6 import "gogoproto/gogo.proto"; 7 import "google/protobuf/timestamp.proto"; 8 9 /* A note on users 10 * 11 * Internally, in Pachyderm, usernames are structured strings. This makes both 12 * our API and our data model more flexible (at the loss of some type safety). 13 * Basically, anywhere that Pachyderm internally stores a subject (i.e. 14 * TokenInfo) or principal (ACL, the 'admins' collection), that username will 15 * have some structured prefix. 16 * 17 * Note that externally-facing principals ({Get,Set}{Scope,ACL}, ModifyAdmins, 18 * ListAdmins) will have their own conventions 19 * 20 * The current user formats are: 21 * 1) GitHub usernames: 22 * "github:MyGitHubUsername" 23 * 2) Pachyderm robot users: 24 * "robot:robot_user_1" 25 * 3) Pachyderm pipelines: 26 * "pipeline:terasort" 27 */ 28 29 //// Activation API 30 31 // ActivateRequest mirrors AuthenticateRequest. The caller is authenticated via 32 // GitHub OAuth, and then promoted to the cluster's first Admin. Afterwards, the 33 // caller can promote other users to Admin and remove themselves 34 message ActivateRequest { 35 // If set, Pachyderm will authenticate the caller as this user. 36 // - If set to a github user (i.e. it has a 'github:' prefix or no prefix) 37 // then Pachyderm will confirm that it matches the user associated with 38 // 'github_token' 39 // - If set to a robot user (i.e. it has a 'robot:' prefix), then Pachyderm 40 // will generate a new token for the robot user; this token will be the only 41 // way to administer this cluster until more admins are added. 42 string subject = 2; 43 44 // This is the token returned by GitHub and used to authenticate the caller. 45 // When Pachyderm is deployed locally, setting this value to a given string 46 // will automatically authenticate the caller as a GitHub user whose username 47 // is that string (unless this "looks like" a GitHub access code, in which 48 // case Pachyderm does retrieve the corresponding GitHub username) 49 string github_token = 1 [(gogoproto.customname) = "GitHubToken"]; 50 51 // If set, activate auth for the root user (`pach:root`), and add this 52 // token as the initial login token. The root user will have super 53 // admin permissions on the cluster. 54 string root_token = 3; 55 } 56 57 58 message ActivateResponse { 59 // pach_token authenticates the caller with Pachyderm (if you want to perform 60 // Pachyderm operations after auth has been activated as themselves, you must 61 // present this token along with your regular request) 62 string pach_token = 1; 63 } 64 65 message DeactivateRequest {} 66 message DeactivateResponse {} 67 68 // IDProvider configures a single ID provider that can authenticate Pachyderm 69 // users 70 message IDProvider { 71 // Name identifies this authentication backend in Pachyderm. 72 string name = 1; 73 74 // Description is a human-readable description of this authentication 75 // backend. It's ignored by Pachyderm, but exists for the benefit of users 76 // configuring Pachyderm's auth system. 77 string description = 2; 78 79 // SAMLOptions describes a SAML-based identity provider 80 message SAMLOptions { 81 // metadata_url is the URL of the SAML ID provider's metadata service 82 // (which Pachd can query to get more info about the SAML ID provider) 83 string metadata_url = 1 [(gogoproto.customname) = "MetadataURL"]; 84 85 // metadata_xml is a direct reproduction of the ID provider's metadata. 86 // Users can set this field in the argument to SetConfig if the ID provider 87 // can't be reached from pachd (e.g. because it's on a separate network to 88 // which Pachyderm users also have access) or for testing. Exactly one of 89 // metadata_url and metadata_xml should be set in calls to SetConfig, but 90 // internally, if metadata_url is set, the result of scraping the metadata 91 // URL will be placed here in the result from GetConfig(). 92 bytes metadata_xml = 2 [(gogoproto.customname) = "MetadataXML"]; 93 94 // If this ID provider supports sending group memberships via attribute, 95 // then users can set group_attribute to the SAML attribute that indicates 96 // group mmbership, and Pachyderm will update users' group memberships when 97 // they authenticate. 98 string group_attribute = 3; 99 } 100 SAMLOptions saml = 3 [(gogoproto.customname) = "SAML"]; 101 102 // OIDCOptions describes a OIDC-based identity provider 103 message OIDCOptions { 104 string issuer = 1; 105 string client_id = 2 [(gogoproto.customname) = "ClientID"]; 106 string client_secret = 3; 107 string redirect_uri = 4 [(gogoproto.customname) = "RedirectURI"]; 108 } 109 OIDCOptions oidc = 5 [(gogoproto.customname) = "OIDC"]; 110 111 // GitHubOptions is an empty protobuf message whose presence in the IDProvider 112 // of an AuthConfig indicates that GitHub auth should be enabled. 113 message GitHubOptions{} 114 GitHubOptions github = 4 [(gogoproto.customname) = "GitHub"]; 115 } 116 117 // Configure Pachyderm's auth system (particularly authentication backends 118 message AuthConfig { 119 // live_config_version identifies the version of a given pachyderm cluster's 120 // current auth configuration; if a user tries to write an auth configuration 121 // where live_config_version doesn't match the version of the cluster's 122 // current config, the write will fail. This allows for safe 123 // read+modify+write config changes. 124 int64 live_config_version = 1; 125 126 // id_providers describes external ID providers that can authenticate 127 // Pachyderm users (e.g. GitHub, Okta, etc) 128 repeated IDProvider id_providers = 2 [(gogoproto.customname) = "IDProviders"]; 129 130 // saml_svc_options configures the SAML services (Assertion Consumer Service 131 // and Metadata Service) that Pachd can export. 132 message SAMLServiceOptions { 133 // acs is the URL of Pachd's Assertion Consumer Service (i.e. where SAML ID 134 // providers can send SAMLResponses to Pachd). If Pachyderm is running in a 135 // private cluster, the cluster admin would be responsible for setting up a 136 // domain name/proxy to resolve to pachd:654/acs 137 string acs_url = 1 [(gogoproto.customname) = "ACSURL"]; 138 139 // metadata_url is the public URL of Pachd's SAML metadata service (some 140 // SAML ID providers will query this for information about Pachyderm's SAML 141 // implementation and use it to idenfity Pachyderm as a service provider). 142 // If Pachyderm is running in a private cluster, the cluster admin would be 143 // responsible for creating this URL (which must resolve to 144 // pachd:654/saml/metadata) 145 string metadata_url = 2 [(gogoproto.customname) = "MetadataURL"]; 146 147 // dash_url is the public address of this cluster's Pachyderm 148 // dashboard, if one exists; this option determines where users will be 149 // redirected after successfully authenticating 150 string dash_url = 3 [(gogoproto.customname) = "DashURL"]; 151 152 // session_duration determines the duration of SAML-IdP-authenticated user 153 // sessions (specified as a Golang time duration, e.g. "24h" or "600m"). If 154 // unset, user sessions last 24 hours (a short default, as SAML assertions 155 // may contain group memberships that need to be refreshed) 156 string session_duration = 4; 157 158 // debug_logging determines whether pachd emits verbose logs (including 159 // SAML credentials) as it receives them, which may be helpful for 160 // debugging. This will probably not be present in any official releases. 161 bool debug_logging = 5; 162 } 163 SAMLServiceOptions saml_svc_options = 3 [(gogoproto.customname) = "SAMLServiceOptions"]; 164 } 165 166 message GetConfigurationRequest {} 167 message GetConfigurationResponse { 168 AuthConfig configuration = 1; 169 } 170 message SetConfigurationRequest { 171 AuthConfig configuration = 1; 172 } 173 message SetConfigurationResponse {} 174 175 enum ClusterRole { 176 UNDEFINED = 0; 177 178 // SUPER gives access to all APIs and owner on everything in PFS (previous just called admin) 179 SUPER = 1; 180 181 // FS gives Owner on all repos in PFS but not access to manage other aspects of the cluster 182 FS = 2; 183 } 184 185 // ClusterRoles reflects any cluster-wide permissions a principal has. 186 // A principal can have multiple cluster roles. 187 message ClusterRoles { 188 repeated ClusterRole roles = 1; 189 } 190 191 // Get the current set of principals and roles for the cluster 192 message GetClusterRoleBindingsRequest{} 193 message GetClusterRoleBindingsResponse{ 194 // bindings contains a mapping of principals to cluster roles 195 map<string, ClusterRoles> bindings = 1; 196 } 197 198 // Set cluster roles for the specified principal. Setting an empty list of roles 199 // revokes any roles the principal has. 200 message ModifyClusterRoleBindingRequest { 201 string principal = 1; 202 ClusterRoles roles = 2; 203 } 204 message ModifyClusterRoleBindingResponse {} 205 206 // Deprecated. Get the list of cluster super admins. 207 message GetAdminsRequest{} 208 message GetAdminsResponse{ 209 repeated string admins = 1; 210 } 211 212 // Deprecated. Add and remove users from the set of cluster super admins. 213 message ModifyAdminsRequest { 214 repeated string add = 1; 215 repeated string remove = 2; 216 } 217 message ModifyAdminsResponse {} 218 219 //// Authentication data structures 220 221 // OTPInfo is the analogue of 'TokenInfo' for Authentication Codes (short-lived, 222 // one-time-use codes that are passed to the frontend and then exchanged for 223 // longer-lived tokens) 224 message OTPInfo { 225 // Subject (i.e. Pachyderm account) that a given OTP authenticates. This may 226 // be copied into the 'subject' field of a TokenInfo, and therefore has the 227 // same format, with the same prefixes. 228 string subject = 1; 229 230 // session_expiration indicates when the subject's session expires, a.k.a. 231 // when the Token to which this OTP converts expires (likely later than this 232 // OTP expires, but never earlier). 233 google.protobuf.Timestamp session_expiration = 2; 234 } 235 236 // TokenInfo is the 'value' of an auth token 'key' in the 'tokens' collection 237 message TokenInfo { 238 // Subject (i.e. Pachyderm account) that a given token authorizes. Prefixed 239 // with "github:" or "robot:" to distinguish the two classes of 240 // Subject in Pachyderm 241 string subject = 1; 242 243 enum TokenSource { 244 INVALID = 0; 245 AUTHENTICATE = 1; // returned by Authenticate()--non-revokeable 246 GET_TOKEN = 2; // returned by GetToken()--revokeable. 247 } 248 TokenSource source = 2; 249 } 250 251 //// Authentication API 252 253 message AuthenticateRequest { 254 // Exactly one of 'github_token', 'oidc_state', or 'one_time_password' must be set: 255 256 // This is the token returned by GitHub and used to authenticate the caller. 257 // When Pachyderm is deployed locally, setting this value to a given string 258 // will automatically authenticate the caller as a GitHub user whose username 259 // is that string (unless this "looks like" a GitHub access code, in which 260 // case Pachyderm does retrieve the corresponding GitHub username) 261 string github_token = 1 [(gogoproto.customname) = "GitHubToken"]; 262 // This is the session state that Pachyderm creates in order to keep track of 263 // information related to the current OIDC session. 264 string oidc_state = 3 [(gogoproto.customname) = "OIDCState"]; 265 266 // This is a short-lived, one-time-use password generated by Pachyderm, for 267 // the purpose of propagating authentication to new clients (e.g. from the 268 // dash to pachd) 269 string one_time_password = 2; 270 } 271 272 message AuthenticateResponse { 273 // pach_token authenticates the caller with Pachyderm (if you want to perform 274 // Pachyderm operations after auth has been activated as themselves, you must 275 // present this token along with your regular request) 276 string pach_token = 1; 277 } 278 279 message WhoAmIRequest {} 280 281 message WhoAmIResponse { 282 string username = 1; 283 bool is_admin = 2; 284 int64 ttl = 3 [(gogoproto.customname) = "TTL"]; 285 ClusterRoles cluster_roles = 4; 286 } 287 288 //// Authorization data structures 289 290 // Scope (actually a "role" in canonical security nomenclature) represents a 291 // rough level of access that a principal has to a repo 292 enum Scope { 293 // To remove a user's scope from a repo, set their scope to NONE 294 NONE = 0; 295 READER = 1; 296 WRITER = 2; 297 OWNER = 3; 298 } 299 300 message ACL { 301 // principal -> scope. All principals are the default principal of a Pachyderm 302 // subject (i.e. all keys in this map are strings prefixed with either 303 // "github:" or "robot:", followed by the name of a GitHub user, all of whom 304 // are Pachyderm subjects, or a Pachyderm robot user) 305 map<string, Scope> entries = 1; 306 } 307 308 message Users { 309 map<string, bool> usernames = 1; 310 } 311 312 message Groups { 313 map<string, bool> groups = 1; 314 } 315 316 //// Authorization API 317 318 message AuthorizeRequest { 319 // repo is the object that the caller wants to access 320 string repo = 1; 321 322 // scope is the access level that the caller needs to perform an action 323 Scope scope = 2; 324 } 325 326 message AuthorizeResponse { 327 // authorized is true if the caller has at least 328 // 'AuthorizeRequest.scope'-level access to 'AuthorizeRequest.repo', and false 329 // otherwise 330 bool authorized = 1; 331 } 332 333 message GetScopeRequest { 334 // username is the principal (some of which belong to robots rather than 335 // users, but the name is preserved for now to provide compatibility with the 336 // pachyderm dash) whose access level is queried. To query the access level 337 // of a robot user, the caller must prefix username with "robot:". If 338 // 'username' has no prefix (i.e. no ":"), then it's assumed to be a github 339 // user's principal. 340 string username = 1; 341 342 // repos are the objects to which 'username's access level is being queried 343 repeated string repos = 2; 344 } 345 346 message GetScopeResponse { 347 // scopes (actually a "role"--see "Scope") are the access level that 348 // 'GetScopeRequest.username' has to each repo in 'GetScopeRequest.repos', in 349 // the same order that repos appeared in 'repos'. 350 repeated Scope scopes = 1; 351 } 352 353 message SetScopeRequest { 354 // username is the principal (some of which belong to robots rather than 355 // users, but the name is preserved for now to provide compatibility with the 356 // pachyderm dash) whose access is being granted/revoked. As with 357 // GetScopeRequest, to set the access level of a robot user, the caller must 358 // prefix username with "robot:". If 'username' has no prefix (i.e. no ":"), 359 // then it's assumed to be a github user's principal. 360 string username = 1; 361 362 // repo is the object to which access is being granted/revoked 363 string repo = 2; 364 365 // scope (actually a "role"--see "Scope") is the access level that the owner 366 // of 'principal' will now have 367 Scope scope = 3; 368 } 369 370 message SetScopeResponse {} 371 372 message GetACLRequest { 373 string repo = 1; 374 } 375 376 message ACLEntry { 377 // username is the principal posessing this level of access to this ACL's 378 // repo (despite the name, this principal may be for a human github user or a 379 // pachyderm robot) 380 string username = 1; 381 382 // scope is the level of access that the owner of 'principal' has to this 383 // ACL's repo (actually a role in typical security terminology) 384 Scope scope = 2; 385 } 386 387 // GetACLReponse contains the list of entries on a Pachyderm ACL. 388 // 389 // To avoid migration pain with the Pachyderm dash the list of user principal 390 // entries and robot principal entries are separate. This way, no prefix or 391 // other disambiguating device is needed in 'entries' to separate user 392 // principals from robot principals (which would confuse the dash). Instead, 393 // the dash can simply ignore robot principals. 394 message GetACLResponse { 395 // entries contains all [user principal] -> [role] mappings. This is separate 396 // from robot_entries to avoid migration pain the Pachyderm dashboard 397 repeated ACLEntry entries = 1; 398 399 // robot_entries contains all [robot principal] -> [role] mappings. This is 400 // separate from entries to be unambiguous (all keys are robot principals, but 401 // have no prefixes) while avoiding migration pain in the Pachyderm dashboard. 402 repeated ACLEntry robot_entries = 2; 403 } 404 405 message SetACLRequest { 406 string repo = 1; 407 repeated ACLEntry entries = 2; 408 } 409 410 message SetACLResponse {} 411 412 ////////////////////////////// 413 //// OIDC Data Structures //// 414 ////////////////////////////// 415 416 // SessionInfo stores information associated with one OIDC authentication 417 // session (i.e. a single instance of a single user logging in). Sessions are 418 // short-lived and stored in the 'oidc-authns' collection, keyed by the OIDC 419 // 'state' token (30-character CSPRNG-generated string). 'GetOIDCLogin' 420 // generates and inserts entries, then /authorization-code/callback retrieves 421 // an access token from the ID provider and uses it to retrive the caller's 422 // email and store it in 'email', and finally Authorize() returns a Pachyderm 423 // token identified with that email address as a subject in Pachyderm. 424 message SessionInfo { 425 // nonce is used by /authorization-code/callback to validate session 426 // continuity with the IdP after a user has arrived there from GetOIDCLogin(). 427 // This is a 30-character CSPRNG-generated string. 428 string nonce = 1; 429 // email contains the email adddress associated with a user in their OIDC ID 430 // provider. Currently users are identified with their email address rather 431 // than their OIDC subject identifier to make switching between OIDC ID 432 // providers easier for users, and to make user identities more easily 433 // comprehensible in Pachyderm. The OIDC spec doesn't require that users' 434 // emails be present or unique, but we think this will be preferable in 435 // practice. 436 string email = 2; 437 // conversion_err indicates whether an error was encountered while exchanging 438 // an auth code for an access token, or while obtaining a user's email (in 439 // /authorization-code/callback). Storing the error state here allows any 440 // sibling calls to Authenticate() (i.e. using the same OIDC state token) to 441 // notify their caller that an error has occurred. We avoid passing the caller 442 // any details of the error (which are logged by Pachyderm) to avoid giving 443 // information to a user who has network access to Pachyderm but not an 444 // account in the OIDC provider. 445 bool conversion_err = 3; 446 } 447 448 //// OIDC API 449 450 message GetOIDCLoginRequest { 451 } 452 453 message GetOIDCLoginResponse { 454 // The login URL generated for the OIDC object 455 string login_url = 1 [(gogoproto.customname) = "LoginURL"]; 456 string state = 2; 457 } 458 459 //// Token API (very limited -- for pipelines) 460 461 message GetAuthTokenRequest { 462 // The returned token will allow the caller to access resources as this 463 // subject 464 string subject = 1; 465 466 // ttl indicates the requested (approximate) remaining lifetime of this token, 467 // in seconds 468 int64 ttl = 2 [(gogoproto.customname) = "TTL"]; 469 } 470 471 message GetAuthTokenResponse { 472 // A canonicalized version of the subject in the request 473 string subject = 2; 474 475 // A new auth token for the user in 'GetAuthTokenRequest.Subject' token 476 string token = 1; 477 } 478 479 message ExtendAuthTokenRequest { 480 // token indicates the Pachyderm token whose TTL is being extended 481 string token = 1; 482 483 // ttl indicates the new TTL of 'token' (if it's longer than the existing TTL) 484 int64 ttl = 2 [(gogoproto.customname) = "TTL"]; 485 } 486 487 message ExtendAuthTokenResponse {} 488 489 message RevokeAuthTokenRequest { 490 string token = 1; 491 } 492 493 message RevokeAuthTokenResponse {} 494 495 message SetGroupsForUserRequest { 496 string username = 1; 497 repeated string groups = 2; 498 } 499 500 message SetGroupsForUserResponse {} 501 502 message ModifyMembersRequest { 503 string group = 1; 504 repeated string add = 2; 505 repeated string remove = 3; 506 } 507 508 message ModifyMembersResponse {} 509 510 message GetGroupsRequest { 511 string username = 1; 512 } 513 514 message GetGroupsResponse { 515 repeated string groups = 1; 516 } 517 518 message GetUsersRequest { 519 string group = 1; 520 } 521 522 message GetUsersResponse { 523 repeated string usernames = 1; 524 } 525 526 // GetOneTimePassword allows users to generate short-lived (~30s) tokens that 527 // can be passed to Authenticate() (via AuthenticateRequest.one_time_password) 528 // and exchanged for a longer-lived pachyderm token. This is more secure than 529 // GetAuthToken, which produces long-lived authorization tokens. 530 message GetOneTimePasswordRequest { 531 // If the caller is an admin, GetOneTimePassword() can return a code for 532 // any user (useful for testing). 533 // If the caller is not an admin, GetOneTimePassword() will return an 534 // authentication code for the caller if username is unset or set to the 535 // caller's username (and will return an error otherwise) 536 string subject = 1; 537 538 // ttl indicates the requested (approximate) remaining lifetime of this token, 539 // in seconds 540 int64 ttl = 2 [(gogoproto.customname) = "TTL"]; 541 } 542 543 message GetOneTimePasswordResponse { 544 // 'code' is the string that must be presented in 545 // AuthenticateRequest.one_time_password to login as 546 // GetOneTimePasswordRequest.subject 547 string code = 1; 548 549 // expiration is the time at which the token in 'code' will expire 550 google.protobuf.Timestamp otp_expiration = 2 [(gogoproto.customname) = "OTPExpiration"]; 551 } 552 553 message HashedAuthToken { 554 string hashed_token = 1; 555 TokenInfo token_info = 2; 556 google.protobuf.Timestamp expiration = 3; 557 } 558 559 // ExtractAuthTokens returns all the hashed robot tokens that have been issued. 560 // User tokens are not extracted as they can be recreated by logging in. 561 message ExtractAuthTokensRequest {} 562 563 message ExtractAuthTokensResponse { 564 repeated HashedAuthToken tokens = 1; 565 } 566 567 // RestoreAuthToken inserts a hashed token that has previously been extracted. 568 message RestoreAuthTokenRequest { 569 HashedAuthToken token = 1; 570 } 571 572 message RestoreAuthTokenResponse {} 573 574 service API { 575 // Activate/Deactivate the auth API. 'Activate' sets an initial set of admins 576 // for the Pachyderm cluster, and 'Deactivate' removes all ACLs, tokens, and 577 // admins from the Pachyderm cluster, making all data publicly accessable 578 rpc Activate(ActivateRequest) returns (ActivateResponse) {} 579 rpc Deactivate(DeactivateRequest) returns (DeactivateResponse) {} 580 581 rpc GetConfiguration(GetConfigurationRequest) returns (GetConfigurationResponse) {} 582 rpc SetConfiguration(SetConfigurationRequest) returns (SetConfigurationResponse) {} 583 584 // Deprecated. GetAdmins returns the current list of cluster super admins 585 rpc GetAdmins(GetAdminsRequest) returns (GetAdminsResponse) {} 586 // Deprecated. ModifyAdmins adds or removes super admins from the cluster 587 rpc ModifyAdmins(ModifyAdminsRequest) returns (ModifyAdminsResponse) {} 588 589 // GetClusterRoleBindings returns the current set of cluster role bindings 590 rpc GetClusterRoleBindings(GetClusterRoleBindingsRequest) returns (GetClusterRoleBindingsResponse) {} 591 // ModifyAdmin sets the list of admin roles for a principal 592 rpc ModifyClusterRoleBinding(ModifyClusterRoleBindingRequest) returns (ModifyClusterRoleBindingResponse) {} 593 594 rpc Authenticate(AuthenticateRequest) returns (AuthenticateResponse) {} 595 rpc Authorize(AuthorizeRequest) returns (AuthorizeResponse) {} 596 rpc WhoAmI(WhoAmIRequest) returns (WhoAmIResponse) {} 597 598 rpc GetScope(GetScopeRequest) returns (GetScopeResponse) {} 599 rpc SetScope(SetScopeRequest) returns (SetScopeResponse) {} 600 rpc GetACL(GetACLRequest) returns (GetACLResponse) {} 601 rpc SetACL(SetACLRequest) returns (SetACLResponse) {} 602 603 rpc GetOIDCLogin(GetOIDCLoginRequest) returns (GetOIDCLoginResponse) {} 604 605 rpc GetAuthToken(GetAuthTokenRequest) returns (GetAuthTokenResponse) {} 606 rpc ExtendAuthToken(ExtendAuthTokenRequest) returns (ExtendAuthTokenResponse) {} 607 rpc RevokeAuthToken(RevokeAuthTokenRequest) returns (RevokeAuthTokenResponse) {} 608 609 rpc SetGroupsForUser(SetGroupsForUserRequest) returns (SetGroupsForUserResponse) {} 610 rpc ModifyMembers(ModifyMembersRequest) returns (ModifyMembersResponse) {} 611 rpc GetGroups(GetGroupsRequest) returns (GetGroupsResponse) {} 612 rpc GetUsers(GetUsersRequest) returns (GetUsersResponse) {} 613 614 rpc GetOneTimePassword(GetOneTimePasswordRequest) returns (GetOneTimePasswordResponse) {} 615 616 rpc ExtractAuthTokens(ExtractAuthTokensRequest) returns (ExtractAuthTokensResponse) {} 617 rpc RestoreAuthToken(RestoreAuthTokenRequest) returns (RestoreAuthTokenResponse) {} 618 }