* README.md: add new default value column. * refactor: split out config parsing in own function * add tests for parseConfig * more ideomatic order of functions in main.go * fix(deps): update github.com/matrix-org/gomatrixserverlib digest to 6697d93 (#120) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> * chore(deps): update dependency go to v1.25.3 (#121) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> * fix espace pipe character * add logging to indicate where the LiveKit API key and secrets are loaded from. --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
9.6 KiB
🎥 MatrixRTC Authorization Service
The MatrixRTC Authorization Service bridges Matrix and LiveKit, handling authentication and room creation when needed.
💡 TL;DR
Matrix user wants to start or join a call?
👤 ➡️ Gets OpenID token ➡️ Sends it to the MatrixRTC Authorization Service ➡️ Receives LiveKit JWT ➡️
- If full-access user ➡️ Can trigger LiveKit room creation (if needed) ➡️ Joins the call 🎉
- If restricted user ➡️ Can join existing rooms ➡️ Joins the call 🎉
📡 Once connected, the LiveKit SFU handles all real-time media routing so participants can see and hear each other.
🏗️ MatrixRTC Stack: Architecture Overview
📌 When to Use
This service is part of the MatrixRTC stack and is primarily used when the LiveKit RTC backend (MSC4195) is in use.
As outlined in the Element Call Self-Hosting Guide, you’ll also need:
- A LiveKit SFU
- MatrixRTC-compatible clients such as
Element Call, which can run
either:
- As a standalone Single Page Application (SPA) or
- Embedded for in-app calling
✨ What It Does
🔑 Generates JWT tokens for a given LiveKit identity and room derived from the Matrix user and Matrix room, allowing users to authenticate with the LiveKit SFU.
🛡️ Manages user access levels to ensure the proper and secure use of infrastructure:
- Full-access users — Matrix users from homeservers in the same or related deployment as the MatrixRTC backend. Can trigger automatic LiveKit room creation if needed.
- Restricted users — All other Matrix users. Can join existing LiveKit SFU rooms, but cannot auto-create new ones.
🏗️ Auto-creates LiveKit rooms for full-access users if they don’t already exist.
Note
This setup ensures resources are used appropriately while still supporting seamless cross-federation MatrixRTC sessions, e.g., video calls. Remote users (not on the same deployment) can join existing rooms, but only full-access (local) users can trigger room creation. The SFU selection algorithm and event ordering ensure that conferences across Matrix federation remain fully functional.
🗺️ How It Works — Token Exchange Flow
sequenceDiagram
participant U as 🧑 User
participant M as 🏢 Matrix Homeserver
participant A as 🔐 MatrixRTC Authorization Service
participant L as 📡 LiveKit SFU
U->>M: Requests OpenID token
M-->>U: Returns OpenID token
U->>A: Sends OpenID token & room request
A->>M: Validates token via OpenID API
M-->>A: Confirms user identity
A->>A: Generates LiveKit JWT
A->>L: (If full-access user) Create room if missing
A-->>U: Returns LiveKit JWT
U->>L: Connects to room using JWT
🚀 Installation
Releases are available here.
🐳 From Docker Image
docker run -e LIVEKIT_URL="ws://somewhere" -e LIVEKIT_KEY=devkey -e LIVEKIT_SECRET=secret -e LIVEKIT_FULL_ACCESS_HOMESERVERS=example.com -p 8080:8080 ghcr.io/element-hq/lk-jwt-service:0.3.0
📦 From Release File
- Download & extract:
wget https://github.com/element-hq/lk-jwt-service/archive/refs/tags/v0.3.0.tar.gz
tar -xvf v0.3.0.tar.gz
mv lk-jwt-service-0.3.0 lk-jwt-service
- Build:
cd lk-jwt-service
go build -o lk-jwt-service .
- Run locally:
LIVEKIT_URL="ws://somewhere" LIVEKIT_KEY=devkey LIVEKIT_SECRET=secret LIVEKIT_LOCAL_HOMESERVERS=example.com ./lk-jwt-service
⚙️ Configuration
Set environment variables to configure the service:
| Variable | Description | Required | Default |
|---|---|---|---|
LIVEKIT_URL |
WebSocket URL of the LiveKit SFU | ✅ Yes | |
LIVEKIT_KEY / LIVEKIT_KEY_FROM_FILE |
API key or file path for LiveKit SFU | ✅ Yes | |
LIVEKIT_SECRET / LIVEKIT_SECRET_FROM_FILE |
API secret or file path for LiveKit SFU | ✅ Yes | |
LIVEKIT_KEY_FILE |
File path with APIkey: secret format |
⚠️ mutually exclusive with LIVEKIT_{KEY|SECRET} |
|
LIVEKIT_JWT_BIND |
Address to bind the server to | ❌ No, ⚠️ mutually exclusive with LIVEKIT_JWT_PORT |
:8080 |
LIVEKIT_JWT_PORT |
⚠️ Deprecated Port to bind the server to | ❌ No, ⚠️ mutually exclusive with LIVEKIT_JWT_BIND |
|
LIVEKIT_FULL_ACCESS_HOMESERVERS |
Comma-separated list of full-access homeservers (* for all) |
❌ No | * |
Important
By default, the LiveKit SFU auto-creates rooms for all users. To ensure proper access control, update your LiveKit config.yaml to disable automatic room creation.
LiveKit SFU config should include:
room:
auto_create: false
🔒 Transport Layer Security (TLS) Setup Using a Reverse Proxy
To properly secure the MatrixRTC Authorization Service, a reverse proxy is recommended.
Example Caddy Config
matrix-rtc.domain.tld {
bind xx.xx.xx.xx
handle /livekit/jwt* {
reverse_proxy localhost:8080
}
}
Example Nginx Config
server {
listen 80;
server_name matrix-rtc.domain.tld;
# Redirect HTTP → HTTPS
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name matrix-rtc.domain.tld;
# TLS certificate paths (replace with your own)
ssl_certificate /etc/ssl/certs/matrix-rtc.crt;
ssl_certificate_key /etc/ssl/private/matrix-rtc.key;
# TLS settings (minimal)
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
location /livekit/jwt/ {
proxy_pass http://localhost:8080/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
📌 Do Not Forget to Update Your Matrix Site's .well-known/matrix/client
For proper MatrixRTC functionality, you need to configure your site's
.well-known/matrix/client. See the
Element Call self-hosting guide
for reference.
The following key must be included in
https://domain.tld/.well-known/matrix/client:
"org.matrix.msc4143.rtc_foci": [
{
"type": "livekit",
"livekit_service_url": "https://matrix-rtc.domain.tld/livekit/jwt"
}
]
🧪 Development & Testing
Disable TLS verification
For testing and debugging (e.g. in the absence of trusted certificates while
testing in a lab), you can disable TLS verification for the outgoing connection
to the Matrix homeserver by setting the environment variable
LIVEKIT_INSECURE_SKIP_VERIFY_TLS to YES_I_KNOW_WHAT_I_AM_DOING.
🛠️ Development Environment (Docker Compose)
Based on the Element Call GitHub repo
The easiest way to spin up the full Matrix stack is by using the development environment provided by Element Call. For detailed instructions, see Element Call Backend Setup.
Note
To ensure your local frontend works properly, you need to add certificate exceptions in your browser for:
https://localhost:3000https://matrix-rtc.m.localhost/livekit/jwt/healthzhttps://synapse.m.localhost/.well-known/matrix/clientYou can do this either by adding the minimal m.localhost CA (dev_tls_m.localhost.crt) to your browser’s trusted certificates, or by visiting each URL in your browser and following the prompts to accept the exception.
🐳 Start MatrixRTC stack without the MatrixRTC Authorization Service
git clone https://github.com/element-hq/element-call.git
cd element-call
docker-compose -f ./dev-backend-docker-compose.yml -f ./playwright-backend-docker-compose.override.yml up nginx livekit synapse redis
🔑 Start the MatrixRTC Authorization Service locally
git clone https://github.com/element-hq/lk-jwt-service
cd lk-jwt-service
LIVEKIT_INSECURE_SKIP_VERIFY_TLS="YES_I_KNOW_WHAT_I_AM_DOING" \
LIVEKIT_URL="wss://matrix-rtc.m.localhost/livekit/sfu" \
LIVEKIT_KEY=devkey \
LIVEKIT_SECRET=secret \
LIVEKIT_JWT_PORT=6080 \
LIVEKIT_LOCAL_HOMESERVERS=synapse.m.localhost \
./lk-jwt-service
