| 1 | # Sequoia Server |
| 2 | |
| 3 | Self-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 |
| 10 | cp .env.example .env |
| 11 | # Edit .env — at minimum set CLIENT_URL to your public URL |
| 12 | docker compose up |
| 13 | ``` |
| 14 | |
| 15 | ### Local development |
| 16 | |
| 17 | Requires [Bun](https://bun.sh) and a running Redis instance. |
| 18 | |
| 19 | ```bash |
| 20 | bun install |
| 21 | CLIENT_URL=http://localhost:3000 bun run dev |
| 22 | ``` |
| 23 | |
| 24 | ## How it works |
| 25 | |
| 26 | 1. A user visits `/subscribe?publicationUri=at://...` and enters their Bluesky handle |
| 27 | 2. The server initiates an AT Protocol OAuth flow — the user authorizes on Bluesky |
| 28 | 3. After callback, the server creates a `site.standard.graph.subscription` record in the user's repo |
| 29 | 4. 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 | |
| 57 | The 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 | |
| 73 | For 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 | |
| 77 | The included `Dockerfile` produces a minimal image: |
| 78 | |
| 79 | ```bash |
| 80 | docker build -t sequoia-server . |
| 81 | docker 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 | |
| 87 | Or use `docker-compose.yml` which bundles Redis: |
| 88 | |
| 89 | ```bash |
| 90 | docker compose up -d |
| 91 | ``` |
| 92 | |
| 93 | Place behind a reverse proxy (Caddy, nginx, Traefik) for TLS. |