> ## Documentation Index
> Fetch the complete documentation index at: https://arkor-92aeef0e-eng-635.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# arkor login / logout / whoami

> Sign in to Arkor's managed backend, sign out, and inspect the current identity.

# `arkor login`, `arkor logout`, `arkor whoami`

Three short commands that read or write `~/.arkor/credentials.json`. None of them touches `.arkor/state.json`. For anonymous workspaces, project routing is auto-created by the runtime on the first `trainer.start()` (or first inference call). For OAuth workspaces, `.arkor/state.json` has to exist before the run: today, neither `arkor login` nor `arkor init` creates it, so the practical path is to create it manually with `{ orgSlug, projectSlug, projectId }`. The runtime points you at this fallback when it errors out on a missing state file.

## `arkor login`

<CodeGroup>
  ```bash pnpm theme={null}
  pnpm arkor login
  ```

  ```bash npm theme={null}
  npm arkor login
  ```

  ```bash yarn theme={null}
  yarn arkor login
  ```

  ```bash yarn-berry theme={null}
  yarn run arkor login
  ```

  ```bash bun theme={null}
  bun arkor login
  ```
</CodeGroup>

Sign in to the managed backend. With no flags the CLI asks interactively whether to sign in via Arkor Cloud's OAuth or as an anonymous session. The interactive selector defaults to **Anonymous**, so accepting the default (or piping into a non-TTY) lands on the anonymous path; OAuth runs only when you explicitly select it or pass `--oauth`.

### Synopsis

```
arkor login [options]
```

### Options

| Flag           | Description                                                                                                                                                                                                                                                                                                                                              |
| -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--oauth`      | Skip the picker and run the Arkor Cloud OAuth (Authorization Code + PKCE) flow directly. Mutually exclusive with `--anonymous`. Errors out with `--oauth needs a browser callback that CI runners can't complete. Use --anonymous in CI.` when `process.env.CI` is set, because PKCE needs a browser callback and the loopback would hang forever in CI. |
| `--anonymous`  | Skip the picker and request a throwaway anonymous token. Mutually exclusive with `--oauth`. This is also what `arkor dev` does at launch when no credentials exist on disk: it always bootstraps anonymous first.                                                                                                                                        |
| `--no-browser` | Disable the automatic `open(url)` call. The authorization URL is printed either way (`Browser: <url>` line); this flag only stops the CLI from launching a browser for you. Useful in headless environments (SSH, Docker). It only affects the OAuth path.                                                                                               |

### What happens

1. The CLI calls `/v1/auth/cli/config` on the cloud-api to read the deployment's OAuth settings.
2. If `--anonymous` is passed, the CLI requests an anonymous token from `/v1/auth/anonymous` and writes it to `~/.arkor/credentials.json` with `mode: "anon"`.
3. If `--oauth` is passed, it skips straight to the OAuth flow.
4. If no flag is passed, it shows an interactive picker (`OAuth (browser)` / `Anonymous`) with **Anonymous** preselected. Accepting the default, including in non-interactive contexts where the prompt is non-blocking, runs the anonymous path; choosing OAuth runs the OAuth flow.
5. The OAuth flow generates a PKCE pair, starts a loopback HTTP server on one of the cloud-api-provided callback ports, opens (or prints) the authorize URL, and waits for the callback. State is verified before exchanging the code for tokens; a mismatch aborts to prevent CSRF. The resulting OAuth tokens are written to `~/.arkor/credentials.json` with `mode: "auth0"`.

The loopback server is closed in a `finally` block so it does not stick around if login fails.

### Anonymous mode in one paragraph

Anonymous credentials let you try Arkor without an account: training runs, jobs, and any work you do are tied to the local machine via the anonymous token. The anonymous path always mints a brand-new token (and a new `anonymousId`) and overwrites `~/.arkor/credentials.json`, so re-running `arkor login --anonymous` does not refresh the existing identity. Switching to OAuth (`arkor login --oauth`, or selecting `OAuth (browser)` in the picker) overwrites the credentials file the same way and does not migrate prior anonymous workspaces or jobs into the account. Merging anonymous work into an OAuth account once you sign in is on the roadmap; until that lands, run `arkor login --oauth` **before** you start the runs you want associated with the account.

### Anonymous issuance output

Both anonymous paths surface the new `anonymousId` and an explanation that the same id is how Arkor Cloud recognises this client across sessions, though the line shape differs by entry point. `arkor login` (`--anonymous` flag or picker → **Anonymous**) prints `Anonymous id: <id>` as the spinner stop and then a separate info line saying that keeping the credentials file (`credentialsPath()`, typically `~/.arkor/credentials.json` on Linux and macOS) is what preserves the identity. `arkor dev`'s auto-bootstrap skips the spinner and emits a single info line that already embeds the id and the same explanation. The picker → **Anonymous** path additionally surfaces a one-line warn alongside the success message reading "Anonymous sessions aren't guaranteed to persist — sign in with `arkor login --oauth` to tie future work to your Arkor Cloud account.", so the upgrade hint is visible at issuance time. The explicit `--anonymous` shortcut suppresses that warn because it skips the `/v1/auth/cli/config` fetch and so cannot tell whether `arkor login --oauth` would succeed on this deployment; pointing at it on a rare anon-only deployment would steer users at a command that fails.

## `arkor logout`

<CodeGroup>
  ```bash pnpm theme={null}
  pnpm arkor logout
  ```

  ```bash npm theme={null}
  npm arkor logout
  ```

  ```bash yarn theme={null}
  yarn arkor logout
  ```

  ```bash yarn-berry theme={null}
  yarn run arkor logout
  ```

  ```bash bun theme={null}
  bun arkor logout
  ```
</CodeGroup>

Deletes `~/.arkor/credentials.json`. Prompts for confirmation by default.

### Synopsis

```
arkor logout [options]
```

### Options

| Flag        | Description                   |
| ----------- | ----------------------------- |
| `-y, --yes` | Skip the confirmation prompt. |

### Behavior

* If the credentials file does not exist, the CLI logs `No credentials on file.` and exits.
* If the user declines the prompt, the CLI logs `Aborted.` and exits without deleting.
* `arkor logout` does not touch `.arkor/state.json` or the `.arkor/build/` artifact. To start fully fresh, remove `.arkor/` manually as well.

## `arkor whoami`

<CodeGroup>
  ```bash pnpm theme={null}
  pnpm arkor whoami
  ```

  ```bash npm theme={null}
  npm arkor whoami
  ```

  ```bash yarn theme={null}
  yarn arkor whoami
  ```

  ```bash yarn-berry theme={null}
  yarn run arkor whoami
  ```

  ```bash bun theme={null}
  bun arkor whoami
  ```
</CodeGroup>

Prints the current identity from `/v1/me` on the cloud-api, plus the org slugs you can reach.

### Synopsis

```
arkor whoami
```

No flags.

### Output

When signed in, the command prints the JSON `user` object pretty-printed, then a single `Orgs: <slug>, <slug>, …` line if the response includes any. When `~/.arkor/credentials.json` is missing, it prints `Not signed in. Run \`arkor login\` or \`arkor login --anonymous\`.\` and exits.

### Exit codes

* `0`: signed in, identity printed.
* `0`: not signed in; the message is informational only.
* `1`: the cloud-api returned `426 Upgrade Required`. The CLI prints the upgrade hint (and the upgrade command for your detected package manager) and sets `process.exitCode = 1` so the deprecation-warning flush in `arkor`'s shutdown hook still runs before the process exits.
* Other 4xx / 5xx are reported as `Failed to fetch /v1/me (<status>). Token may be expired.` and exit `0`.

## Where the credentials live

Both modes write to the same file at `~/.arkor/credentials.json` and are tagged with a `mode` field of either `"auth0"` or `"anon"` so the rest of the CLI (and the Studio server) knows which path to use. See [Project structure](/concepts/project-structure) for the full layout.

## Token expiry

For OAuth sessions, the credentials file records both the access token and the issued refresh token, plus the `expiresAt` timestamp returned by the token exchange. The refresh token is stored today, but the CLI does **not** yet auto-refresh expired access tokens; that path is [on the roadmap](/roadmap#auth0-token-auto-refresh).

In practice that means:

* An expired access token shows up as a `Failed to fetch /v1/me (401). Token may be expired.` from `arkor whoami`, or analogous failures from anything that talks to the cloud-api.
* The fix for an OAuth session is to re-run `arkor login --oauth`, which goes through the full PKCE flow again and overwrites `~/.arkor/credentials.json` with fresh tokens.

Anonymous tokens have no client-side expiry tracking; the cloud-api decides when they stop working. If an anonymous session starts failing, run `arkor login --anonymous` to mint a new one (this issues a new `anonymousId`, so it is effectively a different workspace).

## Common errors

| Message                                                                                               | Where                                             | What it means                                                                                                                                                                                      | Fix                                                                                                                                                                                                                                                                                   |
| ----------------------------------------------------------------------------------------------------- | ------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Pick one of --oauth / --anonymous, not both.`                                                        | `arkor login`                                     | Both mode flags were passed.                                                                                                                                                                       | Pass at most one.                                                                                                                                                                                                                                                                     |
| `--oauth needs a browser callback that CI runners can't complete. Use --anonymous in CI.`             | `arkor login --oauth` (with `process.env.CI` set) | PKCE depends on a loopback redirect from a browser, which CI cannot satisfy.                                                                                                                       | Use `--anonymous` in CI. For local headless flows that still have a reachable browser (e.g. `... --no-browser \| tee logs`), unset `CI` for the run.                                                                                                                                  |
| `State mismatch — aborting to prevent CSRF`                                                           | `arkor login --oauth`                             | The `state` returned to the loopback callback does not match the one the CLI generated (almost always because the browser hit a stale tab from a previous login attempt).                          | Re-run `arkor login --oauth` and complete the flow in the freshly opened tab.                                                                                                                                                                                                         |
| `Auth0 did not return a refresh token. Make sure the Application has 'offline_access' scope enabled.` | `arkor login --oauth`                             | The OAuth token exchange succeeded but the response had no `refresh_token`, so the CLI cannot keep the session alive past the access token's lifetime. Usually a deployment-side misconfiguration. | Enable the `offline_access` scope on the OAuth (Auth0) application, then re-run `arkor login --oauth`.                                                                                                                                                                                |
| `No credentials on file.`                                                                             | `arkor logout`                                    | `~/.arkor/credentials.json` does not exist. Nothing to delete.                                                                                                                                     | Run `arkor login` first if you wanted to sign in.                                                                                                                                                                                                                                     |
| `Not signed in. Run \`arkor login\` or \`arkor login --anonymous\`.\`                                 | `arkor whoami`                                    | Same condition as above, surfaced from a different command.                                                                                                                                        | Same fix.                                                                                                                                                                                                                                                                             |
| `Failed to fetch /v1/me (<status>). Token may be expired.`                                            | `arkor whoami`                                    | The cloud-api rejected the request with a non-200, non-426 status. Most often expired access tokens.                                                                                               | Re-run `arkor login` matching the current `mode`: `arkor login --oauth` for `mode: "auth0"`, `arkor login --anonymous` for `mode: "anon"` (the latter mints a new `anonymousId`, so it lands in a new workspace). The exit code stays `0` so wrapper scripts can inspect the message. |
| `426 Upgrade Required` (with upgrade hint)                                                            | `arkor whoami` (and other cloud-api calls)        | The deployment requires a newer SDK version. The CLI prints the upgrade command for your detected package manager and sets `process.exitCode = 1`.                                                 | Upgrade the `arkor` package and re-run.                                                                                                                                                                                                                                               |
