Standalone Matrix CLI client: send messages, listen to rooms, and manage E2E encrypted communication
Project description
minimatrix
Standalone Matrix CLI client with E2E encryption. Send messages, listen to rooms, and list joined rooms — all from the command line.
Status
Beta (v0.0.1) — core CLI with E2E encryption, password/SSO/JWT authentication, and basic room operations are implemented.
Features
- Send encrypted messages to Matrix rooms
- Listen for incoming messages in real-time (prints to stdout)
- List joined rooms with display names and member counts
- E2E encryption via matrix-nio with persistent crypto store
- TOFU device trust — automatically trusts all devices in a room
- Multiple auth methods: password, SSO, or JWT via Keycloak (ROPC + JWKS)
- Flexible config: YAML file, environment variables, and CLI args (in ascending priority)
- Structured logging via loguru
Installation
From PyPI
pip install minimatrix
From source
git clone https://github.com/vroomfondel/minimatrix.git
cd minimatrix
make venv
source .venv/bin/activate
pip install .
Docker
docker build -t minimatrix .
Quick Start
1. Create a config file (optional)
# ~/.config/minimatrix/config.yaml
homeserver: "https://matrix.example.com"
user: "myuser"
password: "mypassword"
2. List joined rooms
minimatrix rooms
3. Send a message
minimatrix send --room '!abc123:example.com' "Hello from minimatrix!"
# Or pipe from stdin
echo "Hello from a pipe" | minimatrix send --room '!abc123:example.com'
4. Listen for messages
minimatrix listen --room '!abc123:example.com'
# [2026-02-22 14:30:01] <@alice:example.com> Hi there!
# Press Ctrl+C to stop
Configuration
Configuration is resolved in this order (later overrides earlier):
- YAML config file (
~/.config/minimatrix/config.yamlby default) - Environment variables
- CLI arguments
General Options
| Variable / Config Key | CLI Argument | Default |
|---|---|---|
MATRIX_HOMESERVER / homeserver |
--homeserver |
http://synapse.matrix.svc.cluster.local:8008 |
MATRIX_USER / user |
--user |
— (required) |
MATRIX_PASSWORD / password |
--password |
— (required) |
CRYPTO_STORE_PATH / crypto_store_path |
--crypto-store-path |
~/.local/share/minimatrix/crypto_store |
AUTH_METHOD / auth_method |
--auth-method |
password |
LOGURU_LEVEL |
— | DEBUG |
CLI Subcommands
| Subcommand | Description |
|---|---|
rooms |
List joined rooms with display name and member count |
send --room ROOM_ID [MESSAGE] |
Send a text message (reads from stdin if message omitted) |
listen --room ROOM_ID |
Listen for messages and print to stdout |
Use minimatrix --help or minimatrix <subcommand> --help for full usage.
JWT Authentication
When AUTH_METHOD=jwt is set, minimatrix authenticates via Keycloak ROPC (Resource Owner Password Credentials) grant instead of direct Matrix password login. This enables centralized identity management through Keycloak while allowing non-interactive authentication.
Authentication Flow
sequenceDiagram
participant CLI as minimatrix
participant KC as Keycloak
participant Syn as Synapse
CLI->>KC: 1. ROPC grant (username + password)
KC-->>CLI: 2. JWT access token
CLI->>Syn: 3. Matrix login (JWT)
Syn->>KC: 4. Validate JWT (JWKS or introspection)
KC-->>Syn: JWT valid
Syn-->>CLI: 5. Matrix access token
Supported Login Types
| Login Type | Synapse Config | Validation Method | Use Case |
|---|---|---|---|
com.famedly.login.token.oauth (default) |
synapse-token-authenticator oauth: |
JWKS endpoint | Recommended — automatic key rotation |
com.famedly.login.token |
synapse-token-authenticator jwt: |
Symmetric secret (HS512) | Internal services with shared secret |
org.matrix.login.jwt |
Native jwt_config: |
Public key (RS256) | Simple setup, manual key management |
JWT Environment Variables
| Variable / Config Key | CLI Argument | Default |
|---|---|---|
AUTH_METHOD / auth_method |
--auth-method |
password |
KEYCLOAK_URL / keycloak_url |
--keycloak-url |
— (required if jwt) |
KEYCLOAK_REALM / keycloak_realm |
--keycloak-realm |
— (required if jwt) |
KEYCLOAK_CLIENT_ID / keycloak_client_id |
--keycloak-client-id |
— (required if jwt) |
KEYCLOAK_CLIENT_SECRET / keycloak_client_secret |
--keycloak-client-secret |
"" (empty for public clients) |
JWT_LOGIN_TYPE / jwt_login_type |
--jwt-login-type |
com.famedly.login.token.oauth |
Requires synapse-token-authenticator on the Synapse side for the com.famedly.login.token.* login types.
Synapse Setup for JWT Authentication
Prerequisites
- Keycloak instance (any recent version)
- Synapse homeserver
- Admin access to both Keycloak and Synapse
Step 1: Keycloak Realm Setup
Create a dedicated realm for Matrix (or use an existing one).
Recommended realm settings:
registrationAllowed: false— disable self-registrationloginWithEmailAllowed: false— use usernames, not emails (Matrix localparts)registrationEmailAsUsername: false— important for Matrix username compatibility
Step 2: Create OAuth Client
Create a confidential client with ROPC (Direct Access Grants) enabled:
| Setting | Value | Reason |
|---|---|---|
publicClient |
false |
Confidential client with secret |
clientAuthenticatorType |
client-secret |
Use client secret for auth |
directAccessGrantsEnabled |
true |
Required — enables ROPC grant |
standardFlowEnabled |
false |
No browser redirects needed |
serviceAccountsEnabled |
false |
Not using service account |
After creation, copy the Client secret from the Credentials tab.
Step 3: Create User in Keycloak
Create a user account in your Keycloak realm. The Keycloak username must match the desired Matrix localpart — Synapse extracts it from the preferred_username JWT claim.
Step 4: Configure Synapse
Option A: OAuth with JWKS Validation (Recommended)
modules:
- module: synapse_token_authenticator.TokenAuthenticator
config:
oauth:
jwt_validation:
jwks_endpoint: "https://keycloak.example.com/realms/<realm>/protocol/openid-connect/certs"
localpart_path: "preferred_username"
require_expiry: true
validator:
type: exist
registration_enabled: true
Option B: JWT with Symmetric Secret
modules:
- module: synapse_token_authenticator.TokenAuthenticator
config:
jwt:
secret: "your-256-bit-secret-here"
algorithm: HS512
allow_registration: false
require_expiry: true
Option C: Native Synapse JWT (No Module Required)
# Get the realm public key
curl -s "https://keycloak.example.com/realms/<realm>" | jq -r '.public_key'
jwt_config:
enabled: true
secret: |
-----BEGIN PUBLIC KEY-----
<paste the public key here>
-----END PUBLIC KEY-----
algorithm: "RS256"
subject_claim: "preferred_username"
issuer: "https://keycloak.example.com/realms/<realm>"
Login Type Comparison
| Feature | com.famedly.login.token.oauth |
com.famedly.login.token |
org.matrix.login.jwt |
|---|---|---|---|
| Key management | Automatic (JWKS) | Manual (shared secret) | Manual (public key) |
| Key rotation | Automatic | Manual secret update | Manual config update |
| Algorithm | RS256 (asymmetric) | HS512 (symmetric) | RS256 (asymmetric) |
| Module required | Yes | Yes | No |
| Recommended for | Production | Internal services | Simple setups |
Troubleshooting
"Invalid username or password" from Synapse:
- Verify the Keycloak user exists and password is correct
- Check that
preferred_usernamein JWT matches an existing Matrix user (orregistration_enabled: true) - Verify JWKS endpoint is accessible from Synapse
"ROPC grant failed" from Keycloak:
- Ensure
directAccessGrantsEnabled: trueon the client - Verify client secret is correct
- Check user is enabled in Keycloak
"JWT signature validation failed":
- For JWKS: verify the endpoint URL is correct and accessible
- For native JWT: ensure public key is correctly formatted with PEM headers
- Check
issuermatches the JWTissclaim
Useful Keycloak Endpoints
| Endpoint | Purpose |
|---|---|
/realms/<realm>/.well-known/openid-configuration |
OIDC discovery document |
/realms/<realm>/protocol/openid-connect/certs |
JWKS endpoint (public keys) |
/realms/<realm>/protocol/openid-connect/token |
Token endpoint (ROPC) |
/realms/<realm> |
Realm info (includes public key) |
Development
| Target | Description |
|---|---|
make venv |
Create virtualenv and install all dependencies |
make tests |
Run pytest |
make lint |
Format code with black (line length 120) |
make isort |
Sort imports with isort |
make tcheck |
Static type checking with mypy (strict) |
make commit-checks |
Run pre-commit hooks on all files |
make prepare |
Run tests + commit-checks |
make pypibuild |
Build sdist + wheel with hatch |
make pypipush |
Publish to PyPI with hatch |
License
This project is licensed under the LGPL where applicable/possible — see LICENSE.md. Some files/parts may use other licenses: MIT | GPL | LGPL. Always check per‑file headers/comments.
Authors
- Repo owner (primary author)
- Additional attributions are noted inline in code comments
Acknowledgments
- Inspirations and snippets are referenced in code comments where appropriate.
⚠️ Note
This is a development/experimental project. For production use, review security settings, customize configurations, and test thoroughly in your environment. Provided "as is" without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or copyright holders be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with the software or the use or other dealings in the software. Use at your own risk.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file minimatrix-0.0.5.tar.gz.
File metadata
- Download URL: minimatrix-0.0.5.tar.gz
- Upload date:
- Size: 19.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: Hatch/1.16.3 cpython/3.14.3 HTTPX/0.28.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7c08f8ce36a446913a8ebf55be5712c343d44faca756c90201cd92bcce2356fa
|
|
| MD5 |
4e4aa38ee8db7ead1a18bb2040d1fea7
|
|
| BLAKE2b-256 |
433ef670c5627304b3c981da2e3d9ce5f50f5ac80af4d1c9ae8b437b3e65097c
|
File details
Details for the file minimatrix-0.0.5-py3-none-any.whl.
File metadata
- Download URL: minimatrix-0.0.5-py3-none-any.whl
- Upload date:
- Size: 22.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: Hatch/1.16.3 cpython/3.14.3 HTTPX/0.28.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f68617acd65596b31095f3996bc0ed7ae1b252eb58d144f02ac6cfd74d8207ab
|
|
| MD5 |
d0e7e315e6986bf6c40c618688c26285
|
|
| BLAKE2b-256 |
7e673890072f685c61d6cf4d7de7188905aec01b947b1e74e0282ef47c7f657b
|