Skip to content

Commit 3b8f5ad

Browse files
committed
docs(auth): document paste-token token flag
1 parent 757232b commit 3b8f5ad

5 files changed

Lines changed: 15 additions & 27 deletions

File tree

docs/cli/models.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -219,9 +219,11 @@ Notes:
219219
method (defaulting to that provider's `setup-token` method when it exposes
220220
one).
221221
- `paste-token` accepts a token string generated elsewhere or from automation.
222-
- `paste-token` requires `--provider`, prompts for the token value, and writes
223-
it to the default profile id `<provider>:manual` unless you pass
222+
- `paste-token` requires `--provider`, prompts for the token value by default,
223+
and writes it to the default profile id `<provider>:manual` unless you pass
224224
`--profile-id`.
225+
- In automation, pipe the token on stdin instead of passing it as an argument so
226+
provider credentials do not appear in shell history or process lists.
225227
- `paste-token --expires-in <duration>` stores an absolute token expiry from a
226228
relative duration such as `365d` or `12h`.
227229
- For `openai-codex`, OpenAI API keys and ChatGPT/OAuth token material are

src/agents/auth-profiles.ensureauthprofilestore.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1046,6 +1046,7 @@ describe("ensureAuthProfileStore", () => {
10461046
missing_provider: 1,
10471047
non_object: 1,
10481048
},
1049+
validTypes: ["api_key", "oauth", "token"],
10491050
keys: ["anthropic:missing-type", "openai:missing-provider", "qwen:not-object"],
10501051
},
10511052
);

src/cli/models-cli.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -333,10 +333,7 @@ export function registerModelsCli(program: Command) {
333333
.option("--provider <id>", "Provider id registered by a plugin")
334334
.option("--method <id>", "Provider auth method id")
335335
.option("--device-code", "Use the provider device-code auth method", false)
336-
.option(
337-
"--profile-id <id>",
338-
"Auth profile id override for single-profile login methods",
339-
)
336+
.option("--profile-id <id>", "Auth profile id override for single-profile login methods")
340337
.option("--set-default", "Apply the provider's default model recommendation", false)
341338
.action(async (opts, command) => {
342339
if (opts.deviceCode && typeof opts.method === "string" && opts.method !== "device-code") {
@@ -389,7 +386,6 @@ export function registerModelsCli(program: Command) {
389386
"--expires-in <duration>",
390387
"Optional expiry duration (e.g. 365d, 12h). Stored as absolute expiresAt.",
391388
)
392-
.option("--token <value>", "Token value (skip interactive prompt)")
393389
.action(async (opts, command) => {
394390
await withModelsRuntime(async ({ defaultRuntime, resolveModelAgentOption }) => {
395391
const agent = resolveModelAgentOption(command);
@@ -400,7 +396,6 @@ export function registerModelsCli(program: Command) {
400396
profileId: opts.profileId as string | undefined,
401397
expiresIn: opts.expiresIn as string | undefined,
402398
agent,
403-
token: opts.token as string | undefined,
404399
},
405400
defaultRuntime,
406401
);

src/commands/models/auth.test.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ const mocks = vi.hoisted(() => ({
5555
logConfigUpdated: vi.fn(),
5656
openUrl: vi.fn(),
5757
isRemoteEnvironment: vi.fn(() => false),
58+
validateAnthropicSetupToken: vi.fn<() => string | undefined>(() => undefined),
5859
loadAuthProfileStoreForRuntime: vi.fn(),
5960
listProfilesForProvider: vi.fn(),
6061
promoteAuthProfileInOrder: vi.fn(),
@@ -170,7 +171,7 @@ vi.mock("../../plugins/provider-oauth-flow.js", () => ({
170171
}));
171172

172173
vi.mock("../auth-token.js", () => ({
173-
validateAnthropicSetupToken: vi.fn(() => undefined),
174+
validateAnthropicSetupToken: mocks.validateAnthropicSetupToken,
174175
}));
175176

176177
vi.mock("../../plugins/provider-auth-choice-helpers.js", async (importOriginal) => {
@@ -356,6 +357,8 @@ describe("modelsAuthLoginCommand", () => {
356357
mocks.clackPassword.mockReset();
357358
mocks.clackSelect.mockReset();
358359
mocks.clackText.mockReset();
360+
mocks.validateAnthropicSetupToken.mockReset();
361+
mocks.validateAnthropicSetupToken.mockReturnValue(undefined);
359362
mocks.upsertAuthProfileWithLock.mockReset();
360363
mocks.upsertAuthProfileWithLock.mockResolvedValue({ version: 1, profiles: {} });
361364
mocks.promoteAuthProfileInOrder.mockReset();

src/commands/models/auth.ts

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -573,7 +573,6 @@ export async function modelsAuthPasteTokenCommand(
573573
profileId?: string;
574574
expiresIn?: string;
575575
agent?: string;
576-
token?: string;
577576
},
578577
runtime: RuntimeEnv,
579578
) {
@@ -601,23 +600,11 @@ export async function modelsAuthPasteTokenCommand(
601600
}
602601
return undefined;
603602
};
604-
const rawToken = normalizeOptionalString(opts.token);
605-
if (opts.token !== undefined && !rawToken) {
606-
throw new Error("--token value must not be empty");
607-
}
608-
if (rawToken !== undefined) {
609-
const rawTokenValidation = validateTokenInput(rawToken);
610-
if (rawTokenValidation) {
611-
throw new Error(rawTokenValidation);
612-
}
613-
}
614-
const tokenInput =
615-
rawToken ??
616-
(await readPastedSecret({
617-
message: `Paste token for ${provider}`,
618-
masked: false,
619-
validate: validateTokenInput,
620-
}));
603+
const tokenInput = await readPastedSecret({
604+
message: `Paste token for ${provider}`,
605+
masked: false,
606+
validate: validateTokenInput,
607+
});
621608
const token =
622609
provider === "anthropic"
623610
? tokenInput.replaceAll(/\s+/g, "").trim()

0 commit comments

Comments
 (0)