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 }