go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/auth/loginsessionspb/service.proto (about)

     1  // Copyright 2022 The LUCI Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  syntax = "proto3";
    16  
    17  package luci.auth.loginsessions;
    18  
    19  option go_package = "go.chromium.org/luci/auth/loginsessionspb";
    20  
    21  import "google/protobuf/duration.proto";
    22  import "google/protobuf/timestamp.proto";
    23  
    24  
    25  // LoginSessions service allows creating and polling login sessions.
    26  //
    27  // A login session is essentially a short-lived container for an OAuth2
    28  // authorization code. A native client-side program creates a login session
    29  // via CreateLoginSession and asks the user to complete the login through
    30  // the web UI exposed by the login session server (see `login_flow_url` field).
    31  //
    32  // The user performs the browser-based login flow that results in an OAuth2
    33  // authorization code placed in the login session.
    34  //
    35  // Meanwhile, the program that created the session is periodically checking its
    36  // status. As soon as it notices there's an authorization code available, it
    37  // exchanges this code for a full set of OAuth2 tokens (an access token,
    38  // a refresh token and an ID token).
    39  //
    40  // This protocol is intended for use **only** by native clients. The backend
    41  // will reply with PERMISSION_DENIED errors if it detects the calls are coming
    42  // from a browser.
    43  service LoginSessions {
    44    // CreateLoginSession creates a new login session in PENDING state.
    45    //
    46    // The returned message contains a new session with auto-generated random `id`
    47    // and `password`. It's the only reply that has `password` populated. Both
    48    // `id` and `password` are needed to get the up-to-date state of the session
    49    // in GetLoginSession.
    50    //
    51    // Returns:
    52    //   INVALID_ARGUMENT: when missing required fields.
    53    //   PERMISSION_DENIED: when `oauth_client_id` is not recognized or some
    54    //       requested scopes are forbidden from use.
    55    rpc CreateLoginSession(CreateLoginSessionRequest) returns (LoginSession);
    56  
    57    // GetLoginSession returns the current up-to-date state of a login session.
    58    //
    59    // The state changes based on interaction with the user in the browser (via
    60    // a flow launched by visiting `login_flow_url`) and with passage of time.
    61    //
    62    // Returns:
    63    //   INVALID_ARGUMENT: when missing required fields.
    64    //   NOT_FOUND: if the session is not found, expired long time ago or the
    65    //       password doesn't match.
    66    rpc GetLoginSession(GetLoginSessionRequest) returns (LoginSession);
    67  }
    68  
    69  
    70  // Inputs for CreateLoginSession
    71  message CreateLoginSessionRequest {
    72    // An OAuth2 client ID that should be known to the login sessions server.
    73    //
    74    // The eventual outcome of the login protocol is a set of tokens associated
    75    // with this OAuth2 client (e.g. the ID token will have this client as
    76    // `aud` claim).
    77    //
    78    // This client ID also identifies the application information that the user
    79    // will see at the OAuth2 consent screen.
    80    //
    81    // Required.
    82    string oauth_client_id = 1;
    83  
    84    // A list of OAuth2 scopes to get the refresh and access tokens with.
    85    //
    86    // The server may deny usage of some sensitive scopes. This set of scopes
    87    // defined what the user will see at the OAuth2 consent screen.
    88    //
    89    // Required.
    90    repeated string oauth_scopes = 2;
    91  
    92    // A `code_challenge` parameter for PKCE protocol using S256 method.
    93    //
    94    // See https://tools.ietf.org/html/rfc7636. It should be a base64 URL-encoded
    95    // SHA256 digest of a `code_verifier` random string (that the caller should
    96    // not disclose anywhere).
    97    //
    98    // Required.
    99    string oauth_s256_code_challenge = 3;
   100  
   101    // A name of the native program that started the flow.
   102    //
   103    // Will be shown on the confirmation web page in the login session UI to
   104    // provide some best-effort context around what opened the login session.
   105    // It is **not a security mechanism**, just an FYI for the user.
   106    //
   107    // Optional.
   108    string executable_name = 4;
   109  
   110    // A hostname of the machine that started the flow.
   111    //
   112    // Used for the same purpose as `executable_name` to give some context around
   113    // what opened the login session. It is **not a security mechanism**, just
   114    // an FYI for the user.
   115    //
   116    // Optional.
   117    string client_hostname = 5;
   118  }
   119  
   120  
   121  // Inputs for GetLoginSession.
   122  message GetLoginSessionRequest {
   123    // ID of the login session to get the state of. Required.
   124    string login_session_id = 1;
   125    // The password returned by CreateLoginSession. Required.
   126    bytes login_session_password = 2;
   127  }
   128  
   129  
   130  // Represents a login session whose eventual outcome if an OAuth2 authorization
   131  // code.
   132  message LoginSession {
   133    // Globally identifies this session.
   134    //
   135    // It is a randomly generated URL-safe string. Knowing it is enough to
   136    // complete the login session via the web UI. Should be used only by the user
   137    // that started the login flow.
   138    //
   139    // It will also appear as a `nonce` claim in the ID token produced by the
   140    // protocol.
   141    string id = 1;
   142  
   143    // Password is required to call GetLoginSession.
   144    //
   145    // It is populated only in the response from CreateLoginSession. It exists
   146    // to make sure that only whoever created the session can check its status.
   147    // Must not be shared or stored.
   148    bytes password = 2;
   149  
   150    // A session starts in PENDING state and then moves to one of other states
   151    // (all of them are final) in response to user actions or passage of time.
   152    enum State {
   153      STATE_UNSPECIFIED = 0;
   154      PENDING = 1;
   155      CANCELED = 2;
   156      SUCCEEDED = 3;
   157      FAILED = 4;
   158      EXPIRED = 5;
   159    }
   160    State state = 3;
   161  
   162    // When the session was created. Always populated.
   163    google.protobuf.Timestamp created = 4;
   164    // When the session will expire. Always populated.
   165    google.protobuf.Timestamp expiry = 5;
   166    // When the session moved to a final state. Populated for finished sessions.
   167    google.protobuf.Timestamp completed = 6;
   168  
   169    // A full URL to a webpage the user should visit to perform the login flow.
   170    //
   171    // It encodes `id` inside. Always populated.
   172    //
   173    // Knowing it is enough to complete the login session via the web UI. Should
   174    // be used only by the user that started the login flow.
   175    string login_flow_url = 7;
   176  
   177    // How often the caller should poll the session status via GetLoginSession.
   178    //
   179    // It is a mechanism to adjust the global poll rate without redeploying
   180    // new clients.
   181    //
   182    // Populated for sessions in PENDING state. The caller is allowed to ignore it
   183    // if absolutely necessary.
   184    google.protobuf.Duration poll_interval = 8;
   185  
   186    // The active confirmation code.
   187    //
   188    // The user will be asked to provide this code by the web UI as the final step
   189    // of the login flow. The code should be shown to the user by the native
   190    // program in the terminal. This code is very short lived (~ 1 min) and the
   191    // native program should periodically fetch and show the most recent code.
   192    //
   193    // The purpose of this mechanism is to make sure the user is completing the
   194    // flow they have actually started in their own terminal. It makes phishing
   195    // attempts harder, since the target of a phishing attack should not only
   196    // click through the web UI login flow initiated from a link (which is
   197    // relatively easy to arrange), but also actively copy-paste an up-to-date
   198    // code that expires very fast (making "asynchronous" phishing attempts
   199    // relatively hard to perform).
   200    //
   201    // Populated only if the session is still in PENDING state.
   202    string confirmation_code = 9;
   203  
   204    // When the confirmation code expires, as duration since when the request to
   205    // get it completed.
   206    //
   207    // It is a relative time (instead of an absolute timestamp) to avoid relying
   208    // on clock synchronization between the backend and the client machine. Since
   209    // the code expires pretty fast, even small differences in clocks may cause
   210    // issues.
   211    //
   212    // This value is always sufficiently larger than zero (to give the user some
   213    // time to use it). The server will prepare a new code in advance if the
   214    // existing one expires soon. See confirmation_code_refresh below. During such
   215    // transitions both codes are valid.
   216    //
   217    // Populated only if the session is still in PENDING state.
   218    google.protobuf.Duration confirmation_code_expiry = 10;
   219  
   220    // When the confirmation code will be refreshed (approximately).
   221    //
   222    // A "refresh" in this context means GetLoginSession will start returning
   223    // a new code. It happens somewhat before the previous code expires. That way
   224    // the user always sees a code that is sufficiently fresh to be copy-pasted
   225    // into the confirmation web page in a leisurely pace.
   226    //
   227    // Populated only if the session is still in PENDING state.
   228    google.protobuf.Duration confirmation_code_refresh = 11;
   229  
   230    // The OAuth2 authorization code that can be exchanged for OAuth2 tokens.
   231    //
   232    // Populated only for sessions in SUCCEEDED state. Getting this code is the
   233    // goal of LoginSessions service. Knowing this code, an OAuth2 client secret
   234    // (which is usually hardcoded in the native program code) and the PKCE code
   235    // verifier secret (which was used to derive `oauth_s256_code_challenge`) is
   236    // enough to get all OAuth2 tokens.
   237    //
   238    // Must not be shared.
   239    string oauth_authorization_code = 12;
   240  
   241    // An URL that should be used as `redirect_url` parameter when calling the
   242    // authorization server token endpoint when exchanging the authorization code
   243    // for tokens.
   244    //
   245    // Populated only for sessions in SUCCEEDED state. It is usually a static
   246    // well-known URL pointing to a page on the login sessions service domain,
   247    // but it is returned with the session to avoid hardcoding dependencies on
   248    // implementation details of the login sessions server.
   249    string oauth_redirect_url = 13;
   250  
   251    // An optional error message if the login flow failed.
   252    //
   253    // Populated only for sessions in FAILED state.
   254    string oauth_error = 14;
   255  }