This repository has no description
README.md

Deploying a Matey homeserver (Tuwunel + broker) #

This directory deploys the spec's Strategy A on Tuwunel (README §5.2, Appendix B): Tuwunel's built-in next-generation OIDC server delegates user authentication to the Matey broker, which authenticates users via AT Protocol OAuth and asserts their DID back to Tuwunel. No MAS is involved.

Matrix client ──OAuth──▶ Tuwunel (own OIDC AS) ──OIDC──▶ matey-broker ──atproto OAuth──▶ user's authserver/PDS
                                                              │
                                                   sub = DID, preferred_username,
                                                   name, picture claims

Prerequisites #

  • A host running Docker with ports 80, 443, and 8448 reachable.
  • Two DNS names pointing at it: the Matrix server name (e.g. matrix.example.org) and the broker host (e.g. matey-auth.example.org). Caddy obtains TLS certificates automatically.
  • The Matrix server name is permanent: changing it later means wiping the Tuwunel database.

Steps #

cd deploy
cp .env.example .env
$EDITOR .env                     # hosts + a fresh BROKER_RP_CLIENT_SECRET
docker compose up -d --build

Smoke checks:

curl https://$AUTH_HOST/.well-known/openid-configuration   # broker OIDC discovery
curl https://$AUTH_HOST/atproto/client-metadata.json       # broker as atproto client
curl https://$MATRIX_HOST/_matrix/client/versions          # Tuwunel C–S API
curl https://$MATRIX_HOST/_matrix/client/v1/auth_metadata  # next-gen auth advertised

Then point the example app (counter/) or any next-gen-auth Matrix client at the server. Logging in walks: Matrix client → Tuwunel authorize → "AT Protocol" provider → broker (handle form) → your PDS → back, with an account provisioned on first login.

What to know about this topology #

  • The broker always shows its handle form. Tuwunel does not forward login_hint to upstream providers (spec §7 item 11), so even when the Matey client resolved the user's DID already, the user types their handle once more at the broker. MAS deployments forward the hint and skip the form.

  • Localparts. The broker emits preferred_username already shaped (did.plc.… by default, MATEY_LOCALPART_STYLE=handle for vanity names); Tuwunel derives the localpart from it. Do not enable trusted or custom userid_claims on the provider unless you know what you're doing — on_conflict-style auto-linking is an account-takeover vector (spec §8).

  • Linking an existing Tuwunel account (spec §5.4.2) uses the admin room:

    !admin query oauth associate <provider_id> @alice:matrix.example.org \
        --claim sub=did:plc:…
    

    Pending approvals are held in memory; the user must log in via the AT provider before the next server restart. (On MAS this is self-serve via the account UI instead.)

  • The DID profile field. The reference broker asserts identity claims but homeserver-side writing of com.berjon.matey.did (spec §3.3.1 server-managed mode) is not yet wired into Tuwunel provisioning; the example app writes the field from the client after login, which default Tuwunel permits. Track this as spec §7 item — a Tuwunel/MAS provisioning hook is the clean fix.

  • Legacy clients get AT login too: the same provider serves m.login.sso, so Element-classic-era clients can also authenticate via atproto (without any Matey mooring logic).

  • Broker state is in-memory (in-flight logins only; no user data). A restart aborts in-flight sign-ins, nothing else. Keys persist in the broker-data volume.

Synapse + MAS route #

Prefer MAS semantics (login_hint forwarding, self-serve account linking, claims_imports templates)? Run Synapse + MAS instead and register the broker as a MAS upstream provider — the exact YAML is in the spec (README §5.2). The broker is identical in both topologies.

Local development (no domains, no TLS) #

The broker runs on plain HTTP with MATEY_DEV=1 (uses the atproto loopback client; only works against PDSes reachable from your machine, and the whole flow must stay on localhost). Combined with a local Tuwunel (TUWUNEL_ALLOW_REGISTRATION, plain HTTP listener) this gives a laptop-only stack:

cd broker
MATEY_DEV=1 MATEY_BROKER_CLIENT_ID=tuwunel MATEY_BROKER_CLIENT_SECRET=dev \
MATEY_BROKER_REDIRECT_URIS=http://localhost:8008/_matrix/client/unstable/login/sso/callback/tuwunel \
pnpm start

Real atproto authserver interactions require the broker to be reachable at a public HTTPS URL (atproto client metadata is fetched by the user's authserver), so end-to-end testing against real PDSes needs the full deployment or a tunnel.