Skip to main content

Keep a Matrix (Synapse) homeserver in sync with Authentik and onboard new users.

Project description

Onbot

A bot that keeps a Matrix (Synapse) homeserver continuously in sync with an Authentik identity provider and onboards every new user into the right rooms with a friendly welcome. Authentik is the source of truth; Matrix mirrors it (group → room, group membership → room membership, power levels), and new users get guided in with a 1:1 welcome DM.

Onbot targets Matrix 2.0: it assumes a Matrix Authentication Service (MAS) deployment with Authentik as an upstream identity provider, uses authenticated media, and drives the Client-Server and admin APIs over a single async HTTP client (no matrix-nio).

See GOALS.md for intent, BATTLE_PLAN.md for the build plan, and docs/adr/ for the architecture decisions.

⚠️ Release blocker (maintainer): the Phase 1 security items are not done — leaked credentials in git history still need rotating and the history scrubbing (BATTLE_PLAN.md §5 Phase 1). Do not publish an image or tag a release until those are complete. The packaging below is ready; the security hand-off is the gate.


How it works — the MAS auth topology

The auth chain is Matrix client → MAS → Authentik (ADR-0006):

                   logs in via                      upstream IdP
   Matrix client ───────────────▶  MAS  ◀───────────────────────  Authentik
        ▲                           │  (provisions Matrix accounts   (source of truth:
        │                           │   on first login)               users & groups)
        │ welcome DM,               │
        │ room membership      ┌────┴─────┐
        └──────────────────────│  Onbot   │── reads users/groups ──▶ Authentik API
                               └────┬─────┘
                                    └── Synapse Admin API + CS API ──▶ Synapse  ◀─ MAS

Consequences that shape how you configure Onbot:

  • Onbot does not create accounts. MAS auto-provisions a Matrix account the first time a user logs in through Authentik. Onbot's job is projection: turn Authentik groups into rooms, group membership into room membership, and group/role attributes into power levels — plus the quarantined offboarding lifecycle.
  • The MXID localpart contract is critical. Onbot computes a user's MXID (@<localpart>:server_name) from an Authentik attribute, and it must match the localpart template MAS uses when it provisions accounts from the same Authentik claim. Set sync_authentik_users_with_matrix_rooms.authentik_username_mapping_attribute to agree with MAS — get it wrong and Onbot's computed MXIDs won't match the real accounts, so nobody gets added to rooms. (Verified by the integration suite's localpart-contract test.)
  • Lifecycle enforcement requires MAS. When Authentik disables a user, MAS blocks new logins but existing Matrix sessions keep working, and the Synapse admin API cannot revoke a MAS-issued session — only MAS can (ADR-0005, §7 Q1, proven empirically). So to actually offboard a disabled user you must configure the mas_admin block. Without it, offboarding is a no-op against live sessions (it silently fails to revoke).

Configuration

Configuration is a single YAML file validated by a pydantic-settings model (onbot/config.py). Every setting can also be supplied (or overridden) via an environment variable: prefix ONBOT_, nest with __. E.g. ONBOT_SYNAPSE_SERVER__BOT_ACCESS_TOKEN=syt_….

  • Full reference: docs/CONFIG_REFERENCE.md — every field, its type, default, description and ONBOT_* env-var name.
  • Annotated template: config.example.yml — a commented, fillable YAML template. Copy it to config.yml and fill in the required values.

Both are generated from the model (with psyplus) and kept in sync by CI — regenerate after editing onbot/config.py:

pdm run gen-config-docs      # rewrite docs/CONFIG_REFERENCE.md + config.example.yml
pdm run check-config-docs    # fail if they drift from the model (runs in CI)

🔐 Never commit a real config. config*.yml is gitignored (only config.example.yml is tracked) and the Docker image carries no secrets — provide config at runtime.

Bot credentials (pick one)

Onbot authenticates to Synapse as a bot user. Under MAS, choose one of:

Option Field When
Compatibility token synapse_server.bot_access_token Near-term. Issue with mas-cli manage issue-compatibility-token. Provide the bare token.
OAuth2 client-credentials synapse_server.oauth2 Forward-looking. The bot is a confidential MAS client and refreshes tokens automatically.

Provide exactly one. The same identity drives both the Synapse Admin API and the Client-Server API.

Minimal config.yml

synapse_server:
  server_name: company.org                  # your Matrix domain (the part after the ':')
  server_url: https://internal.matrix       # how the bot reaches Synapse (internal URL is fine)
  bot_user_id: "@welcome-bot:company.org"
  bot_access_token: syt_REPLACE_ME          # or use an `oauth2:` block instead

authentik_server:
  url: https://authentik.company.org/
  api_key: REPLACE_ME                        # Authentik API token

# Required to enforce offboarding under MAS (omit on non-MAS deployments):
mas_admin:
  url: https://auth.company.org              # the MAS base URL
  client_id: REPLACE_ME                      # a MAS admin client (in policy.data.admin_clients)
  client_secret: REPLACE_ME

sync_authentik_users_with_matrix_rooms:
  authentik_username_mapping_attribute: username   # MUST agree with MAS's localpart template

See config.example.yml for everything else (room mapping rules, power levels, welcome messages, the dry-run lifecycle defaults, ignore lists, …).


Run with Docker

The published image runs as a non-root user and ships only runtime dependencies (no crypto stack — the bot operates outside encrypted rooms, ADR-0009).

docker run --rm \
  -v "$PWD/config.yml:/config/config.yml:ro" \
  ghcr.io/dzd-ev-diabetes-research/matrix-synapse-authentik-onbaording-bot:latest

The image defaults to ONBOT_CONFIG_FILE_PATH=/config/config.yml and the run command. It has a built-in HEALTHCHECK that calls onbot healthcheck (see below).

docker-compose

services:
  onbot:
    image: ghcr.io/dzd-ev-diabetes-research/matrix-synapse-authentik-onbaording-bot:latest
    restart: unless-stopped
    volumes:
      - ./config.yml:/config/config.yml:ro
    # Or skip the file and supply everything via env (no secrets on disk):
    # environment:
    #   ONBOT_SYNAPSE_SERVER__SERVER_NAME: company.org
    #   ONBOT_SYNAPSE_SERVER__BOT_ACCESS_TOKEN: ${ONBOT_BOT_TOKEN}

CLI commands

onbot run               # long-running service: reconcile loop + event-driven onboarding (default)
onbot reconcile-once    # one idempotent reconcile pass, then exit
onbot generate-config   # print a minimal config template (use config.example.yml for the rich one)
onbot healthcheck       # probe Synapse/Authentik/MAS with the real credentials; exit 0 healthy, 1 not

onbot healthcheck is what the container's HEALTHCHECK runs: it issues one authenticated request to the Matrix CS API (/whoami), the Synapse admin API, the Authentik API, and — when mas_admin is configured — the MAS admin API, and exits non-zero if any is unreachable or rejects the credentials.


Develop

Requires Python 3.14 and PDM.

pdm install                 # create the venv and install deps (incl. dev + docs)
pdm run pre-commit install  # enable lint + secret-scan hooks

Run & test

pdm run onbot --help
pdm run onbot reconcile-once

pdm run pytest -m "not integration"     # fast unit + contract suite
pdm run pytest                          # full suite incl. live Synapse+MAS+Authentik (needs Docker)
pdm run ruff check .                     # lint
pdm run ruff format --check .            # formatting
pdm run mypy onbot                       # type check

The run_*.sh helper scripts at the repo root wrap the same PDM commands.

Build the image locally

docker build -t onbot:dev .
docker run --rm onbot:dev --help

Troubleshooting

Symptom Likely cause
Users never get added to rooms The MXID localpart contract is broken — authentik_username_mapping_attribute doesn't match MAS's localpart template, so computed MXIDs don't exist.
Disabled users keep their Matrix access mas_admin is not configured (the Synapse admin API can't revoke a MAS session), or lifecycle dry_run is still true (the default).
Nothing destructive ever happens Expected by default — the lifecycle is quarantined (dry_run: true); it only logs to the onbot.lifecycle.audit channel until you opt in.
Welcome DM send fails with a 500 The bot device isn't registered yet — Onbot registers it on startup (ensure_device_registered); check startup logs.
healthcheck reports a dependency FAIL Read the per-dependency log line; it distinguishes unreachable from auth-rejected. The matrix-cs line also flags a token/bot_user_id mismatch.
Sliding sync unavailable The homeserver doesn't advertise MSC4186; Onbot falls back to the reconciler signal path automatically.

Releasing

Versioned images are published to GHCR by the release workflow when a v* tag is pushed. See CHANGELOG.md and the workflow's header comment for the tag/version flow. (Blocked on the Phase 1 security hand-off — see the note at the top.)

License

MIT — see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

onbot-0.1.0.dev0.tar.gz (92.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

onbot-0.1.0.dev0-py3-none-any.whl (66.1 kB view details)

Uploaded Python 3

File details

Details for the file onbot-0.1.0.dev0.tar.gz.

File metadata

  • Download URL: onbot-0.1.0.dev0.tar.gz
  • Upload date:
  • Size: 92.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for onbot-0.1.0.dev0.tar.gz
Algorithm Hash digest
SHA256 5b6d2dcb799ed132d536c856a28a02ee5e1f459f3053e735034db25691353737
MD5 a204cacb9cc263a4df49248ba9ea75f3
BLAKE2b-256 86d0f216a06b79b99036e71cf373ac66629738d3b4ea4ce3ca57dace9748fe3d

See more details on using hashes here.

File details

Details for the file onbot-0.1.0.dev0-py3-none-any.whl.

File metadata

  • Download URL: onbot-0.1.0.dev0-py3-none-any.whl
  • Upload date:
  • Size: 66.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for onbot-0.1.0.dev0-py3-none-any.whl
Algorithm Hash digest
SHA256 6024de25aea624fbd6d2793ad2c8fe191b94bc0285a0bf3ebfb15a82feb01cad
MD5 ffc35bb54d9dcfc35959274d56970cc8
BLAKE2b-256 3f65f5ef3aae6284089711989309306c1a3c8e2300a23ba238674a3bc16da4e8

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page