Initial commit: Alfred Proxy with OAuth, TTS, and FCM push notifications
- Environment-based configuration (no hardcoded secrets) - OAuth authentication via Authentik - ElevenLabs TTS integration via SAG CLI - FCM push notification support - User preferences sync system - Multi-user support with per-user context files - No internal IPs or service accounts in tracked files
This commit is contained in:
478
SETUP_COMPLETE.md
Normal file
478
SETUP_COMPLETE.md
Normal file
@@ -0,0 +1,478 @@
|
||||
# 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)
|
||||
Reference in New Issue
Block a user