Skip to content
Open
11 changes: 7 additions & 4 deletions docs/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,8 @@ SUBCOMMANDS
to '~/.apify/auth.json'.
auth logout Removes authentication by deleting your API token and
account information from '~/.apify/auth.json'.
auth token Prints the current API token for the Apify CLI.
auth token Prints the API token the CLI would use, resolved from
APIFY_TOKEN or the stored login.
```

##### `apify auth login` / `apify login`
Expand All @@ -168,7 +169,8 @@ USAGE
FLAGS
-m, --method=<option> Method of logging in to Apify.
<options: console|manual>
-t, --token=<value> Apify API token.
-t, --token=<value> Apify API token to log in with and
save.
```

##### `apify auth logout` / `apify logout`
Expand All @@ -187,7 +189,8 @@ USAGE

```sh
DESCRIPTION
Prints the current API token for the Apify CLI.
Prints the API token the CLI would use, resolved from APIFY_TOKEN or the
stored login.

USAGE
$ apify auth token
Expand Down Expand Up @@ -1796,7 +1799,7 @@ ARGUMENTS

FLAGS
-t, --token=<value> Apify API token to embed in the config.
Defaults to the token from 'apify login'.
Defaults to APIFY_TOKEN, then the token from 'apify login'.
--tools=<value> Comma-separated tool IDs or Actor full names
to expose. Forwarded as a '?tools=' query parameter.
--url=<value> Apify MCP server URL.
Expand Down
9 changes: 2 additions & 7 deletions src/commands/actor/charge.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { APIFY_ENV_VARS } from '@apify/consts';

import { getApifyTokenFromEnvOrAuthFile } from '../../lib/actor.js';
import { ApifyCommand } from '../../lib/command-framework/apify-command.js';
import { Args } from '../../lib/command-framework/args.js';
import { Flags } from '../../lib/command-framework/flags.js';
import { info } from '../../lib/outputs.js';
import { getLoggedClient } from '../../lib/utils.js';
import { getLoggedClientOrThrow } from '../../lib/utils.js';

/**
* This command can be used to charge for a specific event in the pay-per-event Actor run.
Expand Down Expand Up @@ -86,11 +85,7 @@ export class ActorChargeCommand extends ApifyCommand<typeof ActorChargeCommand>
return;
}

const apifyToken = await getApifyTokenFromEnvOrAuthFile();
const apifyClient = await getLoggedClient(apifyToken);
if (!apifyClient) {
throw new Error('Apify token is not set. Please set it using the environment variable APIFY_TOKEN.');
}
const apifyClient = await getLoggedClientOrThrow();
const runId = process.env[APIFY_ENV_VARS.ACTOR_RUN_ID];

if (!runId) {
Expand Down
4 changes: 2 additions & 2 deletions src/commands/actors/call.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { runActorOrTaskOnCloud, SharedRunOnCloudFlags } from '../../lib/commands
import { finalizeRun, runUrl } from '../../lib/commands/run-result.js';
import { CommandExitCodes, LOCAL_CONFIG_PATH } from '../../lib/consts.js';
import { error, simpleLog } from '../../lib/outputs.js';
import { getLocalConfig, getLocalUserInfo, getLoggedClientOrThrow, TimestampFormatter } from '../../lib/utils.js';
import { getLocalConfig, getCurrentUserInfo, getLoggedClientOrThrow, TimestampFormatter } from '../../lib/utils.js';

export class ActorsCallCommand extends ApifyCommand<typeof ActorsCallCommand> {
static override name = 'call' as const;
Expand Down Expand Up @@ -102,7 +102,7 @@ export class ActorsCallCommand extends ApifyCommand<typeof ActorsCallCommand> {
const cwd = process.cwd();
const localConfig = getLocalConfig(cwd) || {};
const apifyClient = await getLoggedClientOrThrow();
const userInfo = await getLocalUserInfo();
const userInfo = await getCurrentUserInfo();
const usernameOrId = userInfo.username || (userInfo.id as string);

if (this.flags.json && this.flags.outputDataset) {
Expand Down
4 changes: 2 additions & 2 deletions src/commands/actors/pull.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { Flags } from '../../lib/command-framework/flags.js';
import { CommandExitCodes, LOCAL_CONFIG_PATH } from '../../lib/consts.js';
import { useActorConfig } from '../../lib/hooks/useActorConfig.js';
import { error, success } from '../../lib/outputs.js';
import { downloadZip, getLocalUserInfo, getLoggedClientOrThrow } from '../../lib/utils.js';
import { downloadZip, getCurrentUserInfo, getLoggedClientOrThrow } from '../../lib/utils.js';

const extractGitHubZip = async (url: string, directoryPath: string) => {
const zipFile = await downloadZip(url);
Expand Down Expand Up @@ -80,8 +80,8 @@ export class ActorsPullCommand extends ApifyCommand<typeof ActorsPullCommand> {

const { config: actorConfig } = actorConfigResult.unwrap();

const userInfo = await getLocalUserInfo();
const apifyClient = await getLoggedClientOrThrow();
const userInfo = await getCurrentUserInfo();

const isActorAutomaticallyDetected = !this.args.actorId;
const usernameOrId = userInfo.username || userInfo.id;
Expand Down
4 changes: 2 additions & 2 deletions src/commands/actors/push.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import {
createActZip,
createSourceFiles,
getActorLocalFilePaths,
getLocalUserInfo,
getCurrentUserInfo,
getLoggedClientOrThrow,
outputJobLog,
parseWaitForFinishMillis,
Expand Down Expand Up @@ -287,7 +287,7 @@ export class ActorsPushCommand extends ApifyCommand<typeof ActorsPushCommand> {

const { config: actorConfig } = actorConfigResult.unwrap();

const userInfo = await getLocalUserInfo();
const userInfo = await getCurrentUserInfo();
const isOrganizationLoggedIn = !!userInfo.organizationOwnerUserId;
const redirectUrlPart = isOrganizationLoggedIn ? `/organization/${userInfo.id}` : '';

Expand Down
7 changes: 3 additions & 4 deletions src/commands/actors/search.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { ApifyClient } from 'apify-client';
import chalk from 'chalk';

import { getAnonymousApifyClientOptions } from '../../lib/auth.js';
import { ApifyCommand } from '../../lib/command-framework/apify-command.js';
import { Args } from '../../lib/command-framework/args.js';
import { Flags } from '../../lib/command-framework/flags.js';
import { CompactMode, ResponsiveTable } from '../../lib/commands/responsive-table.js';
import { CommandExitCodes } from '../../lib/consts.js';
import { error, info, simpleLog } from '../../lib/outputs.js';
import { getApifyClientOptions, printJsonToStdout } from '../../lib/utils.js';
import { printJsonToStdout } from '../../lib/utils.js';

const pricingModelLabels: Record<string, string> = {
FREE: 'Free',
Expand Down Expand Up @@ -96,9 +97,7 @@ export class ActorsSearchCommand extends ApifyCommand<typeof ActorsSearchCommand
const { query } = this.args;
const { json, sortBy, category, username, pricingModel, limit, offset } = this.flags;

const clientOptions = await getApifyClientOptions();
delete clientOptions.token;
const client = new ApifyClient(clientOptions);
const client = new ApifyClient(getAnonymousApifyClientOptions());

let result;

Expand Down
4 changes: 2 additions & 2 deletions src/commands/actors/start.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { runActorOrTaskOnCloud, SharedRunOnCloudFlags } from '../../lib/commands
import { getConsoleUrl } from '../../lib/console-url.js';
import { LOCAL_CONFIG_PATH } from '../../lib/consts.js';
import { simpleLog } from '../../lib/outputs.js';
import { getLocalConfig, getLocalUserInfo, getLoggedClientOrThrow, printJsonToStdout } from '../../lib/utils.js';
import { getLocalConfig, getCurrentUserInfo, getLoggedClientOrThrow, printJsonToStdout } from '../../lib/utils.js';
import { ActorsCallCommand } from './call.js';

export class ActorsStartCommand extends ApifyCommand<typeof ActorsStartCommand> {
Expand Down Expand Up @@ -73,7 +73,7 @@ export class ActorsStartCommand extends ApifyCommand<typeof ActorsStartCommand>
const cwd = process.cwd();
const localConfig = getLocalConfig(cwd) || {};
const apifyClient = await getLoggedClientOrThrow();
const userInfo = await getLocalUserInfo();
const userInfo = await getCurrentUserInfo();
const usernameOrId = userInfo.username || (userInfo.id as string);

const {
Expand Down
34 changes: 26 additions & 8 deletions src/commands/auth/login.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,21 @@ import chalk from 'chalk';
import computerName from 'computer-name';
import open from 'open';

import { APIFY_ENV_VARS } from '@apify/consts';
import { cryptoRandomObjectId } from '@apify/utilities';

import { invalidEnvTokenMessage, loginWithToken, readEnvToken } from '../../lib/auth.js';
import { ApifyCommand } from '../../lib/command-framework/apify-command.js';
import { Flags } from '../../lib/command-framework/flags.js';
import { getConsoleIntegrationsUrl, getConsoleUrl } from '../../lib/console-url.js';
import { AUTH_FILE_PATH } from '../../lib/consts.js';
import { AUTH_FILE_PATH, CommandExitCodes } from '../../lib/consts.js';
import { getBackend } from '../../lib/credentials.js';
import { updateUserId } from '../../lib/hooks/telemetry/useTelemetryState.js';
import { useMaskedInput } from '../../lib/hooks/user-confirmations/useMaskedInput.js';
import { useSelectFromList } from '../../lib/hooks/user-confirmations/useSelectFromList.js';
import { createLocalApiServer } from '../../lib/local-api-server.js';
import { error, info, success } from '../../lib/outputs.js';
import { getLocalUserInfo, getLoggedClient, tildify } from '../../lib/utils.js';
import { error, info, success, warning } from '../../lib/outputs.js';
import { tildify } from '../../lib/utils.js';

// When logging in against a local Console instance (local platform development), validate the token
// against the local API rather than production.
Expand All @@ -28,10 +30,10 @@ const API_VERSION = 'v1';

const tryToLogin = async (token: string) => {
const apiBaseUrl = getConsoleUrl().includes('localhost') ? LOCAL_API_BASE_URL : undefined;
const isUserLogged = await getLoggedClient(token, apiBaseUrl);
const userInfo = await getLocalUserInfo();
const result = await loginWithToken(token, apiBaseUrl);

if (isUserLogged) {
if (result) {
const { userInfo } = result;
await updateUserId(userInfo.id!);

const backend = await getBackend();
Expand All @@ -47,11 +49,12 @@ const tryToLogin = async (token: string) => {
message: `You are logged in to Apify as ${userInfo.username || userInfo.id}. ${chalk.gray(`Your token is stored in ${tokenLocation}.`)}`,
});
} else {
process.exitCode = CommandExitCodes.MissingAuth;
error({
message: 'Login to Apify failed, the provided API token is not valid.',
});
}
return isUserLogged;
return result;
};

export class AuthLoginCommand extends ApifyCommand<typeof AuthLoginCommand> {
Expand Down Expand Up @@ -85,7 +88,7 @@ export class AuthLoginCommand extends ApifyCommand<typeof AuthLoginCommand> {
static override flags = {
token: Flags.string({
char: 't',
description: 'Apify API token.',
description: 'Apify API token to log in with and save.',
required: false,
}),
method: Flags.string({
Expand All @@ -99,6 +102,21 @@ export class AuthLoginCommand extends ApifyCommand<typeof AuthLoginCommand> {
async run() {
const { token, method } = this.flags;

const envToken = readEnvToken();
if (envToken.kind === 'invalid') {
warning({ message: invalidEnvTokenMessage(envToken.raw) });
}

if (envToken.kind === 'token' && envToken.token !== token?.trim()) {
error({
message: token
? `${APIFY_ENV_VARS.TOKEN} is set to a different token, so other commands would ignore this login. Unset ${APIFY_ENV_VARS.TOKEN} and try again.`
: `${APIFY_ENV_VARS.TOKEN} is set, so other commands would ignore this login. Unset ${APIFY_ENV_VARS.TOKEN} and try again, or pass the same token with --token.`,
});
process.exitCode = CommandExitCodes.InvalidInput;
return;
}

if (token) {
await tryToLogin(token);
return;
Expand Down
14 changes: 13 additions & 1 deletion src/commands/auth/logout.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import { APIFY_ENV_VARS } from '@apify/consts';

import { invalidEnvTokenMessage, readEnvToken } from '../../lib/auth.js';
import { ApifyCommand } from '../../lib/command-framework/apify-command.js';
import { AUTH_FILE_PATH } from '../../lib/consts.js';
import { clearKeyringSecrets } from '../../lib/credentials.js';
import { rimrafPromised } from '../../lib/files.js';
import { updateUserId } from '../../lib/hooks/telemetry/useTelemetryState.js';
import { success } from '../../lib/outputs.js';
import { success, warning } from '../../lib/outputs.js';
import { tildify } from '../../lib/utils.js';

export class AuthLogoutCommand extends ApifyCommand<typeof AuthLogoutCommand> {
Expand Down Expand Up @@ -31,5 +34,14 @@ export class AuthLogoutCommand extends ApifyCommand<typeof AuthLogoutCommand> {
await updateUserId(null);

success({ message: 'You are logged out from your Apify account.' });

const envToken = readEnvToken();
if (envToken.kind === 'token') {
warning({
message: `${APIFY_ENV_VARS.TOKEN} is still set, so commands stay authenticated with that token.`,
});
} else if (envToken.kind === 'invalid') {
warning({ message: invalidEnvTokenMessage(envToken.raw) });
}
}
}
14 changes: 7 additions & 7 deletions src/commands/auth/token.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import { resolveAuth } from '../../lib/auth.js';
import { ApifyCommand } from '../../lib/command-framework/apify-command.js';
import { simpleLog } from '../../lib/outputs.js';
import { getLocalUserInfo, getLoggedClientOrThrow } from '../../lib/utils.js';
import { getLoggedClientOrThrow } from '../../lib/utils.js';

export class AuthTokenCommand extends ApifyCommand<typeof AuthTokenCommand> {
static override name = 'token' as const;

static override description = 'Prints the current API token for the Apify CLI.';
static override description =
'Prints the API token the CLI would use, resolved from APIFY_TOKEN or the stored login.';

static override examples = [
{
description: 'Print the stored API token to stdout (use with care — it is a secret).',
description: 'Print the resolved API token to stdout (use with care — it is a secret).',
command: 'apify auth token',
},
];
Expand All @@ -18,10 +20,8 @@ export class AuthTokenCommand extends ApifyCommand<typeof AuthTokenCommand> {

async run() {
await getLoggedClientOrThrow();
const userInfo = await getLocalUserInfo();
const auth = await resolveAuth();

if (userInfo.token) {
simpleLog({ message: userInfo.token, stdout: true });
}
simpleLog({ message: auth!.token, stdout: true });
}
}
5 changes: 2 additions & 3 deletions src/commands/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ import { LANGUAGE_FLAG_CHOICES, USE_CASE_FLAG_CHOICES } from '../lib/templates/c
import {
downloadAndUnzip,
getJsonFileContent,
getLocalUserInfo,
getCurrentUserInfo,
getLoggedClientOrThrow,
isNodeVersionSupported,
isPythonVersionSupported,
Expand Down Expand Up @@ -317,8 +317,7 @@ export class CreateCommand extends ApifyCommand<typeof CreateCommand> {
? {
provider: gitProvider,
client: await getLoggedClientOrThrow(),
// Read after the client, which refreshes auth.json from the token the run resolved.
account: toGitAccount(await getLocalUserInfo()),
account: toGitAccount(await getCurrentUserInfo()),
// Omitted means on: the webhook is what makes a Git-sourced Actor rebuild on a push.
autoBuild: this.flags.autoBuild !== 'off',
...parseGitRepoFlag(gitRepo, actorName),
Expand Down
4 changes: 2 additions & 2 deletions src/commands/datasets/get-items.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { ApifyCommand } from '../../lib/command-framework/apify-command.js';
import { Args } from '../../lib/command-framework/args.js';
import { Flags } from '../../lib/command-framework/flags.js';
import { error, simpleLog } from '../../lib/outputs.js';
import { getLocalUserInfo, getLoggedClientOrThrow } from '../../lib/utils.js';
import { getCurrentUserInfo, getLoggedClientOrThrow } from '../../lib/utils.js';

const downloadFormatToContentType: Record<DownloadItemsFormat, string> = {
[DownloadItemsFormat.JSON]: 'application/json',
Expand Down Expand Up @@ -106,7 +106,7 @@ export class DatasetsGetItems extends ApifyCommand<typeof DatasetsGetItems> {
};
}

const info = await getLocalUserInfo();
const info = await getCurrentUserInfo();

const byName = await client
.dataset(`${info.username!}/${datasetId}`)
Expand Down
4 changes: 2 additions & 2 deletions src/commands/datasets/ls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Flags } from '../../lib/command-framework/flags.js';
import { prettyPrintBytes } from '../../lib/commands/pretty-print-bytes.js';
import { CompactMode, ResponsiveTable } from '../../lib/commands/responsive-table.js';
import { info, simpleLog } from '../../lib/outputs.js';
import { getLocalUserInfo, getLoggedClientOrThrow, printJsonToStdout, TimestampFormatter } from '../../lib/utils.js';
import { getCurrentUserInfo, getLoggedClientOrThrow, printJsonToStdout, TimestampFormatter } from '../../lib/utils.js';

const table = new ResponsiveTable({
allColumns: ['Dataset ID', 'Name', 'Items', 'Size', 'Created', 'Modified'],
Expand Down Expand Up @@ -58,7 +58,7 @@ export class DatasetsLsCommand extends ApifyCommand<typeof DatasetsLsCommand> {
const { desc, offset, limit, json, unnamed } = this.flags;

const client = await getLoggedClientOrThrow();
const user = await getLocalUserInfo();
const user = await getCurrentUserInfo();

const rawDatasetList = await client.datasets().list({ desc, offset, limit, unnamed });

Expand Down
Loading