The command line has two different sign-in scenarios, and confusing them is expensive. The interactive one is the ordinary login command that opens a browser and stores a session: that is for a human at a terminal. The programmatic one is a key passed by a flag or an environment variable: that is for scripts and continuous integration. A token for the editor interoperability protocol is documented separately, and in an environment without graphics a variable that forbids opening a browser helps - otherwise the login command waits for a browser that is not there.
The naive practice is to set the key once for the whole environment and forget it. It is convenient right up to the moment when something else runs in the same job. And something almost always does: dependency installation, the build, package lifecycle scripts. All of that is repository-controlled code, and it reads the environment as freely as your agent does. A key set for the whole job is available to every step, including the one added to the dependencies last week that nobody read.
The right form is to pass the key to exactly the process that needs it. Below is what that looks like: the variable is set before a specific call and does not outlive it. The difference looks cosmetic and in fact shrinks the blast radius if any other step is compromised: the secret is not sitting in a shared environment where a foreign script can read it.
There are places where a key becomes visible regardless of your intentions, and they are worth knowing by name. A value passed by a flag lands in the process's launch line, and the process list on a machine is usually readable by any user and is often written into build logs. The same flag stays in the shell's command history, and history outlives the session and travels into backups. So an environment variable before the call is preferred to a flag, and the key itself is taken from a secret store rather than typed in by hand. This is not about paranoia: the places listed exist whether you remember them or not.
A separate question is where credentials live after an interactive sign-in. The command line can keep them in the system store or in a file, and there is a variable that forces the file option. On your own machine the system store is preferable: a file is easier to copy accidentally with the home directory, carry into a backup or show on screen. The file mode is left for environments where a system store simply does not exist - a container, for instance, with neither a user session nor graphics.
There is a non-obvious detail that leaks keys even for careful people: examples from the documentation. They contain placeholders, and sometimes those are replaced literally and then committed. A real value must not be in source, in command history, in the process list, in a session transcript or in build artifacts. Every one of those places outlives your task and is seen by people the key was not meant for.
For team work the right answer is service accounts. They have their own scope of rights, revoking them costs nothing personal, and the logs show that an action was performed by an automated process rather than a person. A personal key in shared automation creates the opposite picture: any action looks like yours, and revocation breaks your work together with the pipeline. An incident review in such a scheme turns into working out who started the pipeline that evening instead of reading a journal.
Every key must have a ready answer to two questions: how it is revoked and what stops working when it is. If there is no answer, the key is already used more widely than intended, and revocation will turn into an outage. Hence the rule of action on suspicion: a key that showed up in a transcript, a log or an artifact is treated as compromised and replaced, rather than investigated for whether anyone actually saw it. Replacement costs ten minutes; untangling things after a leak costs incomparably more.
The engineering conclusion is simple: authentication is part of the automation's architecture, not a line at the top of a script. Who exactly acts, with which key, with what scope and how that key is revoked are questions answered before the first run. The answers are recorded where the process itself lives.
The typical failures are predictable. Setting the key for the whole job and exposing it to the repository's scripts. Leaving credentials in a file where a system store is available. Substituting a placeholder from an example literally and committing it. And using a personal key in team automation instead of a service account.
agent login
agent status
# One automation process: the key does not outlive the call
CURSOR_API_KEY="$CURSOR_JOB_API_KEY" agent -p "Analyze the current diff"
# a key set for the whole job is also read by repository-controlled scripts