# Authentication for existing accounts

> How the Revdoku CLI and AI agents sign in to an existing account with OAuth and email codes.

API requests go to `https://api.revdoku.com`. Every path starts with `/v1`, for
example `https://api.revdoku.com/v1/buckets`. OAuth endpoints (paths that
start with `/oauth/`) use `https://app.revdoku.com`.

Most REST clients use an API key from **Account → Access**. Send it as
`Authorization: Bearer YOUR_API_KEY`. For a new account, use [browser signup](https://app.revdoku.com/users/sign_up).
Hosted MCP setup is documented in the [MCP guide](/mcp).

| Method | Path | Purpose |
| --- | --- | --- |
| `POST` | `/v1/auth/sign_in_code` | Request an email verification code without revealing whether the email has a Revdoku account. Existing-user sign-in only; use browser signup for a new identity. |
| `POST` | `/v1/auth/sign_in_code/verify` | Verify the email code and create an API key when the code is valid. |
| `POST` | `/v1/auth/grant/exchange` | Exchange a one-time connection token from the dashboard for an API key. |
| `POST` | `/v1/auth/dashboard_link` | Return a stable dashboard URL (normal sign-in is required). |
| `POST` | `/oauth/device_authorization` | Start OAuth device authorization for local CLI/agent clients. |
| `GET` / `POST` | `/oauth/device` | Browser page where the user enters/approves a device code. |
| `POST` | `/oauth/token` | Exchange OAuth authorization codes, device codes, or refresh tokens. |

## OAuth Device Authorization

Local CLI/device-code flow:

```http
POST /oauth/register
Content-Type: application/json

{
  "client_name": "Codex on laptop",
  "redirect_uris": [],
  "grant_types": [
    "urn:ietf:params:oauth:grant-type:device_code",
    "refresh_token"
  ],
  "response_types": [],
  "token_endpoint_auth_method": "none"
}

POST /oauth/device_authorization
Content-Type: application/json

{
  "client_id": "mcp_client_...",
  "scope": "revdoku:mcp",
  "resource": "https://mcp.revdoku.com"
}
```

1. Open the returned browser link and show the Connection ID to the human.
2. The human checks the same ID in Revdoku and selects **Connect**.
3. Poll the token endpoint until approval or expiry.
4. Store the returned credential privately. Permissions can be reduced in **Account → Access**.

| Field | Purpose |
| --- | --- |
| `verification_uri_complete` | Browser approval link. |
| `user_code` | Connection ID for visual confirmation; never request it in chat. |
| `device_code` | Private code used while polling the token endpoint. |
| `interval` | Minimum delay between polls. |
| `revdoku_api_key` | Revdoku extension returned after approval for local REST tooling. |



Local agents should prefer OAuth device authorization over email-code login. The
client registers with grant type
`urn:ietf:params:oauth:grant-type:device_code`, calls
`POST /oauth/device_authorization`, shows the returned `verification_uri_complete`
and presents `user_code` as a **Connection ID**, then polls `POST /oauth/token`.
The user confirms the matching Connection ID in the browser.

Pending poll responses use standard device-flow errors:

| Error | Meaning |
| --- | --- |
| `authorization_pending` | User has not approved yet; wait `interval` seconds and poll again. |
| `slow_down` | Increase the polling interval. |
| `access_denied` | User denied the browser prompt. |
| `expired_token` | Device code expired; start again. |

Successful device-code token responses include normal OAuth fields plus
`revdoku_api_key`, a durable `revdoku_...` key for local REST API clients.
The browser approval screen defaults to selected buckets and `bucket_read` when
the client does not request a scope. Choose the buckets and permission on that
screen. Selecting all existing buckets keeps a fixed selection; **All current and
future buckets** is a separate choice. Read access supports message/file reads;
provisioning new buckets requires account-wide `bucket_admin`.

## Permission scopes

| Scope | Meaning |
| --- | --- |
| `bucket_read` | List and read allowed bucket files only. |
| `bucket_write` | Create and update allowed bucket files. |
| `bucket_admin` | Create, update, and manage allowed buckets. |

| Input | Purpose |
| --- | --- |
| `permission_scope` | Choose one of the permissions above; bound to consent. |
| OAuth `scope` | Protocol scope: `revdoku:mcp`, optionally `offline_access`. |

OAuth/device requests and dashboard one-time connection prompts default to
`bucket_read` when permission is omitted. Legacy email-code login and raw API-key creation default to `bucket_admin`;
request an explicit permission for those flows. Invalid values are rejected. Account → Access defaults
new keys to selected buckets and read permission.

## POST /v1/auth/sign_in_code

The request returns the same success shape for every syntactically valid email.
It does not reveal whether an account exists, is locked, or has two-factor authentication.

| Response field | Purpose |
| --- | --- |
| `fallback_url` | Browser sign-in link if no code arrives or email-code verification fails. |
| `hint` | Explanation of the fallback. |

Use browser sign-in when required. Never ask for passwords, TOTP codes or backup
codes through an AI chat.

```json
{
  "email": "person@example.com"
}
```

## POST /v1/auth/sign_in_code/verify

Verify a privately entered email code for an eligible account.

| Result | Behavior |
| --- | --- |
| Success | Returns a Revdoku API key. Store it privately. |
| `INVALID_CODE` | Verification failed; also covers locked accounts or accounts requiring two-factor authentication. |
| `error.details.fallback_url` | Browser sign-in link. |
| `error.details.hint` | Recovery explanation. |

Use browser device sign-in after verification fails; do not repeatedly submit codes.

```json
{
  "email": "person@example.com",
  "code": "123456",
  "label": "Codex on laptop",
  "permission_scope": "bucket_admin",
  "bucket_access": "all"
}
```

For selected-mailbox access, use:

```json
{
  "bucket_access": "selected",
  "bucket_ids": [
    "bkt_..."
  ],
  "bucket_permissions": {
    "bkt_...": "write"
  }
}
```

## POST /v1/auth/dashboard_link

Requires `Authorization`. This endpoint returns a stable internal
dashboard URL and never exchanges an API key for a browser session. The user
signs in normally if the browser has no active Revdoku session.

```json
{
  "redirect_path": "/account/access"
}
```

Common `redirect_path` values:

| Path | Destination |
| --- | --- |
| `/buckets` | Mailbox dashboard. |
| `/account/access` | Members, agents, and API keys. |

## Activity attribution

Optional: identify your client in activity logs. These headers are not required
to create a bucket or read email.

```http
User-Agent: MyRevdokuClient/1.0 (codex)
X-Revdoku-Agent: codex
X-Revdoku-Agent-Client: chatgpt
X-Revdoku-Agent-Version: 1.0.0
X-Revdoku-Agent-Run-Id: run_20260520_001
X-Revdoku-Agent-Project: support-mailbox
X-Revdoku-Agent-Task: check-new-messages
```


---

published with [Revdoku](https://revdoku.com)
