fix: replace --api-key with --with-api-key in codex login (#4646)
Previously, users could supply their API key directly via: ```shell codex login --api-key KEY ``` but this has the drawback that `KEY` is more likely to end up in shell history, can be read from `/proc`, etc. This PR removes support for `--api-key` and replaces it with `--with-api-key`, which reads the key from stdin, so either of these are better options: ``` printenv OPENAI_API_KEY | codex login --with-api-key codex login --with-api-key < my_key.txt ``` Other CLIs, such as `gh auth login --with-token`, follow the same practice.
This commit is contained in:
@@ -9,6 +9,8 @@ use codex_core::config::ConfigOverrides;
|
|||||||
use codex_login::ServerOptions;
|
use codex_login::ServerOptions;
|
||||||
use codex_login::run_device_code_login;
|
use codex_login::run_device_code_login;
|
||||||
use codex_login::run_login_server;
|
use codex_login::run_login_server;
|
||||||
|
use std::io::IsTerminal;
|
||||||
|
use std::io::Read;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
pub async fn login_with_chatgpt(codex_home: PathBuf) -> std::io::Result<()> {
|
pub async fn login_with_chatgpt(codex_home: PathBuf) -> std::io::Result<()> {
|
||||||
@@ -56,6 +58,33 @@ pub async fn run_login_with_api_key(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn read_api_key_from_stdin() -> String {
|
||||||
|
let mut stdin = std::io::stdin();
|
||||||
|
|
||||||
|
if stdin.is_terminal() {
|
||||||
|
eprintln!(
|
||||||
|
"--with-api-key expects the API key on stdin. Try piping it, e.g. `printenv OPENAI_API_KEY | codex login --with-api-key`."
|
||||||
|
);
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
eprintln!("Reading API key from stdin...");
|
||||||
|
|
||||||
|
let mut buffer = String::new();
|
||||||
|
if let Err(err) = stdin.read_to_string(&mut buffer) {
|
||||||
|
eprintln!("Failed to read API key from stdin: {err}");
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
let api_key = buffer.trim().to_string();
|
||||||
|
if api_key.is_empty() {
|
||||||
|
eprintln!("No API key provided via stdin.");
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
api_key
|
||||||
|
}
|
||||||
|
|
||||||
/// Login using the OAuth device code flow.
|
/// Login using the OAuth device code flow.
|
||||||
pub async fn run_login_with_device_code(
|
pub async fn run_login_with_device_code(
|
||||||
cli_config_overrides: CliConfigOverrides,
|
cli_config_overrides: CliConfigOverrides,
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use codex_chatgpt::apply_command::ApplyCommand;
|
|||||||
use codex_chatgpt::apply_command::run_apply_command;
|
use codex_chatgpt::apply_command::run_apply_command;
|
||||||
use codex_cli::LandlockCommand;
|
use codex_cli::LandlockCommand;
|
||||||
use codex_cli::SeatbeltCommand;
|
use codex_cli::SeatbeltCommand;
|
||||||
|
use codex_cli::login::read_api_key_from_stdin;
|
||||||
use codex_cli::login::run_login_status;
|
use codex_cli::login::run_login_status;
|
||||||
use codex_cli::login::run_login_with_api_key;
|
use codex_cli::login::run_login_with_api_key;
|
||||||
use codex_cli::login::run_login_with_chatgpt;
|
use codex_cli::login::run_login_with_chatgpt;
|
||||||
@@ -139,7 +140,18 @@ struct LoginCommand {
|
|||||||
#[clap(skip)]
|
#[clap(skip)]
|
||||||
config_overrides: CliConfigOverrides,
|
config_overrides: CliConfigOverrides,
|
||||||
|
|
||||||
#[arg(long = "api-key", value_name = "API_KEY")]
|
#[arg(
|
||||||
|
long = "with-api-key",
|
||||||
|
help = "Read the API key from stdin (e.g. `printenv OPENAI_API_KEY | codex login --with-api-key`)"
|
||||||
|
)]
|
||||||
|
with_api_key: bool,
|
||||||
|
|
||||||
|
#[arg(
|
||||||
|
long = "api-key",
|
||||||
|
value_name = "API_KEY",
|
||||||
|
help = "(deprecated) Previously accepted the API key directly; now exits with guidance to use --with-api-key",
|
||||||
|
hide = true
|
||||||
|
)]
|
||||||
api_key: Option<String>,
|
api_key: Option<String>,
|
||||||
|
|
||||||
/// EXPERIMENTAL: Use device code flow (not yet supported)
|
/// EXPERIMENTAL: Use device code flow (not yet supported)
|
||||||
@@ -298,7 +310,13 @@ async fn cli_main(codex_linux_sandbox_exe: Option<PathBuf>) -> anyhow::Result<()
|
|||||||
login_cli.client_id,
|
login_cli.client_id,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
} else if let Some(api_key) = login_cli.api_key {
|
} else if login_cli.api_key.is_some() {
|
||||||
|
eprintln!(
|
||||||
|
"The --api-key flag is no longer supported. Pipe the key instead, e.g. `printenv OPENAI_API_KEY | codex login --with-api-key`."
|
||||||
|
);
|
||||||
|
std::process::exit(1);
|
||||||
|
} else if login_cli.with_api_key {
|
||||||
|
let api_key = read_api_key_from_stdin();
|
||||||
run_login_with_api_key(login_cli.config_overrides, api_key).await;
|
run_login_with_api_key(login_cli.config_overrides, api_key).await;
|
||||||
} else {
|
} else {
|
||||||
run_login_with_chatgpt(login_cli.config_overrides).await;
|
run_login_with_chatgpt(login_cli.config_overrides).await;
|
||||||
|
|||||||
@@ -5,9 +5,17 @@
|
|||||||
If you prefer to pay-as-you-go, you can still authenticate with your OpenAI API key:
|
If you prefer to pay-as-you-go, you can still authenticate with your OpenAI API key:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
codex login --api-key "your-api-key-here"
|
printenv OPENAI_API_KEY | codex login --with-api-key
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Alternatively, read from a file:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
codex login --with-api-key < my_key.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
The legacy `--api-key` flag now exits with an error instructing you to use `--with-api-key` so that the key never appears in shell history or process listings.
|
||||||
|
|
||||||
This key must, at minimum, have write access to the Responses API.
|
This key must, at minimum, have write access to the Responses API.
|
||||||
|
|
||||||
## Migrating to ChatGPT login from API key
|
## Migrating to ChatGPT login from API key
|
||||||
|
|||||||
Reference in New Issue
Block a user