Step Seven — Auth, without theatrics: Bearer + optional mTLS

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.pyDownload
  • 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.zipDownload (unchanged from Step Six).


What’s new (tight and precise)

  1. Auth modes (--auth-mode):
    • open — no auth (for development only).
    • protected (default) — bearer required for all endpoints except /health; /ui can be opened with --open-ui.
    • strict — bearer required for everything (including /ui, /health, SSE, metrics).
  2. 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).
  3. 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-Fingerprint when a client cert is present.
  4. 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.
  5. UI updated
    • Token box persists in localStorage.
    • All fetch calls include Authorization: Bearer….
    • SSE /events automatically appends ?access_token=….

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)

EndpointOpenProtected (default)Strict
/uiopenclosed (open with --open-ui)closed
/healthopenopenclosed
/events (SSE)openbearer requiredbearer required
/metricsopenbearer requiredbearer required
/read, /historyopenbearer requiredbearer required
/schemas, /validate, /plugins, /stateopenbearer requiredbearer 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 /health is open; /ui may be opened via --open-ui.
  • Bearer:--auth-token YOURLONGTOKEN; send Authorization: Bearer ….
    • SSE uses ?access_token=… automatically; disable by removing --allow-query-token.
  • 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-admin and --admin-token, plus bearer when auth mode ≠ open.
  • New: /authinfo reflects 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