# Visitor Auth

Canonical: https://auggy.dev/docs/augment-visitor-auth
Status: Published
Package: auggy 0.5.0

Verify email ownership and restore one recognized public identity across browser sessions.

## Recognize a returning visitor

**What it enables:** Turn an anonymous browser visitor into a durable `public` + `recognized` identity after they prove control of an email address.

- **Status:** Stable
- **Availability:** Add with ``auggy augment add` visitorAuth`; run setup before production email delivery.
- **Contributes:** `request_auth tool`, `3 HTTP routes`, `identity lookup`, `SQLite store`, `admin controls`

> **Note: Recognition is not elevation**
>
> Verification proves control of an email address. The caller remains at `public` trust; it does not grant `creator`, `agent`, application roles, or permission to consequential tools.

## Install locally, then configure delivery

**Recommended setup**

```bash
auggy augment add layeredMemory visitorAuth
auggy augment setup visitorAuth
auggy doctor --cloud
```

**augments/visitorAuth/augment.yaml**

```yaml
type: visitorAuth
config:
  publicUrl: ${AUGGY_PUBLIC_URL}
  dbPath: ./data/visitor-auth.db
  agentMail:
    transport: agentmail
    apiKey: ${AGENTMAIL_API_KEY}
    inboxId: ${AGENTMAIL_INBOX_ID}
    subjectPrefix: "[Verify] "
  signingKey: ${VISITOR_SIGNING_KEY}
  rateLimit:
    perHour: 1
    perDay: 3
  reverifyAfterDays: 90
  tokenTtlMinutes: 15
  layeredMemoryDbPath: ./data/memory.db
```

A fresh local install uses `agentMail.transport: console` and prints verification links to the agent process. `auggy augment setup visitorAuth` configures AgentMail for production. Cloud preflight rejects console delivery unless you explicitly accept links appearing in service logs.

## Choose the model or application path

### Let the agent request verification

**Conversation.** Use when the visitor asks to be remembered during an active turn. The augment requires the email to appear in recent visitor messages.

**request_auth input**

```json
{
  "method": "email",
  "email": "sam@example.com"
}
```

### Submit a sign-in form directly

**Application.** Use the deterministic route when a frontend owns the form. This path does not migrate an existing anonymous chat identity.

**Request a link**

```bash
curl -X POST "$AUGGY_URL/visitor-auth/request" \
  -H 'content-type: application/json' \
  --data '{"email":"sam@example.com"}'
```

The verification page uses `GET` to display confirmation without consuming the token. Its `POST` consumes the token atomically and writes the signed visitor token to same-origin browser storage.

## Runtime surfaces

| Surface | Behavior |
| --- | --- |
| ``request_auth`` | Sends a magic link from the active anonymous turn after validating recent-message email evidence and per-email rate limits. |
| `POST /visitor-auth/request` | Deterministic public form endpoint; issues a link without binding arbitrary anonymous chat history. |
| `GET /visitor-auth/verify` | Renders the confirmation page without consuming the one-time token. |
| `POST /visitor-auth/verify` | Consumes the token, records verification, returns a signed visitor token, and can migrate current-turn memory when safely bound. |
| Route auth | Enables `visitor.optional` and `visitor.required` for augment routes through Web Transport. |
| SQLite | Stores issued tokens, recognized visitors, revocations, and first-verification notification state. |
| Admin and CLI | Lists and revokes recognized visitors through Console and `auggy visitors`. |

## Production boundaries

- A recognized visitor is still `public`. Add route/tool authorization requirements for application roles or grants.
- The model tool requires the email to appear in one of the visitor's recent messages; the deterministic route instead relies on body validation and per-email throttling.
- Identity continuity depends on the signed `x-visitor-token` and same-origin browser storage. Rotating `VISITOR_SIGNING_KEY` invalidates existing tokens.
- SQLite must live on durable storage. **Railway** persists `./data/visitor-auth.db`; use one process for the local database.
- Rate-limit evidence is process-local and resets on restart. Revocation is durable and denylisted rather than deleting the verification record.

## Verify identity and trust separately

1. Start locally, ask an anonymous visitor to verify an email they typed, and open the printed confirmation link.
2. Submit the confirmation page and confirm `auggy visitors <agent>` lists a stable `vis_...` identity.
3. Start a new same-origin browser session and confirm the recognized identity is restored.
4. With Layered Memory installed, confirm remembered context follows that recognized visitor rather than a display name.
5. Call a creator-only operation and confirm email verification alone does not authorize it.

## Related

- [Delegated authorization](https://auggy.dev/docs/delegated-authorization/markdown)
- [Layered Memory](https://auggy.dev/docs/augment-layered-memory/markdown)
- [Connect an application](https://auggy.dev/docs/connect-application/markdown)
- [Security](https://auggy.dev/docs/security/markdown)
- [Deploy and verify](https://auggy.dev/docs/deploy/markdown)