Files
location-mqtt-tracker-app/MQTT_TOPIC_FIX.md
Joachim Hummel 31c0e1f572 Fix MQTT topic pattern for OwnTracks and implement privacy isolation
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>
2025-11-29 21:49:31 +00:00

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)

  1. 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
  2. Backend Level

    • Subscribes to owntracks/+/+ using admin credentials
    • Collects all location data but filters by parent_user_id in database queries
    • Acts as centralized data processor
  3. Application Level

    • Web UI/API filters data by user ownership
    • Users only see their own devices and locations

Files Modified

Core Logic Changes

  1. lib/mqtt-db.ts (Line 209-214)

    • Updated createDefaultRule() function signature to accept username parameter
    • Changed topic pattern from owntracks/owntrack/${deviceId}/# to owntracks/${username}/#
  2. app/api/mqtt/credentials/route.ts (Line 111)

    • Updated call to createDefaultRule() to pass both device_id and username
  3. lib/mqtt-subscriber.ts (Line 202-203)

    • Backend now uses MQTT_ADMIN_USERNAME and MQTT_ADMIN_PASSWORD from environment
    • Ensures backend has admin privileges to subscribe to all topics

UI Changes

  1. app/admin/mqtt/page.tsx
    • Line 67: Added mqtt_username field to aclFormData state
    • Line 413: Pass mqtt_username when opening ACL modal
    • Line 246: Include mqtt_username when resetting form
    • Line 603: Fixed placeholder to show owntracks/<username>/#
    • Line 607: Fixed help text example to show correct pattern

Email Template

  1. emails/mqtt-credentials.tsx (Line 52)
    • Changed topic pattern from owntracks/owntrack/{deviceId} to owntracks/{mqttUsername}/#

Documentation

  1. README.md (Line 283-284)

    • Updated OwnTracks configuration example with correct topic format
  2. GEMINI.md (Line 84, 86)

    • Updated architecture documentation with correct topic patterns
    • Added note about backend using admin credentials

Migration Tools

  1. 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

  1. Admin creates MQTT credentials for device:

    • Username: device_12_4397af93 (auto-generated)
    • Password: (auto-generated secure password)
  2. ACL rule is automatically created:

    user device_12_4397af93
    topic readwrite owntracks/device_12_4397af93/#
    
  3. User configures OwnTracks app:

    • MQTT Broker: mqtt://your-broker:1883
    • Username: device_12_4397af93
    • Password: (from credentials)
    • Device ID: 12
  4. OwnTracks publishes to:

    owntracks/device_12_4397af93/12
    
  5. Mosquitto ACL enforces:

    • User device_12_4397af93 can ONLY access topics matching owntracks/device_12_4397af93/*
    • Other users CANNOT read or write to this topic
  6. Backend receives data:

    • Subscribes to owntracks/+/+ with admin credentials
    • Stores location in database with device relationship
    • Web UI filters by parent_user_id to show only user's data

Deployment Steps

For Fresh Installations

  1. Pull the updated code
  2. Ensure .env has correct MQTT_ADMIN_USERNAME and MQTT_ADMIN_PASSWORD
  3. Build and start services:
    docker-compose up --build -d
    

For Existing Installations

  1. Pull the updated code
  2. Verify .env has admin credentials set
  3. Run migration script if database has existing ACL rules:
    node scripts/fix-acl-topic-patterns.js
    
  4. Rebuild and restart services:
    docker-compose up --build -d
    
  5. In admin UI, click "MQTT Sync" to regenerate ACL file
  6. Restart Mosquitto to apply ACL changes:
    docker-compose restart mosquitto
    

Testing the Fix

  1. Provision a test device via admin UI
  2. Check generated credentials:
    • Note the MQTT username (e.g., device_12_abc123)
  3. Verify ACL rule was created with correct pattern:
    • Go to admin MQTT page
    • Check ACL rules show owntracks/device_12_abc123/#
  4. Configure OwnTracks app with credentials
  5. 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:


Last Updated: 2025-11-29 Author: Claude Code Version: 1.0