# Sign in and choose a company

> Connect the CLI to the hosted Oatmilk or your own, with your browser, another device or an API key.

Source: https://app.getoatmilk.com/docs/terminal/sign-in

The CLI signs in the way an AI app does: you approve it in your browser, and it acts as you. Your role in each company still decides what it can see and do. For scripts and CI, an [API key](https://app.getoatmilk.com/docs/authentication.md#api-keys) works instead.

## 1. Choose the Oatmilk to connect to

Without `--host`, the CLI talks to the hosted Oatmilk at `https://app.getoatmilk.com`. For any other Oatmilk, pass its address once when you sign in; the CLI remembers it for later commands.

| Oatmilk | Address |
| --- | --- |
| The hosted Oatmilk | Nothing to add |
| Your own, on this computer | `--host https://oatmilk.localhost` |
| Your own, on a server | `--host https://books.example.com` |
| A development server from `bun run dev` | `--host localhost:3000` |

The address is read from `--host` first, then the `OATMILK_HOST` environment variable, then the last address you signed in to. Addresses must use `https`; plain `http` is allowed only for `localhost`.

## 2. Sign in with your browser

```bash
oatmilk login
# or, for your own Oatmilk:
oatmilk login --host https://books.example.com
```

1. Your browser opens Oatmilk's sign-in page. Sign in if you aren't already.
2. Oatmilk shows what the CLI asks for. Choose **Allow**.
3. The page says you're signed in. Go back to the terminal: it shows your email, company and role.

The browser sends the sign-in back to a one-time address on your own computer (`http://localhost:<port>/callback`), so nothing to copy. If no browser opens, the CLI prints the address to open; `--no-browser` or `OATMILK_NO_BROWSER=1` always prints it instead.

## Sign in on another device

Over SSH, in a container, or on a machine without a browser:

```bash
oatmilk login --device
```

1. The CLI prints an address. Open it on any device: your laptop or your phone.
2. Sign in and choose **Allow**.
3. Oatmilk shows a code with a **Copy code** button. Paste it into the terminal.

The code only works for the terminal that asked for it, and only once.

## Sign in with an API key

An API key belongs to one company and keeps exactly the permissions it was given, so it suits scripts, CI and shared machines. Create one in **Developers › API keys** in Oatmilk, then:

```bash
oatmilk login --api-key                  # asks for the key without showing it
echo "$KEY" | oatmilk login --api-key    # or pipe it in
```

For a single command or a CI job, skip `login` and set the key in the environment. `OATMILK_API_KEY` and `OATMILK_TOKEN` (an OAuth access token) win over a saved sign-in.

```bash
OATMILK_API_KEY=oat_live_… oatmilk whoami
```

## 3. Check who you are

```bash
oatmilk whoami
oatmilk whoami --json
```

It shows your email, the company, your role, the address and how you signed in. With an API key it also lists the key's permissions.

## 4. Choose a company

A browser sign-in can open every company you belong to. The CLI works in one at a time, and `oatmilk whoami` shows which.

```bash
oatmilk orgs                      # the companies you can open; ● marks the current one
oatmilk orgs use "Contoso"        # switch by name or ID
oatmilk api entries.list --org org_2abc…   # one command in another company
```

`OATMILK_ORG` sets the company for every command. An API key always works in its own company, so `orgs use` asks you to sign in with the browser instead.

## Your own Oatmilk

A [self-hosted Oatmilk](https://app.getoatmilk.com/docs/self-hosting.md) signs you in through its own accounts, with the same steps. Two things differ on this computer's `*.localhost` address:

- **The certificate.** Oatmilk's local HTTPS certificate comes from its own certificate authority, which Node.js doesn't trust by default. Point `NODE_EXTRA_CA_CERTS` at the file `bun run self-host cert` saves, in every terminal that runs the CLI:

```bash
export NODE_EXTRA_CA_CERTS="$HOME/oatmilk/self-host/oatmilk-local-ca.crt"   # where your Oatmilk checkout is
oatmilk login --host https://oatmilk.localhost
```

- **The name.** `*.localhost` names always mean this computer. The CLI knows that without an `/etc/hosts` entry.

A server with a real domain and a Let's Encrypt certificate needs neither.

## Sign out

```bash
oatmilk logout                     # this address
oatmilk logout --all               # every address you signed in to
```

Signing out revokes the browser sign-in, so the saved token stops working everywhere. To stop an API key, delete it in **Developers › API keys**.

## Where sign-ins are saved

Sign-ins live in `credentials.json` in `~/.config/oatmilk` (`$XDG_CONFIG_HOME/oatmilk` when that is set, `%APPDATA%\oatmilk` on Windows). Only your user can read it. `OATMILK_CONFIG_DIR` moves it, for example to keep a separate sign-in per project. Browser sign-ins refresh themselves; run `oatmilk login` again if one stops working.

## When it goes wrong

| Message or exit code | What to do |
| --- | --- |
| Exit code `3`, "You're not signed in" | Run `oatmilk login`, or set `OATMILK_API_KEY`. |
| "Oatmilk addresses must use https" | Use `https://…`. Only `localhost` may use `http`. |
| "That isn't an Oatmilk API key" | Keys start with `oat_`. Copy the whole key again. |
| A certificate error on `*.localhost` | Set `NODE_EXTRA_CA_CERTS` as shown in [Your own Oatmilk](#your-own-oatmilk). |
| Exit code `4`, not allowed | Your role, or the key's permissions, don't allow that action. Check with `oatmilk whoami`. |
| The browser never comes back | Cancel with Ctrl+C and use `oatmilk login --device`. |
