---
title: Authentication
description: How `coduck login` works, how tokens are stored, and how to revoke them.
category: cli
order: 2
agent: "Run 'coduck login' — opens a browser, user approves, CLI gets a 90-day token. No password handling in the CLI ever. 'coduck token list', 'coduck token revoke <id>', 'coduck logout'."
---

# Authentication

The CLI uses **browser-based device authorization**. You never type your CoDuck password into your terminal. Approval happens on a CoDuck web page that you're already signed in to.

## Signing in

```bash
coduck login
```

What happens, step by step:

1. CLI prints a short confirmation code like `AB7K-9XQM` and opens your browser to `https://app.coduck.ai/cli?code=AB7K-9XQM`.
2. If you're not signed in to the web app, you're sent to `/login` first, then bounced back.
3. The page shows the device the CLI is asking for ("your hostname / your OS") and an Approve / Deny button.
4. You click **Approve**.
5. Within ~5 seconds, the CLI receives the token and writes it to `~/.coduck/credentials.json` (file mode `0600`).

That's it. From this point on, every CoDuck command works without prompting.

> [!NOTE]
> The CLI has no `--password` flag and never reads your password from stdin or an env var. If you're seeing a doc anywhere that mentions one, it's outdated.

## Token lifetime

| What | How long |
|---|---|
| Initial token | 90 days |
| Sliding extension on each use | +30 days, capped at 180 from issue |
| Hard maximum lifetime | 180 days from creation |
| Idle expiry | 90 days of no use |

In practice: if you use the CLI even occasionally, you'll never get logged out. If you stop using it for 90 days, your next call will 401 and you'll need to `coduck login` again.

## Managing tokens

Every device gets its own token. You can have many — one per laptop, one for CI, etc.

### List your tokens

```bash
coduck token list
```

Shows each token with its device name, last-used timestamp, last IP, and expiration.

### Revoke a single token

```bash
coduck token revoke <token-id>
```

Takes effect within ~30 seconds (the API caches the revocation list for performance).

### Revoke every token on your account

```bash
coduck logout --all
```

Use this if you think a token might have been exposed. Your web session is untouched.

### Sign out from just this machine

```bash
coduck logout
```

Revokes only the current device's token and clears `~/.coduck/credentials.json`. Other devices keep working.

## Where your credentials live

```
~/.coduck/
└── credentials.json   (mode 0600)
```

The file contains your token, the API URL, your user ID, and your email. **Don't share it.** Anyone with this file has full account access until the token expires or you revoke it.

If you accidentally print or share it, run `coduck logout --all` immediately and `coduck login` to issue a fresh token.

## Inspecting the current token

```bash
coduck token status         # plan + credits, no token printed
coduck whoami               # who you're signed in as
coduck token show --confirm # actually print the token (refuses without --confirm)
```

The `--confirm` requirement on `show` is intentional: by default it refuses to leak the token to stdout, where it could end up in shell history or someone else's screen.

## For CI / GitHub Actions

`npm login` doesn't work in CI. The token-based flow is what you want anyway:

1. Run `coduck login` once on your local machine.
2. `cat ~/.coduck/credentials.json` — copy the `token` field.
3. Add it to your CI secrets as `CODUCK_TOKEN`.
4. In CI:

```yaml
- run: npm install -g @coduckai/cli
- run: |
    mkdir -p ~/.coduck
    cat > ~/.coduck/credentials.json <<EOF
    {"apiUrl":"https://api.coduck.ai","token":"$CODUCK_TOKEN","savedAt":"$(date -Iseconds)"}
    EOF
  env:
    CODUCK_TOKEN: ${{ secrets.CODUCK_TOKEN }}
- run: coduck deploy --no-input --json
```

Treat that token as long-lived (rotate it periodically; the sliding extension only kicks in on actual API use).

## What the CLI cannot do

Even with a valid token, the CLI is **scoped to your account only**. It cannot:

- See projects belonging to other CoDuck users
- Read the AI agent's system prompt or tool definitions
- Access the underlying database directly with a raw connection string
- Touch other containers or the host

These are enforced server-side, not by the CLI. A stolen token gives someone access to *your* projects until you revoke it — nothing else.

## Common failures

- **"login denied in the browser"** — you clicked Deny instead of Approve, or someone else did. Run `coduck login` again.
- **"login code expired"** — the 10-minute window ran out. Run `coduck login` again.
- **"unauthorized" on any command** — your token expired or was revoked. Run `coduck login`.

## Next

You're authenticated. Next: [import an existing project](/docs/projects/create-existing) or [generate a new one](/docs/getting-started).
