# Identity and Authentication

> **Platform Reference** — describes implemented, production behavior.

Acequia automatically generates and manages identity for every browser that connects. This document explains the identity model in layers — start with what you need, skip what you don't.

**If you're just getting started**, all you need to know is:

```javascript
await acequia.acequiaReady()  // initializes identity, keys, and service worker
const instanceId = acequia.getInstanceId()
group.registerRoute(`/${instanceId}/status`, handler)
```

`instanceId` uniquely identifies this browser tab. Use it to prefix your routes so they don't collide when multiple instances of your app are in the same group. That's enough to build a working app.

Read on when you need to understand *who* is using your app, not just *which tab*.

---

## Three Identifiers

Every Acequia client has three IDs, each with a different scope and lifetime:

| ID | Scope | Lifetime | Storage | Example |
|----|-------|----------|---------|---------|
| `userId` | User (cross-device) | Permanent | IndexedDB | `clx7k9m2a0001...` |
| `deviceId` | Single browser profile | Permanent | IndexedDB | `cm3p8f5x20000...` |
| `instanceId` | Single tab/window | Session (survives reload) | sessionStorage | `cm4r2j8k10003...` |

### When you need each one

**`instanceId`** — Almost always. This is the ID you use to prefix routes and distinguish your tab from other tabs running the same app. Available immediately after `acequiaReady()`.

```javascript
const instanceId = acequia.getInstanceId()
group.registerRoute(`/${instanceId}/camera/shot`, shotHandler)
```

**`deviceId`** — When you need to identify *this browser* across sessions. Useful for device-specific settings, remembering which device last uploaded a file, or distinguishing a user's laptop from their phone.

```javascript
const deviceId = acequia.getDeviceId()
await fetch(`/groups/mygroup/${peerId}/register-device`, {
    method: 'POST',
    body: JSON.stringify({ deviceId, capabilities: ['camera'] }),
})
```

**`userId`** — When you need to identify *the person*, regardless of which device they're on. Useful for user-facing features: "who sent this message?", "who owns this file?", access control decisions.

```javascript
const userId = acequia.getUserId()
// Same userId on laptop and phone after device linking
```

### How IDs relate

A single **user** can have multiple **devices** (laptop, phone, work computer). Each device can have multiple **instances** (browser tabs). The hierarchy:

```
userId (one per person)
  └─ deviceId (one per browser profile)
       └─ instanceId (one per tab, ephemeral)
```

On first run, `acequiaReady()` generates both `userId` and `deviceId` and stores them in IndexedDB. They persist across page reloads, browser restarts, and tab closures. `instanceId` is generated per session and stored in `sessionStorage` — it survives page reloads but not tab closure.

When a user links a second device (via the device-link flow), both devices share the same `userId` but have different `deviceId` values.

---

## Human-Readable Names

Opaque IDs are fine for routing, but users and developers need readable labels. Acequia provides three naming layers that parallel the three IDs:

| Name | Scope | Example | Getter |
|------|-------|---------|--------|
| **handle** | User (cross-device) | `@joshua` | `acequia.getHandle()` |
| **deviceName** | Single device | `silver-falcon` | `acequia.getDeviceName()` |
| **instanceName** | Single tab/session | `tab-k7x2` | `acequia.getInstanceName()` |

These compose naturally for unambiguous identification: `@joshua / silver-falcon / tab-k7x2`.

### Handle

A handle is a human-readable username (e.g., `@joshua`). It's assigned during user registration or device linking and stored both server-side and in IndexedDB.

- Set during the invite-accept or device-link flow
- Validated: `/^[a-z][a-z0-9_-]{2,29}$/`
- Server-authoritative — the client caches it, but the server is the source of truth
- Available via `acequia.getHandle()` after `acequiaReady()`

### Device Name

An auto-generated adjective-noun pair (e.g., `silver-falcon`) that identifies a specific browser. Generated on first run, stored in IndexedDB and registered server-side.

- Can be renamed via the dashboard
- Helps users distinguish "my laptop" from "my phone" without remembering opaque IDs

### Instance Name

An ephemeral per-session label (e.g., `tab-k7x2`). Stored in `sessionStorage`, regenerated when a new tab opens.

- Useful for debugging (which tab produced this log line?)
- Can appear in peer lists alongside device name

---

## Cryptographic Keys

Each device generates **two PS256 key pairs** on first run:

| Key pair | Purpose | Storage |
|----------|---------|---------|
| **Device keys** | Signing device-level tokens | IndexedDB |
| **User keys** | Per-device user identity, device linking | IndexedDB |

Public keys from both pairs are registered with the auth server during device registration. The private keys never leave the browser.

**Most apps don't need to interact with keys directly.** Token creation and signing happen automatically when you use Acequia's auth flows (invitations, device linking, token creation). The key-related getters exist for advanced use cases like building custom delegation chains.

```javascript
// Advanced — most apps won't need this
const { publicKey, privateKey } = acequia.getKeys()       // device keys
const { publicKey, privateKey } = acequia.getUserKeys()    // user keys
```

---

## When Authentication Matters

### Single-user, local development

Identity is automatic. `acequiaReady()` generates IDs and keys, and the server recognizes the device. No auth code needed in your app.

### Multi-user apps

When other people use your app, they need accounts. The flow:

1. Owner creates an **invitation** (via dashboard or API)
2. New user accepts the invite, choosing a handle and registering their public keys
3. The server issues them a role (`viewer`, `editor`, `owner`)
4. Their browser automatically creates and manages tokens

App code doesn't handle any of this — it happens through the invitation pages and the Acequia auth system.

### Scoped access and delegation

When you need fine-grained access control — granting write access to specific paths, creating time-limited tokens, or delegating authority to other users — you're working with **chain tokens** and the delegation system.

This is covered in:
- [User Authentication](user-authentication.md) — JWT architecture, three token types, verification flow
- [Capability Delegation](../projects/capability-delegation.md) — Content-addressable chain tokens, revocation, scope narrowing

---

## Token Types (Overview)

Acequia uses three token types, detected by JWT claim inspection:

| Token type | Detected by | Use case | Status |
|------------|-------------|----------|--------|
| **Chain token** | `parent` claim present | Delegated access with scoped paths and expiry | Primary mechanism |
| **User token** | `kid` claim, no `parent` | Direct user auth verified against registered public key | Active |
| **Device token** | No `kid`, no `parent` | Legacy device auth | Deprecated |

**Chain tokens** are the primary auth mechanism. A chain token's `parent` claim points to its parent token's hash, forming a linked list that traces back to a registered user. Each link in the chain can narrow scope (fewer paths, shorter expiry) but never widen it.

For the full JWT structure, verification algorithm, and chain mechanics, see [User Authentication](user-authentication.md).

---

## API Summary

All identity APIs are available after `await acequia.acequiaReady()`:

| Method | Returns | Description |
|--------|---------|-------------|
| `getInstanceId()` | `string` | Per-session tab identifier |
| `getDeviceId()` | `string` | Persistent device identifier |
| `getUserId()` | `string` | Persistent user identifier |
| `getHandle()` | `string` | User's human-readable handle |
| `getDeviceName()` | `string` | Device display name |
| `getInstanceName()` | `string` | Session display name |
| `getKeys()` | `{ publicKey, privateKey }` | Device crypto key pair (advanced) |
| `getUserKeys()` | `{ publicKey, privateKey }` | User crypto key pair (advanced) |

See [API Reference](api-reference.md) for the complete API surface.
