Skip to content

Token resolution #1418

Description

@l2ysho

Note

TL;DR — Three separate resolvers decide which token a command uses, and they disagree. resolveToken ignores APIFY_TOKEN, mcp install honors it, the actor entrypoint requires it. On top of that, getLoggedClient() persists whatever token it resolved, so a one-off token overwrites the stored login. Fix: one resolver, one order, and only apify login writes credentials. Two stacked PRs, no data migration.

Part of #1383 (Stage-1).

Problem

Resolver Order
resolveTokenutils.ts:132, behind all 46 getLoggedClientOrThrow() calls passed token → stored. No env.
resolveApifyTokenmcp/install.ts:13 --tokenAPIFY_TOKEN → stored
getApifyTokenFromEnvOrAuthFilelib/actor.ts:24 APIFY_TOKEN → stored

Same shell, three answers depending on the command. --token exists on 2 of ~50 commands.

Second defect, found in the review of #1293: getLoggedClient() both resolves and persists. Once the resolver returns an env token, setToken() writes it over the stored login and rewrites username/id. The stored account is replaced by a transient env var, and it survives unset.

Decision

--token  →  APIFY_TOKEN  →  stored

This is not a new rule. mcp install and the actor entrypoint already work this way; only resolveToken does not. It also needs no special case for the actor CLI: inside a platform run there is no stored login, so APIFY_TOKEN wins on its own.

Scope

  • One resolver. Delete getApifyTokenFromEnvOrAuthFile (lib/actor.ts:24, used by actor charge) and resolveApifyToken (mcp/install.ts:13).
  • Split the resolve/persist pair:
    • resolveAuth() — reads only. --tokenAPIFY_TOKEN → stored.
    • loginWithToken(token) — authenticates and saves. Only apify login calls it.
  • --token becomes a global flag through baseOptions in _buildParseArgsOption, next to --help and --user-agent. On login it keeps today's meaning, save the token. Everywhere else it is one-off and stores nothing.
  • apify login ignores APIFY_TOKEN. Logging in is explicit.
  • apify auth token prints the token that would be used, not getLocalUserInfo().token. It only looks right today because of the overwrite bug.
  • apify run passes the resolved token to the child and stops overwriting an inherited APIFY_TOKEN (run.ts:331).
  • A rejected token names its source: "APIFY_TOKEN is set but was rejected" is not the same message as "not logged in".

Commit order

  1. Write guard — reads stop writing, loginWithToken added, only login persists.
  2. Precedence — env added to the resolver, other two resolvers folded in, global --token, run child env.

Never the reverse. Precedence without the guard is the #1293 data-loss bug.

Open

  • --token on every command, or only ones that authenticate? Suggest every command — the resolver is global and exceptions are hard to maintain.
  • A one-off token has no stored username. push, call and others need it. Suggest a lazy in-memory lookup, only when the command needs it.
  • Exit codes on auth failure. Fix the auth paths here, leave the rest of the CLI to Many commands exit with code 0 on failure (and some failures skip telemetry) #1254.
  • No warning when env overrides a stored login. apify info names the source instead.

Supersedes and related

Ref State Relation
#720 open issue Closes. Asks for APIFY_TOKEN to work as a parameter or env var.
#94 closed issue The original request, from 2019 — run one command as a different user. Closed into #445; the global --token here is the actual fix.
#1293 closed PR Supersedes. First attempt. Correct read-side precedence, blocked because getLoggedClient persisted the env token over the stored login. Its tests are worth lifting from claude/apify-token-permissions-bug-15c25d.
#1246 open draft PR Supersedes. Same goal, env-first, no write guard. Close it when this lands.
#1262 open issue Related, not closed. Touches the same line (run.ts:331), but the hang is the child SDK blocking on a terminal-status POST. The fix may belong in the SDK.
#1254 open issue Related. Auth paths get correct exit codes here; the rest of the CLI stays with #1254.
#1051 open issue Related. 401 handling becomes profile-aware in Stage-3 (#1384).
#1328 open epic Parent discussion. Its "Token handling" section is decided by this issue.
apify/agent-skills#80 cross-repo Asks to stop using APIFY_TOKEN in their docs. Tell them the outcome — support stays, precedence is now defined.

Notes

🤖 Generated with Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    t-buildersIssues owned by the Builders team.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions