CRITICAL FIX: The OwnTracks app publishes to owntracks/<username>/<device_id>, not owntracks/owntrack/<device_id>. This was causing data delivery failures and privacy violations. Changes: - Fix ACL topic pattern: owntracks/<username>/# (was: owntracks/owntrack/<device_id>) - Backend now uses MQTT_ADMIN_USERNAME for global subscription - Update UI forms and placeholders with correct pattern - Update email template with correct topic format - Enable Mosquitto ACL file for user isolation - Add migration script for existing ACL rules - Update documentation (README, GEMINI.md) Privacy & Security: - Each user isolated at MQTT broker level via ACL - Backend subscribes with admin credentials to owntracks/+/+ - Web UI filters data by parent_user_id for additional security - GDPR compliant multi-layer defense in depth Files changed: - lib/mqtt-db.ts - Updated createDefaultRule() to use username - app/api/mqtt/credentials/route.ts - Pass username to ACL creation - app/admin/mqtt/page.tsx - UI forms and state management - emails/mqtt-credentials.tsx - Email template topic pattern - lib/mqtt-subscriber.ts - Use admin credentials from env - mosquitto/config/mosquitto.conf - Enable ACL enforcement - README.md, GEMINI.md - Documentation updates - scripts/fix-acl-topic-patterns.js - Migration script - MQTT_TOPIC_FIX.md - Detailed implementation guide 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
6.7 KiB
MQTT Topic Pattern Fix - Implementation Summary
Problem Description
The OwnTracks smartphone app publishes location data to MQTT topics in the format:
owntracks/<username>/<device_id>
Example: owntracks/device_15_2b73f9bb/15
However, the application was configured with the incorrect pattern:
owntracks/owntrack/<device_id>
This was a critical privacy and data protection issue because:
- Users could not receive their location data (wrong subscription pattern)
- ACL rules would not properly isolate users
- GDPR compliance was at risk
Solution Overview
All MQTT topic patterns have been corrected to use the proper OwnTracks format:
owntracks/<username>/#
Where <username> is the MQTT username (e.g., device_12_4397af93).
Privacy & Security Architecture
Multi-Layer Security (Defense in Depth)
-
MQTT Broker Level (Mosquitto ACL)
- Each user has strict ACL rules limiting access to their own topics only
- Example ACL for user
device_12_4397af93:user device_12_4397af93 topic readwrite owntracks/device_12_4397af93/# - Admin user has full access for backend operations
-
Backend Level
- Subscribes to
owntracks/+/+using admin credentials - Collects all location data but filters by
parent_user_idin database queries - Acts as centralized data processor
- Subscribes to
-
Application Level
- Web UI/API filters data by user ownership
- Users only see their own devices and locations
Files Modified
Core Logic Changes
-
lib/mqtt-db.ts(Line 209-214)- Updated
createDefaultRule()function signature to acceptusernameparameter - Changed topic pattern from
owntracks/owntrack/${deviceId}/#toowntracks/${username}/#
- Updated
-
app/api/mqtt/credentials/route.ts(Line 111)- Updated call to
createDefaultRule()to pass bothdevice_idandusername
- Updated call to
-
lib/mqtt-subscriber.ts(Line 202-203)- Backend now uses
MQTT_ADMIN_USERNAMEandMQTT_ADMIN_PASSWORDfrom environment - Ensures backend has admin privileges to subscribe to all topics
- Backend now uses
UI Changes
app/admin/mqtt/page.tsx- Line 67: Added
mqtt_usernamefield toaclFormDatastate - Line 413: Pass
mqtt_usernamewhen opening ACL modal - Line 246: Include
mqtt_usernamewhen resetting form - Line 603: Fixed placeholder to show
owntracks/<username>/# - Line 607: Fixed help text example to show correct pattern
- Line 67: Added
Email Template
emails/mqtt-credentials.tsx(Line 52)- Changed topic pattern from
owntracks/owntrack/{deviceId}toowntracks/{mqttUsername}/#
- Changed topic pattern from
Documentation
-
README.md(Line 283-284)- Updated OwnTracks configuration example with correct topic format
-
GEMINI.md(Line 84, 86)- Updated architecture documentation with correct topic patterns
- Added note about backend using admin credentials
Migration Tools
scripts/fix-acl-topic-patterns.js(New file)- Migration script to update existing ACL rules in database
- Not needed for fresh installations
Environment Variables Required
Ensure the following variables are set in .env:
# MQTT Admin Credentials (used by backend subscriber and sync)
MQTT_ADMIN_USERNAME=admin
MQTT_ADMIN_PASSWORD=admin
# MQTT Broker URL
MQTT_BROKER_URL=mqtt://mosquitto:1883
# Mosquitto Configuration Paths
MOSQUITTO_PASSWORD_FILE=/mosquitto/config/password.txt
MOSQUITTO_ACL_FILE=/mosquitto/config/acl.txt
MOSQUITTO_CONTAINER_NAME=mosquitto
How It Works Now
User Provisioning Flow
-
Admin creates MQTT credentials for device:
- Username:
device_12_4397af93(auto-generated) - Password: (auto-generated secure password)
- Username:
-
ACL rule is automatically created:
user device_12_4397af93 topic readwrite owntracks/device_12_4397af93/# -
User configures OwnTracks app:
- MQTT Broker:
mqtt://your-broker:1883 - Username:
device_12_4397af93 - Password: (from credentials)
- Device ID:
12
- MQTT Broker:
-
OwnTracks publishes to:
owntracks/device_12_4397af93/12 -
Mosquitto ACL enforces:
- User
device_12_4397af93can ONLY access topics matchingowntracks/device_12_4397af93/* - Other users CANNOT read or write to this topic
- User
-
Backend receives data:
- Subscribes to
owntracks/+/+with admin credentials - Stores location in database with device relationship
- Web UI filters by
parent_user_idto show only user's data
- Subscribes to
Deployment Steps
For Fresh Installations
- Pull the updated code
- Ensure
.envhas correctMQTT_ADMIN_USERNAMEandMQTT_ADMIN_PASSWORD - Build and start services:
docker-compose up --build -d
For Existing Installations
- Pull the updated code
- Verify
.envhas admin credentials set - Run migration script if database has existing ACL rules:
node scripts/fix-acl-topic-patterns.js - Rebuild and restart services:
docker-compose up --build -d - In admin UI, click "MQTT Sync" to regenerate ACL file
- Restart Mosquitto to apply ACL changes:
docker-compose restart mosquitto
Testing the Fix
- Provision a test device via admin UI
- Check generated credentials:
- Note the MQTT username (e.g.,
device_12_abc123)
- Note the MQTT username (e.g.,
- Verify ACL rule was created with correct pattern:
- Go to admin MQTT page
- Check ACL rules show
owntracks/device_12_abc123/#
- Configure OwnTracks app with credentials
- Verify data flow:
- OwnTracks should publish successfully
- Location data should appear on map
- Other users should NOT see this device
GDPR Compliance
✅ Privacy by Design: Users are isolated at the MQTT broker level ✅ Data Minimization: Each user only has access to their own data ✅ Security: Multi-layer defense prevents unauthorized access ✅ Transparency: Clear ACL rules define access permissions
Troubleshooting
Issue: OwnTracks not connecting to MQTT
- Verify credentials are correct
- Check Mosquitto logs:
docker-compose logs mosquitto - Ensure ACL file was generated:
docker exec mosquitto cat /mosquitto/config/acl.txt
Issue: Location data not appearing
- Check backend logs:
docker-compose logs app - Verify MQTT subscriber is connected
- Confirm topic pattern matches:
owntracks/<username>/<device_id>
Issue: User can see another user's data
- This should NOT be possible after the fix
- Verify ACL file has correct rules per user
- Restart Mosquitto after ACL changes
- Check user relationships in database (
parent_user_id)
Support
For questions or issues, please check:
- OwnTracks Documentation
- Project README.md
- GitHub Issues
Last Updated: 2025-11-29 Author: Claude Code Version: 1.0