# Alfred Proxy - Complete Setup Guide **Updated:** 2026-02-04 **Status:** ✅ Fully functional with FCM push notifications ## What This Is Alfred Proxy is an authentication and notification bridge that: 1. Validates OAuth tokens from the Alfred mobile app (via Authentik) 2. Injects OpenClaw gateway tokens (server-side, never exposed) 3. Sends Firebase Cloud Messaging push notifications to mobile devices 4. Persists FCM tokens across restarts for reliable alarm delivery ## Quick Start ### Prerequisites - Node.js 24+ installed - OpenClaw gateway running on localhost:18789 - Authentik OAuth provider configured - Firebase project with FCM enabled - Google Cloud service account with correct permissions ### 1. Install Dependencies ```bash cd ~/.openclaw/workspace/alfred-proxy npm install ``` ### 2. Configure Firebase (FCM) #### a. Create Service Account 1. Go to: https://console.cloud.google.com/iam-admin/serviceaccounts?project=YOUR_PROJECT_ID 2. Click "Create Service Account" 3. Name: `alfred-fcm-server` 4. Grant role: **Firebase Admin SDK Administrator Service Agent** - This role includes `cloudmessaging.messages.create` permission - Do NOT use "Firebase Cloud Messaging Admin" (legacy API) 5. Download JSON key #### b. Enable FCM API 1. Go to: https://console.cloud.google.com/apis/library/fcm.googleapis.com?project=YOUR_PROJECT_ID 2. Click "Enable" #### c. Place Service Account Key ```bash cp ~/Downloads/your-key.json service-account.json chmod 600 service-account.json ``` ### 3. Configure Environment ```bash # Copy example config cp .env.example .env # Edit with your settings nano .env ``` **Required settings:** ```bash PROXY_PORT=18790 OPENCLAW_URL=ws://127.0.0.1:18789 OPENCLAW_TOKEN=your-openclaw-token # From ~/.openclaw/openclaw.json AUTHENTIK_URL=https://auth.your-domain.com AUTHENTIK_CLIENT_ID=your-client-id REQUIRE_AUTH=true ``` ### 4. Start the Proxy **Development (auto-reload):** ```bash npm run dev ``` **Production (systemd service):** ```bash # Copy service file cp alfred-proxy.service ~/.config/systemd/user/ # Start and enable systemctl --user daemon-reload systemctl --user enable alfred-proxy.service systemctl --user start alfred-proxy.service # Check status systemctl --user status alfred-proxy.service ``` ### 5. Verify Setup ```bash # Check proxy is running curl http://localhost:18790/health # Expected: {"status":"ok","service":"alfred-proxy"} # Check logs tail -f /tmp/alfred-proxy.log # Look for: # [firebase] Firebase Admin SDK initialized # [alfred-proxy] Service started successfully ``` ### 6. Test FCM Notifications ```bash # Send test alarm ./alfred-notify --alarm "Test alarm!" # Check logs for success tail -f /tmp/alfred-proxy.log | grep fcm # Expected: [fcm] Successfully sent X message(s) ``` ## Features ### ✅ Working Features - **OAuth Authentication**: Validates Authentik tokens via userinfo endpoint - **Token Injection**: Injects OpenClaw gateway token server-side - **FCM Push Notifications**: Send notifications even when app is closed - **Token Persistence**: FCM tokens persist across proxy restarts (`fcm-tokens.json`) - **Dual Delivery**: WebSocket (if connected) + FCM (always) - **CLI Wrapper**: `alfred-notify` command for easy notification sending - **Auto-Reconnection**: App reconnects and re-registers FCM token automatically ### Notification Types - **Alarm**: High-priority, wakes device - **Alert**: Standard priority notification - **Silent**: Vibrate only or completely silent ## Usage ### Send Notification via CLI ```bash # Simple alarm ./alfred-notify --alarm "Wake up!" # Notification with custom title ./alfred-notify --title "Kitchen Timer" "Oven is ready" # Silent notification ./alfred-notify --no-sound --no-vibrate "Background task complete" ``` Run `./alfred-notify --help` for all options. ### Send Notification via HTTP API ```bash curl -X POST http://localhost:18790/api/notify \ -H "Content-Type: application/json" \ -d '{ "notificationType": "alarm", "title": "Test", "message": "This is a test alarm", "priority": "high", "sound": true, "vibrate": true }' ``` **Response:** ```json { "success": true, "clients": 1, // WebSocket clients notified "fcm": 1 // FCM devices notified } ``` ### Schedule Alarms with Cron Use OpenClaw's cron tool to schedule alarms: ```javascript // Example: 5 minute alarm { "name": "5 minute alarm", "schedule": { "kind": "at", "atMs": Date.now() + (5 * 60 * 1000) }, "payload": { "kind": "agentTurn", "message": "Run: alfred-notify --alarm '⏰ 5 minute alarm is up!'", "deliver": false }, "sessionTarget": "isolated" } ``` **Critical:** Always use `sessionTarget: "isolated"` + `agentTurn` for alarms. ## Monitoring ### Check Proxy Status ```bash systemctl --user status alfred-proxy.service ``` ### View Logs ```bash # Live tail tail -f /tmp/alfred-proxy.log # Check for FCM activity grep "fcm" /tmp/alfred-proxy.log | tail -20 # Check for errors grep "Error\|error" /tmp/alfred-proxy.log | tail -20 ``` ### Check Token Persistence ```bash cat fcm-tokens.json ``` Should show registered FCM tokens: ```json { "user-id-hash": [ "fcm-token-string" ] } ``` ### Monitor Notification Delivery ```bash # Send test ./alfred-notify "Test" # Check logs tail -f /tmp/alfred-proxy.log ``` Look for: ``` [notify] Broadcasting notification: type=alert title="Alfred" message="Test" [notify] Sent notification to X connected client(s) [fcm] Sending push notification to Y registered device(s) [fcm] Successfully sent Y message(s) ``` ## Troubleshooting ### Permission Denied Error **Error:** ``` [fcm] Error: Permission 'cloudmessaging.messages.create' denied ``` **Solution:** 1. Verify service account role is **Firebase Admin SDK Administrator Service Agent** - Go to: https://console.cloud.google.com/iam-admin/iam - Find service account: `alfred-fcm-server@...` - Should have role: `roles/firebase.sdkAdminServiceAgent` 2. Verify FCM API is enabled 3. Regenerate service account key if > 1 hour old 4. Restart proxy after updating key ### No Tokens Registered **Error:** ``` [fcm] No FCM tokens registered, skipping push notification ``` **Solution:** 1. Open Alfred mobile app 2. Verify connection (should show "Connected ✅") 3. Check logs for token registration: ``` [fcm] Registering token for user... [fcm] Saved tokens to disk ``` 4. Verify `fcm-tokens.json` file exists and has content ### Tokens Lost After Restart **This should NOT happen if setup is correct.** If tokens are lost: 1. Check `fcm-tokens.json` exists in proxy directory 2. Check file permissions: `chmod 600 fcm-tokens.json` 3. Verify logs show: `[fcm] Loaded X token(s) for Y user(s) from disk` 4. Check app sends token on every connection (should be automatic) ### OAuth Token Expired **Error:** ``` [auth] Authentik validation failed: 401 [proxy] Invalid OAuth token, rejecting connection ``` **Solution:** 1. App needs to implement token refresh (future fix) 2. For now: logout and login again in the app 3. Or disable auth temporarily: `REQUIRE_AUTH=false` in `.env` ### App Not Receiving Notifications **Checklist:** 1. ✅ Proxy running? `systemctl --user status alfred-proxy.service` 2. ✅ FCM tokens registered? `cat fcm-tokens.json` 3. ✅ Service account has correct role? Check IAM 4. ✅ FCM API enabled? Check APIs & Services 5. ✅ Test notification succeeds? `./alfred-notify "Test"` 6. ✅ Logs show success? `grep "Successfully sent" /tmp/alfred-proxy.log` If all checks pass but still no notifications: - Check app is installed and has notification permissions - Check device has network connectivity - Check Firebase Cloud Messaging isn't blocked by firewall - Try uninstall/reinstall app to get fresh FCM token ## Architecture ``` ┌──────────────────────┐ │ Alfred Mobile App │ │ (Android/OAuth) │ └──────────┬───────────┘ │ wss:// + OAuth token ▼ ┌──────────────────────┐ │ Alfred Proxy │ │ - Validate OAuth │ │ - Inject OpenClaw │ │ token │ │ - Store FCM tokens │ │ - Send FCM push │ └──────────┬───────────┘ │ ┌──────┴───────┐ │ │ ▼ ▼ ┌────────┐ ┌────────────┐ │OpenClaw│ │ Firebase │ │Gateway │ │ FCM │ │(local) │ └─────┬──────┘ └────────┘ │ ▼ ┌──────────────┐ │ Mobile Device│ │ (push notif) │ └──────────────┘ ``` ## Files & Directories ``` alfred-proxy/ ├── server.js # Main proxy server ├── alfred-notify # CLI wrapper for notifications ├── .env # Configuration (git-ignored) ├── service-account.json # Firebase credentials (git-ignored) ├── fcm-tokens.json # Persisted FCM tokens (git-ignored) ├── package.json # Dependencies ├── alfred-proxy.service # Systemd service file ├── README.md # Project overview ├── SETUP_COMPLETE.md # This file ├── FCM_SETUP.md # Firebase setup (see alfred-mobile/) └── /tmp/alfred-proxy.log # Runtime logs ``` ## Security ### Sensitive Files (Never Commit) - `.env` - Contains API tokens - `service-account.json` - Firebase credentials - `fcm-tokens.json` - User device tokens All added to `.gitignore`. ### Best Practices 1. **Restrict service account permissions**: Use minimal role (Firebase Admin SDK Administrator Service Agent) 2. **Rotate keys regularly**: Generate new service account key every 90 days 3. **File permissions**: `chmod 600` for sensitive files 4. **Network isolation**: OpenClaw runs on localhost only, not exposed 5. **OAuth validation**: All connections validated with Authentik before access ## Performance ### Resource Usage - **Memory**: ~50-100MB RSS - **CPU**: <1% idle, ~5% during notification bursts - **Network**: Minimal (WebSocket keepalives + FCM API calls) ### Scalability - Supports multiple connected devices simultaneously - FCM batch sending for efficiency - Token persistence reduces startup overhead ### Monitoring Monitor with: ```bash # Process stats ps aux | grep "node server.js" # Connection count ss -tn | grep :18790 | wc -l # Log size du -h /tmp/alfred-proxy.log ``` ## Updating ### Update Proxy Code ```bash cd ~/.openclaw/workspace/alfred-proxy git pull # If using git npm install # If dependencies changed systemctl --user restart alfred-proxy.service ``` ### Update Service Account Key ```bash # Download new key from Google Cloud Console cp ~/Downloads/new-key.json service-account.json chmod 600 service-account.json systemctl --user restart alfred-proxy.service # Verify tail -f /tmp/alfred-proxy.log | grep firebase # Should show: [firebase] Firebase Admin SDK initialized ``` ## Support & Documentation - **FCM Setup**: See `../alfred-mobile/FCM_SETUP.md` - **Agent Integration**: See `../alfred-mobile/AGENT_TOOLS.md` - **OpenClaw Docs**: https://docs.openclaw.ai - **Firebase Docs**: https://firebase.google.com/docs/cloud-messaging ## Version History ### 2026-02-04: FCM Token Persistence - Added token save/load to `fcm-tokens.json` - App sends token on every connection - Fixed Firebase IAM permissions (correct role) - Created `alfred-notify` CLI wrapper - Updated all documentation ### 2026-02-03: Initial Release - OAuth authentication via Authentik - OpenClaw token injection - Basic FCM notification support - WebSocket proxy functionality --- **Status**: ✅ Production Ready **Last Updated**: 2026-02-04 **Maintainer**: Josh (Shadow)