Authentication API
Secure access to your Wala Works devices with token-based authentication.
Overview
Wala Works devices support optional Bearer token authentication for API endpoints. When enabled, all API requests must include a valid authentication token.
Default state: Authentication is disabled for easy setup.
Authentication Flow
Client Request
↓
Include: Authorization: Bearer TOKEN
↓
Device validates token
↓
├─ Valid → Process request
└─ Invalid → Return 401 Unauthorized
Enabling Authentication
Via Web Interface
- Navigate to device settings
- Security → API Authentication
- Toggle "Enable Authentication"
- Click "Generate Token"
- Copy and save token securely
Via API (Before Enabling)
# Enable authentication and get initial token
curl -X POST http://192.168.1.100/api/auth/enable \
-H "Content-Type: application/json" \
-d '{
"enabled": true,
"token_name": "admin"
}'
Response:
{
"success": true,
"enabled": true,
"token": "ww_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6",
"token_name": "admin",
"created": "2025-11-05T14:30:00Z",
"expires": null
}
⚠️ Important: Save this token immediately. It cannot be retrieved later.
Using Authentication
HTTP Headers
Include the Bearer token in the Authorization header:
curl -H "Authorization: Bearer ww_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6" \
http://192.168.1.100/api/status
Request Examples
MotorWala with authentication:
# Get status
curl -H "Authorization: Bearer YOUR_TOKEN" \
http://192.168.1.100/api/status
# Open motor
curl -X POST \
-H "Authorization: Bearer YOUR_TOKEN" \
http://192.168.1.100/api/motor/open
# Set position
curl -X POST \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"position": 50}' \
http://192.168.1.100/api/motor/position
RelayWala with authentication:
# Turn on relay
curl -X POST \
-H "Authorization: Bearer YOUR_TOKEN" \
http://192.168.1.101/api/relay/1/on
# Get status
curl -H "Authorization: Bearer YOUR_TOKEN" \
http://192.168.1.101/api/status
Token Management
Generate New Token
# Requires existing valid token
curl -X POST http://192.168.1.100/api/auth/token \
-H "Authorization: Bearer ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "home-assistant",
"expires": "2026-12-31T23:59:59Z"
}'
Response:
{
"success": true,
"token": "ww_b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7",
"name": "home-assistant",
"created": "2025-11-05T14:30:00Z",
"expires": "2026-12-31T23:59:59Z"
}
List Active Tokens
curl -H "Authorization: Bearer ADMIN_TOKEN" \
http://192.168.1.100/api/auth/tokens
Response:
{
"tokens": [
{
"id": "1",
"name": "admin",
"created": "2025-01-15T10:00:00Z",
"last_used": "2025-11-05T14:28:00Z",
"expires": null,
"is_admin": true
},
{
"id": "2",
"name": "home-assistant",
"created": "2025-02-01T12:00:00Z",
"last_used": "2025-11-05T14:29:00Z",
"expires": "2026-12-31T23:59:59Z",
"is_admin": false
},
{
"id": "3",
"name": "node-red",
"created": "2025-03-10T09:00:00Z",
"last_used": "2025-11-04T20:15:00Z",
"expires": "2025-12-31T23:59:59Z",
"is_admin": false
}
]
}
Revoke Token
# Revoke by token ID
curl -X DELETE http://192.168.1.100/api/auth/token/2 \
-H "Authorization: Bearer ADMIN_TOKEN"
Response:
{
"success": true,
"message": "Token 'home-assistant' revoked"
}
Token Properties
{
"name": "string", // Human-readable name
"expires": "datetime", // ISO 8601 or null (never)
"is_admin": boolean, // Can manage other tokens
"permissions": [] // Optional: granular permissions
}
Token Permissions
Admin Tokens
Full access to all endpoints including token management:
{
"name": "admin",
"is_admin": true,
"permissions": ["*"]
}
Standard Tokens
Access to device control, no token management:
{
"name": "home-assistant",
"is_admin": false,
"permissions": ["read", "control"]
}
Read-Only Tokens
Status monitoring only:
{
"name": "dashboard",
"is_admin": false,
"permissions": ["read"]
}
Create read-only token:
curl -X POST http://192.168.1.100/api/auth/token \
-H "Authorization: Bearer ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "dashboard",
"permissions": ["read"]
}'
Integration Examples
Home Assistant
Using REST commands:
# secrets.yaml
motorwala_token: "ww_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6"
# configuration.yaml
rest_command:
open_blinds:
url: "http://192.168.1.100/api/motor/open"
method: POST
headers:
Authorization: !secret motorwala_token
close_blinds:
url: "http://192.168.1.100/api/motor/close"
method: POST
headers:
Authorization: !secret motorwala_token
Using REST sensor:
sensor:
- platform: rest
name: "Blinds Position"
resource: "http://192.168.1.100/api/status"
headers:
Authorization: "Bearer ww_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6"
value_template: "{{ value_json.position }}"
scan_interval: 10
Node-RED
HTTP Request node configuration:
{
"method": "POST",
"url": "http://192.168.1.100/api/motor/open",
"headers": {
"Authorization": "Bearer ww_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6"
}
}
Function node to add auth:
msg.headers = {
"Authorization": "Bearer ww_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6"
};
return msg;
Python
import requests
TOKEN = "ww_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6"
BASE_URL = "http://192.168.1.100/api"
headers = {
"Authorization": f"Bearer {TOKEN}",
"Content-Type": "application/json"
}
# Get status
response = requests.get(f"{BASE_URL}/status", headers=headers)
print(response.json())
# Control motor
response = requests.post(
f"{BASE_URL}/motor/position",
headers=headers,
json={"position": 75}
)
print(response.json())
Node.js
const axios = require('axios');
const TOKEN = 'ww_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6';
const BASE_URL = 'http://192.168.1.100/api';
const headers = {
'Authorization': `Bearer ${TOKEN}`,
'Content-Type': 'application/json'
};
// Get status
async function getStatus() {
const response = await axios.get(`${BASE_URL}/status`, { headers });
console.log(response.data);
}
// Control motor
async function setPosition(position) {
const response = await axios.post(
`${BASE_URL}/motor/position`,
{ position },
{ headers }
);
console.log(response.data);
}
getStatus();
setPosition(75);
curl with Environment Variable
# Set token in environment
export WALA_TOKEN="ww_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6"
# Use in requests
curl -H "Authorization: Bearer $WALA_TOKEN" \
http://192.168.1.100/api/status
MQTT Authentication
MQTT uses separate username/password authentication:
Device configuration:
MQTT:
Username: wala-devices
Password: secure-mqtt-password
TLS: Optional
Broker configuration (Mosquitto):
# /etc/mosquitto/mosquitto.conf
allow_anonymous false
password_file /etc/mosquitto/passwd
Create password:
sudo mosquitto_passwd -c /etc/mosquitto/passwd wala-devices
# Enter password when prompted
Home Assistant MQTT configuration:
mqtt:
broker: 192.168.1.50
username: wala-devices
password: !secret mqtt_password
Security Best Practices
Token Storage
✅ Do:
- Store tokens in secrets management
- Use environment variables
- Encrypt configuration files
- Use separate tokens per integration
❌ Don't:
- Hardcode tokens in scripts
- Commit tokens to version control
- Share tokens publicly
- Reuse tokens across devices
Token Rotation
Periodically regenerate tokens:
# Generate new token
NEW_TOKEN=$(curl -X POST http://192.168.1.100/api/auth/token \
-H "Authorization: Bearer $OLD_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "home-assistant", "expires": "2026-12-31"}' \
| jq -r '.token')
# Update integrations with new token
# ...
# Revoke old token
curl -X DELETE http://192.168.1.100/api/auth/token/OLD_ID \
-H "Authorization: Bearer $OLD_TOKEN"
Network Security
Layer security practices:
-
Network Segmentation
- IoT VLAN for devices
- Firewall rules between networks
-
HTTPS (Optional)
- Enable TLS for encrypted communication
- Use valid certificates
-
VPN Access
- Access home network via VPN
- No direct internet exposure
-
Firewall Rules
# Only allow local network access iptables -A INPUT -s 192.168.1.0/24 -p tcp --dport 80 -j ACCEPT iptables -A INPUT -p tcp --dport 80 -j DROP
Error Responses
401 Unauthorized
Missing or invalid token:
{
"error": "Unauthorized",
"message": "Missing or invalid authentication token"
}
Causes:
- Token not provided
- Token invalid/expired
- Token revoked
- Authentication disabled but token sent
403 Forbidden
Token valid but insufficient permissions:
{
"error": "Forbidden",
"message": "Insufficient permissions for this operation"
}
Causes:
- Read-only token attempting control
- Non-admin token attempting token management
429 Too Many Requests
Rate limit exceeded:
{
"error": "Too Many Requests",
"message": "Rate limit exceeded. Try again in 60 seconds"
}
Disabling Authentication
Via API
# Requires admin token
curl -X POST http://192.168.1.100/api/auth/disable \
-H "Authorization: Bearer ADMIN_TOKEN"
Via Web Interface
- Settings → Security → API Authentication
- Toggle "Disable Authentication"
- Confirm action
Emergency Disable
If locked out, use serial console:
# Connect via USB
screen /dev/ttyUSB0 115200
# In serial console
> auth disable
Authentication disabled
Troubleshooting
Token not working:
- Verify token is correct (no extra spaces)
- Check "Authorization: Bearer " prefix
- Ensure authentication is enabled
- Check token hasn't expired
- Verify token hasn't been revoked
Can't generate tokens:
- Ensure you're using admin token
- Check token expiry format (ISO 8601)
- Verify network connectivity
- Review device logs
Locked out of device:
- Use serial console to disable auth
- Or perform factory reset (loses all settings)
- Backup tokens before enabling auth
Next Steps
- Controllers API - Control endpoints
- Sensors API - Monitoring endpoints
- Configuration - Security settings
Security questions? Check FAQ or contact support
Previous
—
Next
—