D-Bus API Reference
FIDO Bridge provides a D-Bus interface for service management, device pairing, and status monitoring. This interface allows external applications and scripts to interact with the FIDO Bridge daemon.
Source: /path/to/fido-bridge/crates/client/src/dbus_interface.rs
Interface Details
Bus Information
- Bus Type: Session bus
- Bus Name:
org.fidobridge.Client - Object Path:
/org/fidobridge/Client - Interface Name:
org.fidobridge.Client
Registration: Lines 477-496 in dbus_interface.rs
Connecting to the Interface
The daemon automatically registers on the session bus when started. Verify it's running:
busctl --user list | grep fidobridge
Expected output:
org.fidobridge.Client 1234 fido-bridge
D-Bus Methods
All methods are defined in the #[interface(name = "org.fidobridge.Client")] block (lines 119-418).
InitiatePairing
Initiate a new pairing session with a device.
Signature: InitiatePairing(s) -> s
Parameters:
pin(string): 6-digit PIN for pairing. If empty string, a random PIN is generated.
Returns:
session_id(string): Unique session ID for this pairing attempt
Errors:
zbus::fdo::Error::Failed: Pairing initiation failed (network error, etc.)
Implementation: Lines 122-173
Example using busctl:
# Generate random PIN
busctl --user call org.fidobridge.Client \
/org/fidobridge/Client \
org.fidobridge.Client \
InitiatePairing s ""
# Use specific PIN
busctl --user call org.fidobridge.Client \
/org/fidobridge/Client \
org.fidobridge.Client \
InitiatePairing s "123456"
What it does:
- Generates random 6-digit PIN if not provided (lines 125-129)
- Cleans up expired pairing sessions (line 132)
- Creates SPAKE2 pairing manager with PIN
- Calls server's pairing initiation endpoint
- Stores session info locally with status "pending"
- Emits
PairingRequestedsignal (line 169) - Returns session ID to caller
ListPairingSessions
List all active pairing sessions.
Signature: ListPairingSessions() -> a(sss)
Parameters: None
Returns:
- Array of tuples
(session_id, initiator_token, pin)session_id(string): Session identifierinitiator_token(string): Device token of initiatorpin(string): The 6-digit PIN for this session
Errors: None
Implementation: Lines 175-189
Example using busctl:
busctl --user call org.fidobridge.Client \
/org/fidobridge/Client \
org.fidobridge.Client \
ListPairingSessions
Output format:
a(sss) 2 "session-123" "linux-abc123" "456789" "session-456" "linux-def456" "012345"
Note: Automatically cleans up expired sessions before returning the list (line 179).
RespondToPairing
Respond to an existing pairing session (called by the responder device).
Signature: RespondToPairing(ss) -> s
Parameters:
session_id(string): Session ID from the initiatorpin(string): 6-digit PIN from the initiator
Returns:
device_id(string): Device ID of the paired initiator
Errors:
zbus::fdo::Error::Failed: Pairing failed (wrong PIN, expired session, network error, etc.)
Implementation: Lines 191-250
Example using busctl:
busctl --user call org.fidobridge.Client \
/org/fidobridge/Client \
org.fidobridge.Client \
RespondToPairing ss "session-abc123" "456789"
What it does:
- Creates SPAKE2 responder with provided PIN
- Calls server to get initiator's SPAKE2 message
- Derives shared secret from SPAKE2 exchange
- Stores paired device with shared secret
- Emits
PairingCompletedsignal (line 234) - Returns initiator's device ID
GetPairingStatus
Get the current status of a pairing session.
Signature: GetPairingStatus(s) -> (ss)
Parameters:
session_id(string): Session ID to check
Returns:
- Tuple
(status, device_name)status(string): "pending", "completed", or "expired"device_name(string): Name of paired device (empty if not completed)
Errors:
zbus::fdo::Error::Failed: Session not found
Implementation: Lines 252-366
Example using busctl:
busctl --user call org.fidobridge.Client \
/org/fidobridge/Client \
org.fidobridge.Client \
GetPairingStatus s "session-abc123"
Output examples:
# Pending (responder hasn't responded yet)
ss "pending" ""
# Completed
ss "completed" "Android Phone"
# Expired
ss "expired" ""
What it does:
- Checks if session exists in local storage
- Validates session hasn't expired (config.pairing_timeout, default 300s)
- If pending, attempts to poll server for responder's message
- If responder has submitted, completes SPAKE2 exchange and stores paired device
- Emits appropriate signals (
PairingCompletedorPairingFailed) - Returns current status
Note: This method is designed to be polled by the initiator to detect when pairing completes.
ListPairedDevices
List all paired devices.
Signature: ListPairedDevices() -> a(sss)
Parameters: None
Returns:
- Array of tuples
(device_id, display_name, last_seen)device_id(string): Unique device identifierdisplay_name(string): Human-readable device name (or "Unknown")last_seen(string): RFC3339 timestamp of last activity
Errors:
zbus::fdo::Error::Failed: Storage error
Implementation: Lines 368-395
Example using busctl:
busctl --user call org.fidobridge.Client \
/org/fidobridge/Client \
org.fidobridge.Client \
ListPairedDevices
Output format:
a(sss) 2 "device-abc123" "Android Phone" "2025-10-06T10:30:15Z" "device-def456" "Tablet" "2025-10-05T15:20:00Z"
UnpairDevice
Remove a paired device.
Signature: UnpairDevice(s) -> b
Parameters:
device_id(string): Device ID to unpair
Returns:
success(boolean):trueif device was unpaired,falseif device not found
Errors:
zbus::fdo::Error::Failed: Storage error
Implementation: Lines 397-418
Example using busctl:
busctl --user call org.fidobridge.Client \
/org/fidobridge/Client \
org.fidobridge.Client \
UnpairDevice s "device-abc123"
Output:
b true # Device was unpaired
b false # Device not found
GetStatus
Get current service status and configuration.
Signature: GetStatus() -> a{ss}
Parameters: None
Returns:
- Dictionary mapping string keys to string values:
service: "running" (always, since you can only call this if service is running)device_id: This client's device identifierserver_url: Current server URLserver_mode: "embedded" or "remote"paired_devices: Number of paired devices (as string)active_sessions: Number of active pairing sessions (as string)
Errors: None
Implementation: Lines 420-450
Example using busctl:
busctl --user call org.fidobridge.Client \
/org/fidobridge/Client \
org.fidobridge.Client \
GetStatus
Output format:
a{ss} 6 "service" "running" "device_id" "linux-abc123" "server_url" "http://localhost:3000" "server_mode" "embedded" "paired_devices" "2" "active_sessions" "1"
D-Bus Signals
Signals are emitted by the service to notify clients of asynchronous events. Defined in lines 452-474.
PairingRequested
Emitted when a new pairing session is initiated.
Signature: PairingRequested(ss)
Parameters:
pin(string): The 6-digit PIN for this pairingsession_id(string): Unique session identifier
Implementation: Lines 453-458, emitted at line 169
Example monitoring with busctl:
busctl --user monitor org.fidobridge.Client
Use case: UI applications can listen for this signal to display pairing QR codes or notifications.
PairingCompleted
Emitted when a pairing session successfully completes.
Signature: PairingCompleted(ss)
Parameters:
device_id(string): Device ID of newly paired devicedevice_name(string): Human-readable name of paired device
Implementation: Lines 460-466, emitted at lines 234, 324
Example use case: Display notification "Paired with Android Phone"
PairingFailed
Emitted when a pairing session fails or expires.
Signature: PairingFailed(ss)
Parameters:
session_id(string): The session that failedreason(string): Human-readable error message
Implementation: Lines 468-474, emitted at lines 242, 272, 346
Common reasons:
- "Session expired" - Timeout reached (default 300s)
- "Pairing response failed: < error >" - Network or crypto error
- "Message too old" - Timestamp validation failed
Background Tasks
The D-Bus service spawns background tasks for maintenance.
Session Cleanup Task
Source: Lines 520-563
What it does:
- Runs every 60 seconds
- Scans all pairing sessions for expired ones
- Removes sessions older than
config.pairing_timeout(default 300s) - Emits
PairingFailedsignals for expired sessions
Implementation details:
tokio::spawn( async move {
let mut interval = tokio::time::interval(tokio::time::Duration::from_secs(60));
// ... cleanup logic
});
Using the D-Bus Interface
From Command Line (busctl)
List all methods and signals:
busctl --user introspect org.fidobridge.Client /org/fidobridge/Client
Monitor all signals:
busctl --user monitor org.fidobridge.Client
From Python (python-dbus)
#!/usr/bin/env python3
import dbus
from dbus.mainloop.glib import DBusGMainLoop
from gi.repository import GLib
DBusGMainLoop(set_as_default=True)
# Connect to session bus
bus = dbus.SessionBus()
# Get proxy object
proxy = bus.get_object('org.fidobridge.Client', '/org/fidobridge/Client')
iface = dbus.Interface(proxy, 'org.fidobridge.Client')
# Call methods
status = iface.GetStatus()
print(f"Service status: {dict(status)}")
devices = iface.ListPairedDevices()
for device_id, name, last_seen in devices:
print(f"Device: {name} ({device_id}), Last seen: {last_seen}")
# Listen for signals
def on_pairing_completed(device_id, device_name):
print(f"Pairing completed: {device_name} ({device_id})")
bus.add_signal_receiver(
on_pairing_completed,
signal_name='PairingCompleted',
dbus_interface='org.fidobridge.Client',
bus_name='org.fidobridge.Client',
path='/org/fidobridge/Client'
)
# Start event loop
loop = GLib.MainLoop()
loop.run()
From Rust (zbus)
The FIDO Bridge CLI uses zbus to communicate with the daemon:
Source: /path/to/fido-bridge/crates/client/src/cli_dbus_client.rs
use zbus::{Connection, Proxy};
async fn get_status() -> anyhow::Result<HashMap<String, String>> {
let connection = Connection::session().await?;
let proxy = Proxy::new(
&connection,
"org.fidobridge.Client",
"/org/fidobridge/Client",
"org.fidobridge.Client",
).await?;
let status: HashMap<String, String> = proxy.call("GetStatus", &()).await?;
Ok(status)
}
Listening for signals (from cli_dbus_client.rs lines 139-173):
use futures_util::StreamExt;
async fn wait_for_pairing_signal() -> anyhow::Result<(String, String)> {
let connection = Connection::session().await?;
let proxy = Proxy::new(
&connection,
"org.fidobridge.Client",
"/org/fidobridge/Client",
"org.fidobridge.Client",
).await?;
let mut stream = proxy.receive_signal("PairingCompleted").await?;
while let Some(signal) = stream.next().await {
let (device_id, device_name): (String, String) =
signal.body().deserialize()?;
return Ok((device_id, device_name));
}
anyhow::bail!("Stream ended")
}
From Shell Scripts
Check if service is running:
if busctl --user list | grep -q "org.fidobridge.Client"; then
echo "FIDO Bridge is running"
else
echo "FIDO Bridge is not running"
fi
Get service status:
busctl --user call org.fidobridge.Client \
/org/fidobridge/Client \
org.fidobridge.Client \
GetStatus | grep -oP 'paired_devices" "\K\d+'
List paired devices:
busctl --user call org.fidobridge.Client \
/org/fidobridge/Client \
org.fidobridge.Client \
ListPairedDevices --json=short | jq
Error Handling
All methods use zbus error types. Common errors:
Method Call Errors
Service Not Available:
Error: org.freedesktop.DBus.Error.ServiceUnknown
Solution: Start the service with systemctl --user start fido-bridge
Invalid Arguments:
Error: org.freedesktop.DBus.Error.InvalidArgs
Solution: Check method signature and argument types
Method Failed:
Error: org.freedesktop.zbus.Error.Failure
Solution: Check service logs with fido-bridge logs
Security Considerations
D-Bus Access Control
The service registers on the session bus, which means:
- Only accessible to the current user session
- Not accessible to other users on the system
- Protected by D-Bus's built-in session isolation
No additional authentication is required beyond D-Bus session access.
Sensitive Data in Methods
- Shared secrets: Never exposed via D-Bus API
- PINs: Only transmitted during pairing, not stored or exposed after
- Device credentials: Only device IDs and names are exposed, not encryption keys
Signal Privacy
Signals are broadcast to all listeners on the session bus. Applications should:
- Not display PINs from
PairingRequestedsignals if screen might be visible to others - Verify session IDs match expected values before acting on signals
Troubleshooting
"Service Not Found" Error
# Check if service is running
systemctl --user status fido-bridge
# Start if not running
systemctl --user start fido-bridge
# Verify D-Bus registration
busctl --user list | grep fidobridge
"Permission Denied" Error
D-Bus session permissions should allow access. If blocked:
# Check D-Bus policy
cat /etc/dbus-1/session.conf
Method Calls Hang
Check if service is responsive:
# Quick status check
fido-bridge status
# Check logs for errors
fido-bridge logs
See Also
- Service Management Guide - Managing the daemon
- CLI Commands - Command-line interface reference
- Architecture Overview - System design