Add separate account session login route

This commit is contained in:
Dhruv
2026-06-03 12:11:30 +05:30
parent f81b5c5aef
commit 6cd74b200b
8 changed files with 124 additions and 32 deletions

View File

@@ -5941,6 +5941,30 @@
"title": "AccountSession/addRequest",
"type": "object"
},
{
"properties": {
"id": {
"$ref": "#/definitions/RequestId"
},
"method": {
"enum": [
"accountSession/login/start"
],
"title": "AccountSession/login/startRequestMethod",
"type": "string"
},
"params": {
"$ref": "#/definitions/LoginAccountParams"
}
},
"required": [
"id",
"method",
"params"
],
"title": "AccountSession/login/startRequest",
"type": "object"
},
{
"properties": {
"id": {

View File

@@ -1811,6 +1811,30 @@
"title": "AccountSession/addRequest",
"type": "object"
},
{
"properties": {
"id": {
"$ref": "#/definitions/v2/RequestId"
},
"method": {
"enum": [
"accountSession/login/start"
],
"title": "AccountSession/login/startRequestMethod",
"type": "string"
},
"params": {
"$ref": "#/definitions/v2/LoginAccountParams"
}
},
"required": [
"id",
"method",
"params"
],
"title": "AccountSession/login/startRequest",
"type": "object"
},
{
"properties": {
"id": {

View File

@@ -2739,6 +2739,30 @@
"title": "AccountSession/addRequest",
"type": "object"
},
{
"properties": {
"id": {
"$ref": "#/definitions/RequestId"
},
"method": {
"enum": [
"accountSession/login/start"
],
"title": "AccountSession/login/startRequestMethod",
"type": "string"
},
"params": {
"$ref": "#/definitions/LoginAccountParams"
}
},
"required": [
"id",
"method",
"params"
],
"title": "AccountSession/login/startRequest",
"type": "object"
},
{
"properties": {
"id": {

File diff suppressed because one or more lines are too long

View File

@@ -943,6 +943,14 @@ client_request_definitions! {
response: v2::AccountSessionsResponse,
},
AccountSessionsLogin => "accountSession/login/start" {
params: v2::LoginAccountParams,
inspect_params: true,
serialization: global("account-auth"),
manual_payload_conversion: manual,
response: v2::LoginAccountResponse,
},
AccountSessionsList => "accountSession/list" {
params: v2::AccountSessionsListParams,
serialization: global("account-auth"),

View File

@@ -289,16 +289,6 @@ impl<'a> AccountSessionsStore<'a> {
self.save(&stored)
}
pub(crate) async fn revoke_all_and_clear(&self) -> std::io::Result<()> {
let stored = self.load()?;
for session in stored.sessions {
if let Err(err) = revoke_auth_dot_json(&session.auth_json).await {
tracing::warn!("failed to revoke saved account session during logout: {err}");
}
}
self.clear()
}
fn load(&self) -> std::io::Result<StoredAccountSessions> {
match self.read()? {
Some(stored) => Ok(stored),

View File

@@ -1289,6 +1289,11 @@ impl MessageProcessor {
ClientRequest::AccountSessionsAdd { params, .. } => {
self.account_processor.add_account_session(params).await
}
ClientRequest::AccountSessionsLogin { params, .. } => {
self.account_processor
.login_account_session(request_id.clone(), params)
.await
}
ClientRequest::AccountSessionsList { params, .. } => {
self.account_processor.list_account_sessions(params).await
}

View File

@@ -86,7 +86,20 @@ impl AccountRequestProcessor {
request_id: ConnectionRequestId,
params: LoginAccountParams,
) -> Result<Option<ClientResponsePayload>, JSONRPCErrorError> {
self.login_v2(request_id, params).await.map(|()| None)
self.login_v2(request_id, params, /*revoke_previous_auth*/ true)
.await
.map(|()| None)
}
pub(crate) async fn login_account_session(
&self,
request_id: ConnectionRequestId,
params: LoginAccountParams,
) -> Result<Option<ClientResponsePayload>, JSONRPCErrorError> {
self.sync_active_account_session()?;
self.login_v2(request_id, params, /*revoke_previous_auth*/ false)
.await
.map(|()| None)
}
pub(crate) async fn logout_account(
@@ -296,6 +309,7 @@ impl AccountRequestProcessor {
&self,
request_id: ConnectionRequestId,
params: LoginAccountParams,
revoke_previous_auth: bool,
) -> Result<(), JSONRPCErrorError> {
match params {
LoginAccountParams::ApiKey { api_key } => {
@@ -305,11 +319,12 @@ impl AccountRequestProcessor {
LoginAccountParams::Chatgpt {
codex_streamlined_login,
} => {
self.login_chatgpt_v2(request_id, codex_streamlined_login)
self.login_chatgpt_v2(request_id, codex_streamlined_login, revoke_previous_auth)
.await;
}
LoginAccountParams::ChatgptDeviceCode => {
self.login_chatgpt_device_code_v2(request_id).await;
self.login_chatgpt_device_code_v2(request_id, revoke_previous_auth)
.await;
}
LoginAccountParams::ChatgptAuthTokens {
access_token,
@@ -351,8 +366,6 @@ impl AccountRequestProcessor {
));
}
self.sync_active_account_session()?;
// Cancel any active login attempt.
{
let mut guard = self.active_login.lock().await;
@@ -392,6 +405,7 @@ impl AccountRequestProcessor {
async fn login_chatgpt_common(
&self,
codex_streamlined_login: bool,
revoke_previous_auth: bool,
) -> std::result::Result<LoginServerOptions, JSONRPCErrorError> {
let config = self.config.as_ref();
@@ -405,12 +419,10 @@ impl AccountRequestProcessor {
));
}
self.sync_active_account_session()?;
let opts = LoginServerOptions {
open_browser: false,
codex_streamlined_login,
revoke_previous_auth: false,
revoke_previous_auth,
..LoginServerOptions::new(
config.codex_home.to_path_buf(),
CLIENT_ID.to_string(),
@@ -445,16 +457,22 @@ impl AccountRequestProcessor {
&self,
request_id: ConnectionRequestId,
codex_streamlined_login: bool,
revoke_previous_auth: bool,
) {
let result = self.login_chatgpt_response(codex_streamlined_login).await;
let result = self
.login_chatgpt_response(codex_streamlined_login, revoke_previous_auth)
.await;
self.outgoing.send_result(request_id, result).await;
}
async fn login_chatgpt_response(
&self,
codex_streamlined_login: bool,
revoke_previous_auth: bool,
) -> Result<LoginAccountResponse, JSONRPCErrorError> {
let opts = self.login_chatgpt_common(codex_streamlined_login).await?;
let opts = self
.login_chatgpt_common(codex_streamlined_login, revoke_previous_auth)
.await?;
let server = run_login_server(opts)
.map_err(|err| internal_error(format!("failed to start login server: {err}")))?;
let login_id = Uuid::new_v4();
@@ -517,16 +535,23 @@ impl AccountRequestProcessor {
})
}
async fn login_chatgpt_device_code_v2(&self, request_id: ConnectionRequestId) {
let result = self.login_chatgpt_device_code_response().await;
async fn login_chatgpt_device_code_v2(
&self,
request_id: ConnectionRequestId,
revoke_previous_auth: bool,
) {
let result = self
.login_chatgpt_device_code_response(revoke_previous_auth)
.await;
self.outgoing.send_result(request_id, result).await;
}
async fn login_chatgpt_device_code_response(
&self,
revoke_previous_auth: bool,
) -> Result<LoginAccountResponse, JSONRPCErrorError> {
let opts = self
.login_chatgpt_common(/*codex_streamlined_login*/ false)
.login_chatgpt_common(/*codex_streamlined_login*/ false, revoke_previous_auth)
.await?;
let device_code = request_device_code(&opts)
.await
@@ -653,8 +678,6 @@ impl AccountRequestProcessor {
));
}
self.sync_active_account_session()?;
// Cancel any active login attempt to avoid persisting managed auth state.
{
let mut guard = self.active_login.lock().await;
@@ -769,12 +792,6 @@ impl AccountRequestProcessor {
}
}
self.sync_active_account_session()?;
self.account_sessions_store()
.revoke_all_and_clear()
.await
.map_err(|err| internal_error(format!("failed to clear account sessions: {err}")))?;
match self.auth_manager.logout_with_revoke().await {
Ok(_) => {}
Err(err) => {