forked from
stevedylan.dev/sequoia
A CLI for publishing standard.site documents to ATProto
1# Sequoia Server
2
3Self-hostable AT Protocol OAuth and subscription server. Handles Bluesky login and manages `site.standard.graph.subscription` records on behalf of users. Built with Bun, Hono, and Redis.
4
5## Quickstart
6
7### Docker (recommended)
8
9```bash
10cp .env.example .env
11# Edit .env — at minimum set CLIENT_URL to your public URL
12docker compose up
13```
14
15### Local development
16
17Requires [Bun](https://bun.sh) and a running Redis instance.
18
19```bash
20bun install
21CLIENT_URL=http://localhost:3000 bun run dev
22```
23
24## How it works
25
261. A user visits `/subscribe?publicationUri=at://...` and enters their Bluesky handle
272. The server initiates an AT Protocol OAuth flow — the user authorizes on Bluesky
283. After callback, the server creates a `site.standard.graph.subscription` record in the user's repo
294. The [sequoia-subscribe](https://github.com/standard-schema/sequoia) web component can point to this server for the full flow
30
31### Routes
32
33| Route | Method | Description |
34|-------|--------|-------------|
35| `/api/health` | GET | Health check |
36| `/oauth/client-metadata.json` | GET | OAuth client metadata |
37| `/oauth/login?handle=` | GET | Start OAuth flow |
38| `/oauth/callback` | GET | OAuth callback |
39| `/oauth/logout` | POST | Revoke session |
40| `/oauth/status` | GET | Check auth status |
41| `/subscribe` | GET | Subscribe page (HTML) |
42| `/subscribe` | POST | Subscribe via API (JSON) |
43| `/subscribe/check` | GET | Check subscription status |
44| `/subscribe/login` | POST | Handle form submission |
45
46## Configuration
47
48| Variable | Required | Default | Description |
49|----------|----------|---------|-------------|
50| `CLIENT_URL` | Yes | — | Public URL of this server (used for OAuth redirects) |
51| `CLIENT_NAME` | No | `Sequoia` | Name shown on Bluesky OAuth consent screen |
52| `PORT` | No | `3000` | Server port |
53| `REDIS_URL` | No | `redis://localhost:6379` | Redis connection URL |
54
55### Theming
56
57The subscribe pages use CSS custom properties that can be overridden via environment variables:
58
59| Variable | Default |
60|----------|---------|
61| `THEME_ACCENT_COLOR` | `#3A5A40` |
62| `THEME_BG_COLOR` | `#F5F3EF` |
63| `THEME_FG_COLOR` | `#2C2C2C` |
64| `THEME_BORDER_COLOR` | `#D5D1C8` |
65| `THEME_ERROR_COLOR` | `#8B3A3A` |
66| `THEME_BORDER_RADIUS` | `6px` |
67| `THEME_FONT_FAMILY` | `system-ui, sans-serif` |
68| `THEME_DARK_BG_COLOR` | `#1A1A1A` |
69| `THEME_DARK_FG_COLOR` | `#E5E5E5` |
70| `THEME_DARK_BORDER_COLOR` | `#3A3A3A` |
71| `THEME_DARK_ERROR_COLOR` | `#E57373` |
72
73For full control, set `THEME_CSS_PATH` to a CSS file path (e.g. `/app/theme.css` mounted via Docker volume). It will be injected after the default styles.
74
75## Deployment
76
77The included `Dockerfile` produces a minimal image:
78
79```bash
80docker build -t sequoia-server .
81docker run -p 3000:3000 \
82 -e CLIENT_URL=https://your-domain.com \
83 -e REDIS_URL=redis://your-redis:6379 \
84 sequoia-server
85```
86
87Or use `docker-compose.yml` which bundles Redis:
88
89```bash
90docker compose up -d
91```
92
93Place behind a reverse proxy (Caddy, nginx, Traefik) for TLS.