Skip to content

Reject --auth without a credential file path - #370

Open
JayOfTheKeyboard wants to merge 1 commit into
stripe:mainfrom
JayOfTheKeyboard:fix/auth-flag-missing-value
Open

JayOfTheKeyboard wants to merge 1 commit into
stripe:mainfrom
JayOfTheKeyboard:fix/auth-flag-missing-value

Conversation

@JayOfTheKeyboard

Copy link
Copy Markdown

Motivation

cli.tsx reads the global --auth <path> flag by hand before incur sees argv. When no path follows the flag, the value is undefined. The CLI then falls back to the default credential store, and it ignores LINK_AUTH_FILE as well. So a command meant for a separate session runs against the default one, and it still exits 0.

Reproduced on main (a4497ca). The default store held a valid session, LINK_AUTH_FILE pointed at a second one, and the path after --auth was left off:

$ LINK_AUTH_FILE=work.json link-cli auth logout --format json --auth
{ "authenticated": false }                       # exit 0

$ link-cli auth status --format json             # default session: gone
  "authenticated": false
$ link-cli auth status --auth work.json --format json
  "authenticated": true                          # the one meant: untouched
Invocation On main With this PR
auth logout --auth (value missing, LINK_AUTH_FILE set) Revokes and deletes the default session, exit 0 INVALID_INPUT, exit 1, nothing touched
auth status --auth --format json Takes --format as the path, creates ./--format.json, prints human output, exit 0 INVALID_INPUT, exit 1, no file created
auth status --auth "" Falls back to the default store INVALID_INPUT, exit 1
auth status --auth work.json Uses work.json Unchanged

Summary

  • Move the --auth parsing into takeAuthFileFlag() (packages/cli/src/auth/auth-file-flag.ts). It still strips the flag and its value, and it still falls back to LINK_AUTH_FILE when the flag is absent.
  • A missing value, an empty value, or a value that starts with - is reported as Missing value for flag: --auth (expected a credential file path; write ./-name for a path that starts with "-"). The following flag is left in argv for incur to parse.
  • The error goes through a root cli.use() middleware calling c.error({ code: 'INVALID_INPUT', ... }), so it comes out in the requested format with exit code 1, like other input errors. The wording follows incur's own Missing value for flag: --config.

Key design considerations

  • A path beginning with - is now refused. ./-creds.json still works.
  • --auth=path is not supported. That is unchanged, and it matches incur's other global flags (--format=json is also "Unknown flag").
  • A path that doesn't end in .json still gets .json appended (--auth creds uses creds.json). That looks deliberate from Specify credential file #81, so this PR leaves it alone.
  • incur's built-ins (--help, --version, --llms, skills add, mcp add, completions) don't run middleware, so they still ignore a bare --auth. None of them read credentials. Under --mcp the server still starts, but every tool call returns the error.
  • The syntax hasn't changed, so README and SKILL.md stay as they are. CLAUDE.md's Global Flags row now describes the new failure mode.

Tests

  • src/__tests__/cli.test.ts, new --auth without a path block, run against the built CLI. Both tests fail on main and pass with the fix:
    • errors instead of logging out the default session also checks that no /device/revoke request is made and that the LINK_AUTH_FILE target isn't created. On main: expected undefined to be 'prod_test_refresh_token', meaning the default session was deleted.
    • does not take the next flag as the credential file path. On main: expected true to be false, meaning --format.json was created.
  • src/auth/__tests__/auth-file-flag.test.ts: unit tests for the parser (value, env fallback, missing/empty/flag-as-value, argv left for incur).
  • Mutations, each tried on its own, and each turns at least one test red: removing the middleware (2 integration tests), dropping the - check (4), dropping the empty-string check (1 unit), splicing the following flag away (1 unit), and falling back to LINK_AUTH_FILE on a missing value (3 unit).

Validation: pnpm turbo run build and pnpm turbo run typecheck pass, and pnpm biome check is clean on the changed files. @stripe/link-sdk passes 211/211 and @stripe/link-integrations-better-auth passes 44/44. @stripe/link-cli has 659 tests (651 + 8 new). On a heavily loaded machine, the full CLI run had 1 to 8 timing-dependent failures, in serve.test.ts and the request agent attribution block. A different few failed on each run, and unmodified main failed in the same blocks on the same machine. None are in the tests added here.

@JayOfTheKeyboard
JayOfTheKeyboard requested a review from a team as a code owner September 28, 2026 13:26
@cla-assistant

cla-assistant Bot commented Sep 28, 2026 •

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@JayOfTheKeyboard
JayOfTheKeyboard force-pushed the fix/auth-flag-missing-value branch from 47ba0e1 to ca395c2 Compare October 11, 2026 07:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant