We harden the phone-native gateway while keeping it portable, auditable, and read‑only. You now have three layers of control:
- Bearer token (simple, effective on LAN)
- TLS (server cert)
- mTLS (client cert required, with optional fingerprint allowlist)
✅ Fresh artifact
- solveforce_phone_seven.py — Download
- SHA‑256:
01fdf8c10ed5359d1db8e1eceae44b08aad7418bf4ea57a47a90b239a261d1e5
Step Seven consolidates all prior steps (1–6) and layers auth. Keep your Step Six plugin pack as-is:
solveforce_step6_plugins.zip — Download (unchanged from Step Six).
What’s new (tight and precise)
- Auth modes (
--auth-mode):open— no auth (for development only).protected(default) — bearer required for all endpoints except/health;/uican be opened with--open-ui.strict— bearer required for everything (including/ui,/health, SSE, metrics).
- Bearer tokens
- Supply one or more:
--auth-token TOKEN(repeatable or comma-separated). - Header:
Authorization: Bearer <TOKEN> - Also supports
?access_token=(on by default) for endpoints that can’t send headers (SSE). Disable by omitting--allow-query-token(it’s enabled by default).
- Supply one or more:
- TLS + mTLS(stdlib ssl)
- TLS server:
--tls-cert server.crt --tls-key server.key. - mTLS (client cert required): add
--tls-ca ca.crt --mtls-require. - Optional fingerprint allowlist:
--mtls-allow-fp <sha256>(repeatable / comma-separated). - The server returns
X-Client-Fingerprintwhen a client cert is present.
- TLS server:
- New helper endpoint
GET /authinfo→ returns current auth mode, whether UI is open, whether query‑token is allowed, whether mTLS is required, count of allowed fingerprints, and (if present) the caller’s client‑cert SHA‑256.
- UI updated
- Token box persists in
localStorage. - All
fetchcalls includeAuthorization: Bearer…. - SSE
/eventsautomatically appends?access_token=….
- Token box persists in
Everything else remains: schemas & validation, JSONL exports, history ring buffer, SSE events, dynamic plugins & scaffolder, Prometheus metrics, read‑only posture.
Termux (Android) — secure launch patterns
A) Bearer + HTTP (LAN)
python solveforce_phone_seven.py \
--host 0.0.0.0 --port 8080 --poll 5 \
--plugins-dir ~/solveforce/plugins \
--history-size 512 \
--auth-mode protected \
--auth-token YOURLONGTOKEN \
--allow-admin --admin-token ADMIN123
Open: http://PHONE_IP:8080/ui
Paste the token in the UI (top card) → “Save token”.
B) TLS (self‑signed) + Bearer
# Create self-signed server cert (Termux requires openssl)
pkg install -y openssl
openssl req -x509 -newkey rsa:2048 -nodes -days 365 \
-keyout server.key -out server.crt -subj "/CN=phone.local"
Run:
python solveforce_phone_seven.py \
--host 0.0.0.0 --port 8443 \
--tls-cert server.crt --tls-key server.key \
--auth-mode strict \
--auth-token YOURLONGTOKEN
Open: https://PHONE_IP:8443/ui (accept the cert, paste token).
C) mTLS + Bearer (CA‑signed clients)
Create a CA, server cert, and client cert:
# 1) CA
openssl genrsa -out ca.key 4096
openssl req -x509 -new -key ca.key -sha256 -days 3650 \
-out ca.crt -subj "/CN=Ron SolveForce CA"
# 2) Server (CN and SANs matching your host/IP)
openssl genrsa -out server.key 2048
openssl req -new -key server.key -out server.csr -subj "/CN=phone.local"
cat > server.ext <<'EOF'
subjectAltName=DNS:phone.local,IP:127.0.0.1,IP:192.168.1.10
EOF
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
-out server.crt -days 825 -sha256 -extfile server.ext
# 3) Client
openssl genrsa -out client.key 2048
openssl req -new -key client.key -out client.csr -subj "/CN=ron-phone-client"
openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
-out client.crt -days 825 -sha256
# 4) Client fingerprint (for allowlist)
openssl x509 -in client.crt -noout -fingerprint -sha256 \
| cut -d= -f2 | tr -d ':'
# Copy the 64-hex fingerprint to <FP>
Run the gateway with mTLS + fingerprint allowlist:
python solveforce_phone_seven.py \
--host 0.0.0.0 --port 8443 \
--tls-cert server.crt --tls-key server.key \
--tls-ca ca.crt --mtls-require \
--mtls-allow-fp <FP> \
--auth-mode strict \
--auth-token YOURLONGTOKEN
Client curl example:
curl --cert client.crt --key client.key \
-H "Authorization: Bearer YOURLONGTOKEN" \
https://PHONE_IP:8443/health
Route matrix (truth table)
| Endpoint | Open | Protected (default) | Strict |
|---|---|---|---|
/ui | open | closed (open with --open-ui) | closed |
/health | open | open | closed |
/events (SSE) | open | bearer required | bearer required |
/metrics | open | bearer required | bearer required |
/read, /history | open | bearer required | bearer required |
/schemas, /validate, /plugins, /state | open | bearer required | bearer required |
/admin/* | closed unless --allow-admin and --admin-token provided; also requires bearer if auth mode ≠ open |
SSE can’t send headers; the UI appends
?access_token=. If you disable query tokens for hardline posture, use an SSE proxy that injects headers.
Security stance (frank and minimal)
- Default is “protected”. Health is open for liveness checks. All else is locked behind bearer unless you explicitly open
/ui. - mTLS is real security. Strong identity at the transport layer; use fingerprint allowlists when you need exact client pinning.
- No cookies, no sessions. Simplicity keeps the surface area small and auditable.
- Read‑only forever. This is a telescope, not a joystick.
WordPress — Step Seven section (drop‑in)
Step Seven — Auth (Bearer + mTLS)
- Modes:
open|protected(default) |strict.protected: Only/healthis open;/uimay be opened via--open-ui.
- Bearer:
--auth-token YOURLONGTOKEN; sendAuthorization: Bearer ….- SSE uses
?access_token=…automatically; disable by removing--allow-query-token.
- SSE uses
- TLS:
--tls-cert server.crt --tls-key server.key(stdlib). - mTLS:
--tls-ca ca.crt --mtls-require; optionally--mtls-allow-fp <sha256>to pin client certs. - Admin:
/admin/*needs--allow-adminand--admin-token, plus bearer when auth mode ≠open. - New:
/authinforeflects the current posture and the caller fingerprint (if any). - Philosophy: Identity at the edge, truth in the log (JSONL), structure in the schema, memory in RAM (history), action nowhere (read‑only).
Integrity (publish these)
sha256sum solveforce_phone_seven.py
# 01fdf8c10ed5359d1db8e1eceae44b08aad7418bf4ea57a47a90b239a261d1e5
sha256sum solveforce_step6_plugins.zip
# 04f364287c38cbe3d9f9f7ae468e0f923e8ad289d886076daa6a4d4d89ee4a6b
If/when you want Step Eight
- Pluggable auth backends: multiple tokens per role, time‑boxed tokens, or a stateless signed token with exp/nbf/roles.
- Rate limiting: sliding window per IP/token.
- Access policies: per‑plugin allowlist (fine‑grained “who can read what”).
Say the word, and I’ll cut it cleanly—no ceremony, maximum clarity.
Step Eight — Roles, Signed Tokens, Rate Limits, and Per‑Plugin Policy – SolveForce Communications