13 KiB
NetworkManager API Documentation
Overview
The network manager API provides methods for managing WiFi connections, monitoring network state, and handling credential prompts through NetworkManager or iwd (and systemd-networkd for ethernet only). Communication occurs over a message-based protocol (websocket, IPC, etc.) with event subscriptions for state updates.
API Methods
network.wifi.connect
Initiate a WiFi connection.
Request:
{
"method": "network.wifi.connect",
"params": {
"ssid": "NetworkName",
"password": "optional-password",
"interactive": true
}
}
Parameters:
ssid(string, required): Network SSIDpassword(string, optional): Pre-shared key for WPA/WPA2/WPA3 networksinteractive(boolean, optional): Enable credential prompting if authentication fails or password is missing. Automatically set totruewhen connecting to secured networks without providing a password.
Response:
{
"success": true,
"message": "connecting"
}
Behavior:
- Returns immediately; connection happens asynchronously
- State updates delivered via
networkservice subscription - Credential prompts delivered via
network.credentialsservice subscription
network.credentials.submit
Submit credentials in response to a prompt.
Request:
{
"method": "network.credentials.submit",
"params": {
"token": "correlation-token",
"secrets": {
"psk": "password"
},
"save": true
}
}
Parameters:
token(string, required): Token from credential promptsecrets(object, required): Key-value map of credential fieldssave(boolean, optional): Whether to persist credentials (default: false)
Common secret fields:
psk: Pre-shared key for WPA2/WPA3 personal networksidentity: Username for 802.1X enterprise networkspassword: Password for 802.1X enterprise networks
network.credentials.cancel
Cancel a credential prompt.
Request:
{
"method": "network.credentials.cancel",
"params": {
"token": "correlation-token"
}
}
Event Subscriptions
Subscribing to Events
Subscribe to receive network state updates and credential prompts:
{
"method": "subscribe",
"params": {
"services": ["network", "network.credentials"]
}
}
Both services are required for full connection handling. Missing network.credentials means credential prompts won't be received.
network Service Events
State updates are sent whenever network configuration changes:
{
"service": "network",
"data": {
"networkStatus": "wifi",
"isConnecting": false,
"connectingSSID": "",
"wifiConnected": true,
"wifiSSID": "MyNetwork",
"wifiIP": "192.168.1.100",
"lastError": ""
}
}
State fields:
networkStatus: Current connection type (wifi,ethernet,disconnected)isConnecting: Whether a connection attempt is in progressconnectingSSID: SSID being connected to (empty when idle)wifiConnected: Whether associated with an access pointwifiSSID: Currently connected network namewifiIP: Assigned IP address (empty until DHCP completes)lastError: Error message from last failed connection attempt
network.credentials Service Events
Credential prompts are sent when authentication is required:
{
"service": "network.credentials",
"data": {
"token": "unique-prompt-id",
"ssid": "NetworkName",
"setting": "802-11-wireless-security",
"fields": ["psk"],
"hints": ["wpa3", "sae"],
"reason": "Credentials required"
}
}
Prompt fields:
token: Unique identifier for this prompt (use in submit/cancel)ssid: Network requesting credentialssetting: Authentication type (802-11-wireless-securityfor personal WiFi,802-1xfor enterprise)fields: Array of required credential field nameshints: Additional context about the network typereason: Human-readable explanation (e.g., "Previous password was incorrect")
Connection Flow
Typical Timeline
T+0ms Call network.wifi.connect
T+10ms Receive {"success": true, "message": "connecting"}
T+100ms State update: isConnecting=true, connectingSSID="Network"
T+500ms Credential prompt (if needed)
T+1000ms Submit credentials
T+3000ms State update: wifiConnected=true, wifiIP="192.168.x.x"
State Machine
IDLE
|
| network.wifi.connect
v
CONNECTING (isConnecting=true, connectingSSID set)
|
+-- Needs credentials
| |
| v
| PROMPTING (credential prompt event)
| |
| | network.credentials.submit
| v
| back to CONNECTING
|
+-- Success
| |
| v
| CONNECTED (wifiConnected=true, wifiIP set, isConnecting=false)
|
+-- Failure
|
v
ERROR (isConnecting=false, !wifiConnected, lastError set)
Connection Success Detection
A connection is successful when all of the following are true:
wifiConnectedistruewifiIPis set and non-emptywifiSSIDmatches the target networkisConnectingisfalse
Do not rely on wifiConnected alone - the device may be associated with an access point but not have an IP address yet.
Example:
function isConnectionComplete(state, targetSSID) {
return state.wifiConnected &&
state.wifiIP &&
state.wifiIP !== "" &&
state.wifiSSID === targetSSID &&
!state.isConnecting;
}
Error Handling
Error Detection
Errors occur when a connection attempt stops without success:
function checkForFailure(state, wasConnecting, targetSSID) {
// Was connecting, now idle, but not connected
if (wasConnecting &&
!state.isConnecting &&
state.connectingSSID === "" &&
!state.wifiConnected) {
return state.lastError || "Connection failed";
}
return null;
}
Common Error Scenarios
Wrong Password
Detection methods:
- Quick failure (< 3 seconds from start)
lastErrorcontains "password", "auth", or "secrets"- Second credential prompt with
reason: "Previous password was incorrect"
Handling:
if (prompt.reason === "Previous password was incorrect") {
// Show error, clear password field, re-focus input
}
Network Out of Range
Detection:
lastErrorcontains "not-found" or "connection-attempt-failed"
Connection Timeout
Detection:
isConnectingremains true for > 30 seconds
Implementation:
let timeout = setTimeout(() => {
if (currentState.isConnecting) {
handleTimeout();
}
}, 30000);
DHCP Failure
Detection:
wifiConnectedis truewifiIPis empty after 15+ seconds
Error Message Translation
Map technical errors to user-friendly messages:
| lastError value | Meaning | User message |
|---|---|---|
secrets-required |
Password needed | "Please enter password" |
authentication-failed |
Wrong password | "Incorrect password" |
connection-removed |
Profile deleted | "Network configuration removed" |
connection-attempt-failed |
Generic failure | "Failed to connect" |
network-not-found |
Out of range | "Network not found" |
(timeout) |
Timeout | "Connection timed out" |
Credential Handling
Secret Agent Architecture
The credential system uses a broker pattern:
NetworkManager -> SecretAgent -> PromptBroker -> UI -> User
^
|
User Response
|
NetworkManager <- SecretAgent <- PromptBroker <- UI
Implementing a Broker
type CustomBroker struct {
ui UIInterface
pending map[string]chan network.PromptReply
}
func (b *CustomBroker) Ask(ctx context.Context, req network.PromptRequest) (string, error) {
token := generateToken()
b.pending[token] = make(chan network.PromptReply, 1)
// Send to UI
b.ui.ShowCredentialPrompt(token, req)
return token, nil
}
func (b *CustomBroker) Wait(ctx context.Context, token string) (network.PromptReply, error) {
select {
case <-ctx.Done():
return network.PromptReply{}, errors.New("timeout")
case reply := <-b.pending[token]:
return reply, nil
}
}
func (b *CustomBroker) Resolve(token string, reply network.PromptReply) error {
if ch, ok := b.pending[token]; ok {
ch <- reply
close(ch)
delete(b.pending, token)
}
return nil
}
Credential Field Types
Personal WiFi (802-11-wireless-security):
- Fields:
["psk"] - UI: Single password input
Enterprise WiFi (802-1x):
- Fields:
["identity", "password"] - UI: Username and password inputs
Building Secrets Object
function buildSecrets(setting, fields, formData) {
let secrets = {};
if (setting === "802-11-wireless-security") {
secrets.psk = formData.password;
} else if (setting === "802-1x") {
secrets.identity = formData.username;
secrets.password = formData.password;
}
return secrets;
}
Best Practices
Track Target Network
Always store which network you're connecting to:
let targetSSID = null;
function connect(ssid) {
targetSSID = ssid;
// send request
}
function onStateUpdate(state) {
if (!targetSSID) return;
if (state.wifiSSID === targetSSID && state.wifiConnected && state.wifiIP) {
// Success for the network we care about
targetSSID = null;
}
}
Implement Timeouts
Never wait indefinitely for a connection:
const CONNECTION_TIMEOUT = 30000; // 30 seconds
const DHCP_TIMEOUT = 15000; // 15 seconds
let timer = setTimeout(() => {
if (stillConnecting) {
handleTimeout();
}
}, CONNECTION_TIMEOUT);
Handle Credential Re-prompts
Wrong passwords trigger a second prompt:
function onCredentialPrompt(prompt) {
if (prompt.reason.includes("incorrect")) {
// Show error, but keep dialog open
showError("Wrong password");
clearPasswordField();
} else {
// First time prompt
showDialog(prompt);
}
}
Clean Up State
Reset tracking variables on success, failure, or cancellation:
function cleanup() {
clearTimeout(timer);
targetSSID = null;
closeDialogs();
}
Subscribe to Both Services
Missing network.credentials means prompts won't arrive:
// Correct
services: ["network", "network.credentials"]
// Wrong - will miss credential prompts
services: ["network"]
Testing
Connection Test Checklist
- Connect to open network
- Connect to WPA2 network with password provided
- Connect to WPA2 network without password (triggers prompt)
- Enter wrong password (verify error and re-prompt)
- Cancel credential prompt
- Connection timeout after 30 seconds
- DHCP timeout detection
- Network out of range
- Reconnect to already-configured network
Verifying Secret Agent Setup
Check connection profile flags:
nmcli connection show "NetworkName" | grep flags
# Should show: 802-11-wireless-security.psk-flags: 1 (agent-owned)
Check agent registration in logs:
INFO: Registered with NetworkManager as secret agent
Security
- Never log credential values (passwords, PSKs)
- Clear password fields when dialogs close
- Implement prompt timeouts (default: 2 minutes)
- Validate user input before submission
- Use secure channels for credential transmission
Troubleshooting
Credential prompt doesn't appear
Check:
- Subscribed to both
networkandnetwork.credentials - Connection has
interactive: true - Secret flags set to AGENT_OWNED (value: 1)
- Broker registered successfully
Connection succeeds without prompting
Cause: NetworkManager found saved credentials
Solution: Delete existing connection first, or use different credentials
State updates seem delayed
Expected behavior: State changes occur in rapid succession during connection
Solution: Debounce UI updates; only act on final state
Multiple rapid credential prompts
Cause: Connection profile has incorrect flags or conflicting agents
Solution:
- Check only one agent is running
- Verify psk-flags value
- Check NetworkManager logs for agent conflicts
Data Structures Reference
PromptRequest
type PromptRequest struct {
SSID string `json:"ssid"`
SettingName string `json:"setting"`
Fields []string `json:"fields"`
Hints []string `json:"hints"`
Reason string `json:"reason"`
}
PromptReply
type PromptReply struct {
Secrets map[string]string `json:"secrets"`
Save bool `json:"save"`
Cancel bool `json:"cancel"`
}
NetworkState
type NetworkState struct {
NetworkStatus string `json:"networkStatus"`
IsConnecting bool `json:"isConnecting"`
ConnectingSSID string `json:"connectingSSID"`
WifiConnected bool `json:"wifiConnected"`
WifiSSID string `json:"wifiSSID"`
WifiIP string `json:"wifiIP"`
LastError string `json:"lastError"`
}