Replace appservice auth with MAS OAuth 2.0 device grant

The appservice approach was wrong for a /sync bot: Synapse forbids
appservice-namespace users from /sync (sync.py raises NotImplementedError,
'we no longer support AS users using /sync'), so the bot received no events.

Authenticate instead via the MAS OAuth 2.0 device grant (RFC 8628):
- internal/bot/masauth.go: discover MAS endpoints from well-known+OIDC,
  dynamic client registration, device-code flow (prints approval URL once),
  persist rotating refresh token in data/mas_auth.json, refresh access token.
- internal/bot/client.go: obtain token via device grant, keep bot a NORMAL
  user (so /sync works), background refresher updates the live client, E2EE
  via cryptohelper on a fresh device.
- main.go: drop AS_TOKEN; remove registration.yaml.example; docs updated.

First run needs a one-time browser approval as the bot user; thereafter the
bot refreshes silently.
This commit is contained in:
prosolis
2026-07-03 15:40:26 -07:00
parent 48330be3d5
commit 20d1f92f97

View File

@@ -1,61 +0,0 @@
# GogoBee appservice registration — MAS-durable auth.
#
# Copy to registration.yaml, fill in the tokens, and register it with your
# homeserver. This replaces the old password login: the as_token is a Synapse-
# level trust relationship, so it never expires and is unaffected by Matrix
# Authentication Service (MAS) removing password login / UIA.
#
# ---------------------------------------------------------------------------
# 1. Generate two independent secrets (do NOT reuse the same value):
# openssl rand -hex 32 # -> as_token
# openssl rand -hex 32 # -> hs_token
#
# 2. Point Synapse at this file in homeserver.yaml:
# app_service_config_files:
# - /path/to/registration.yaml
#
# 3. Restart Synapse, then set AS_TOKEN in GogoBee's .env to the as_token below.
#
# MSC4190 device management (so the bot creates its E2EE device without UIA) is
# opted into per-appservice via the `io.element.msc4190: true` flag at the
# bottom of this file — there is NO homeserver-level flag for it in current
# Synapse. Works even with Matrix Authentication Service (MAS) delegation on:
# Synapse serves PUT /devices for appservice requests regardless of MAS.
# ---------------------------------------------------------------------------
# Unique identifier for this appservice.
id: gogobee
# The token GogoBee sends to the homeserver (Authorization: Bearer <as_token>).
# This is the value that goes in the bot's AS_TOKEN env var.
as_token: "CHANGE_ME_as_token_from_openssl_rand_hex_32"
# The token the homeserver would use to authenticate to the appservice's push
# endpoint. GogoBee uses /sync rather than the push (transaction) model, so it
# is not consumed by the bot — but Synapse still requires it to be set and
# distinct from as_token.
hs_token: "CHANGE_ME_hs_token_from_openssl_rand_hex_32"
# The bot's localpart. Its full user ID is @gogobee:<your-domain>, which must
# match BOT_USER_ID in .env.
sender_localpart: gogobee
# GogoBee uses /sync, not the transaction push API, so this URL is never called.
# Synapse requires the field; null disables push delivery.
url: null
# GogoBee only ever acts as its own @gogobee user. This namespace claims that
# single user ID. Adjust the domain to match your homeserver.
# The bot only needs to ACT AS @gogobee (which already exists), not exclusively
# own the namespace — so exclusive is false to avoid any conflict with the
# existing account.
namespaces:
users:
- exclusive: false
regex: "@gogobee:example\\.com"
aliases: []
rooms: []
# Required for the bot to manage its own E2EE device via MSC4190 (PUT /devices)
# instead of the UIA-gated login flow that MAS removes.
io.element.msc4190: true