# Authentication

> UiPath CLI supports three authentication flows that map to the three common use cases: a developer on a laptop, a CI/CD pipeline calling Orchestrator with an External Application, and a container or ephemeral runner that already holds an access token. All three end at the same place — an authenticated session that every subsequent `uip` command reuses — but they differ in how they obtain the token and how the CLI refreshes it.

UiPath CLI supports three authentication flows that map to the three common use cases: a developer on a laptop, a CI/CD pipeline calling Orchestrator with an External Application, and a container or ephemeral runner that already holds an access token. All three end at the same place — an authenticated session that every subsequent `uip` command reuses — but they differ in how they obtain the token and how the CLI refreshes it.

## Pick a flow

| You are… | Use this | How |
|---|---|---|
| A developer on a laptop or workstation | **Interactive OAuth2** | `uip login` opens a browser, you sign in once, tokens are stored and refreshed automatically. |
| A CI/CD pipeline or server | **External Application (client credentials)** | Create an External App in UiPath, pass its ID and secret to `uip login --client-id … --client-secret …`. Tokens are stored and refreshed. |
| A container, ephemeral runner, or any process that already holds a token | **Environment-variable auth** | Set `UIPATH_CLI_ENABLE_ENV_AUTH=true` and supply the token + organization/tenant via env vars. No file is written; no refresh. |

`uip logout` clears any on-disk credentials from the first two flows. The env-var flow has nothing to clear — unset the env vars.

## Flow 1 — Interactive OAuth2

Run `uip login` with no arguments:

```bash
uip login
```

`uip` opens your default browser on UiPath's sign-in page. After you authenticate, UiPath redirects back to a local callback that `uip` is listening on, and the CLI prompts you to pick a tenant. When the tenant is selected, the session is saved and you are done.

Useful flags:

```bash
uip login --tenant DefaultTenant                 # skip the tenant picker
uip login --organization my-org                  # skip the org picker for users in multiple orgs
uip login --interactive                          # explicitly show the tenant picker even if --tenant was set
uip login --authority https://example.com        # point at a non-default identity authority (Automation Suite, staging)
uip login --scope "OR.Folders OR.Jobs"           # restrict the session to specific scopes
uip login --file /path/to/creds                  # store credentials in a non-default folder
```

### Where credentials are stored

By default, the session is stored inside a `.uipath/` folder. `uip` looks for this folder in three places, in order:

1. Explicit folder — if you passed `--file <folder>`, the CLI uses that folder. Pass the folder, not a file path.
2. **Walk up from the current working directory** looking for `.uipath/` — so a project folder can carry its own session without touching the user's home.
3. `~/.uipath/` — the default fallback.

When no `.uipath/` exists anywhere on the walk-up chain, `uip login` creates one at `~/.uipath/`. Treat the folder's contents as opaque — they are managed by `uip login`, `uip login tenant set`, and `uip logout`.

### Manage tenants mid-session

The session stores a single active tenant at a time. Switch without re-running the full login flow:

```bash
uip login tenant list           # show all tenants available to your account
uip login tenant set MyTenant   # switch the active tenant
```

`uip login status` shows the current organization, tenant, and token expiration.

:::tip
Every `uip or …` command also accepts `--tenant <name>` to override the session tenant for a single call — useful when you need to run against two tenants in the same script without re-logging.
:::

### Refresh is automatic

`uip` refreshes access tokens in the background when they are near expiry. You do not need to re-run `uip login` unless the refresh token itself expires or is revoked, or you change tenants/organizations.

## Flow 2 — External Application (client credentials)

Create an External Application in UiPath (Automation Cloud: **Admin → External Applications**) with:

- Application type: **Confidential**
- Grant type: **Client credentials**
- Scopes: the scopes your pipeline needs (for example, `OR.Folders`, `OR.Jobs`, `OR.Execution`, `OR.Assets`, `OR.Users`)

Copy the generated **App ID** and **App Secret**, and store them in the pipeline's secret store (GitHub Actions secrets, Azure DevOps variable groups, Jenkins credentials, Vault, etc.).

Sign in from the pipeline:

```bash
uip login \
  --client-id env.UIPATH_CLIENT_ID \
  --client-secret env.UIPATH_CLIENT_SECRET \
  --tenant "$UIPATH_TENANT"
```

### The env.VAR_NAME prefix

`--client-id` and `--client-secret` accept either a literal value or the **special prefix `env.`** that resolves to an environment variable at runtime. `env.UIPATH_CLIENT_ID` means "read the value from the `UIPATH_CLIENT_ID` environment variable". This keeps secret values out of shell history and process listings — unlike `--client-secret "$UIPATH_CLIENT_SECRET"`, which expands on the command line.

Literal values still work:

```bash
uip login --client-id 3c7af0…-… --client-secret s3cr3t…   # works, but the secret is visible in history
```

:::warning
Do **not** set `UIPATH_CLIENT_ID` / `UIPATH_CLIENT_SECRET` as environment variables and expect `uip login` to pick them up automatically. Prior to UiPath CLI 1.0, `uip login --env` and implicit env-var reading were supported; they were removed. You must pass the flag explicitly, either with a literal value or with the `env.` prefix.
:::

### Scope overrides

If the External App has multiple scopes and you want a narrower session for a specific script, pass `--scope`:

```bash
uip login \
  --client-id env.UIPATH_CLIENT_ID \
  --client-secret env.UIPATH_CLIENT_SECRET \
  --tenant "$UIPATH_TENANT" \
  --scope "OR.Folders OR.Jobs"
```

## Flow 3 — Environment-variable auth (access token already in hand)

Some environments — containers built by another pipeline, scheduled jobs, test fixtures — already hold a valid UiPath access token and have no need for interactive sign-in or client-credentials exchange. Enable the env-var auth flow by setting:

```bash
export UIPATH_CLI_ENABLE_ENV_AUTH=true

export UIPATH_CLI_AUTH_TOKEN="$UIPATH_TOKEN"            # JWT access token
export UIPATH_CLI_ORGANIZATION_NAME=my-org
export UIPATH_CLI_ORGANIZATION_ID="$UIPATH_ORG_ID"
export UIPATH_CLI_TENANT_NAME=DefaultTenant
export UIPATH_CLI_TENANT_ID="$UIPATH_TENANT_ID"
```

With `UIPATH_CLI_ENABLE_ENV_AUTH=true`, every `uip` invocation authenticates from these variables and bypasses the `.uipath/` folder entirely. There is no `uip login` step and nothing is written to disk.

### Notes and limitations

- **Opaque token.** The caller is responsible for the token's freshness. There is no refresh flow. When the token expires, `uip login status` reports `Expired` and commands fail until the variable is rotated.
- **Server URL is derived from the token.** The `iss` claim in the JWT is authoritative — you do not set `UIPATH_URL`. This prevents mis-routing when a pipeline sets `UIPATH_URL` inconsistently with the token.
- **The gate matters.** If `UIPATH_CLI_ENABLE_ENV_AUTH` is unset or set to anything other than the literal string `true`, the file-based flow is used. Misspelling the gate silently falls back — check with `uip login status`.
- **Missing values fail explicitly.** If any required variable is empty, `uip` returns a clear error naming the offending variable, not a generic "not authenticated".

Example GitHub Actions step using env-var auth:

```yaml
- name: Run uip against Orchestrator
  env:
    UIPATH_CLI_ENABLE_ENV_AUTH: "true"
    UIPATH_CLI_AUTH_TOKEN: ${{ secrets.UIPATH_TOKEN }}
    UIPATH_CLI_ORGANIZATION_NAME: contoso
    UIPATH_CLI_ORGANIZATION_ID: ${{ secrets.UIPATH_ORG_ID }}
    UIPATH_CLI_TENANT_NAME: Default
    UIPATH_CLI_TENANT_ID: ${{ secrets.UIPATH_TENANT_ID }}
  run: uip or folders list --output json
```

## Signing out

```bash
uip logout                         # clear the default credentials folder
uip logout --file /path/to/creds   # clear a non-default credentials folder
```

`logout` clears the stored session inside `.uipath/`. On the env-var flow there is nothing to remove — unset the variables.

## Troubleshooting

### ❌ Not logged in

Either no `.uipath/` folder was found on the walk-up chain, or the stored session is unreadable. Run `uip login` (or set the env-var flow) and retry.

### Token expired

Interactive and External App sessions refresh automatically when near expiry. If you see `Expired`, the refresh token itself expired or was revoked — re-run `uip login`. For env-var auth, rotate `UIPATH_CLI_AUTH_TOKEN`.

### Multiple org members, wrong org picked

Pass `--organization <logical-name>` on `uip login` to bypass the org picker, or `uip login tenant list` after the fact to see what the session is actually bound to.

### Corporate proxy blocks the browser callback

The interactive flow opens a local callback port on `127.0.0.1`. Most proxies leave loopback alone, but some aggressive setups block it. Work around by using Flow 2 (External App) or Flow 3 (env-var auth) — both avoid the browser callback entirely.

## See also

- [Installing UiPath CLI](./installing-uipath-cli.md) — one-time setup before authentication.
- [Configuration](./configuration.md) — environment variables and flag precedence.
- [Sessions and credentials](./concepts-sessions.md) — on-disk layout of the credentials folder.
- [uip login reference](./uip-login.md), [uip logout reference](./uip-logout.md).
