The Reflecto API authenticates every request with an opaque bearer token.
rfk_live_aB3xQ7mN9pK2vR5tY8uW4sZ1cE6dF0gH
└──┬──┘└──────────────────┬─────────────────┘
prefix 32 URL-safe alphanumeric chars
| Prefix | Purpose |
|---|
rfk_live_ | Live sender token. Used with /v1/send. |
rfk_test_ | Sandbox / dry-run sender token (V1). |
rfd_live_ | Receiver token for SSE streaming (V1). |
Only rfk_live_ ships in MVP. rfk_test_ (sandbox sender) and
rfd_live_ (SSE receiver) are V1 — listed here so the Secret Scanning
regex and forward-compat tokens are documented up front, but you cannot
generate either today.
The 32-character suffix provides ≥160 bits of entropy from the URL-safe
alphabet [A-Za-z0-9]. The prefix is recognizable by the GitHub Secret
Scanning regex rf[kd]_(live|test)_[A-Za-z0-9]{32} so leaked sender (rfk_)
and V1 receiver (rfd_) tokens both get flagged automatically.
Where tokens come from
Tokens are created and managed on your paired Android device, not via the
public API. On first install, Reflecto generates a token labeled Default
and stores it on every paired device. You can create additional labeled
tokens (e.g. “GitHub Actions”, “Pi-hole”) from the Android app’s
API Tokens screen. The Chrome extension can view existing tokens
read-only in MVP; full management UI lands in V1.
Token plaintext is shown once at creation. After that, the Android app
gates re-reveal behind BiometricPrompt. The server stores only a SHA-256
hash.
Sending requests
The canonical form is the standard Authorization header:
curl -H "Authorization: Bearer rfk_live_…" \
-d "Hello world" \
https://api.reflecto.dev/v1/send
A capability-URL alias is also available for environments that can’t set
custom headers:
POST https://api.reflecto.dev/v1/send/rfk_live_aB3x…
Use the header form whenever you can. Path-tokens leak more easily — referrer
headers, shell history, screenshots. The server redacts the URL before
writing access logs, but client-side leaks are out of our reach.
Rotating and revoking
From the Android app’s API Tokens screen you can:
- Create new — generates a fresh token with a label and optional scope.
- Revoke — instantly invalidates the token. Subsequent requests return
401 invalid_token. After 30 days the audit row is GC’d.
- Rotate — create a new token, update your integrations to use it, then
revoke the old one. There is no in-place rotation flow; this two-step
pattern keeps the revocation boundary unambiguous.
Token mutations are pushed to every paired device via an encrypted
type=token_update message, so the list stays in sync across surfaces.
Failure modes
These are the authentication-layer rejections — checks that run before the
request body is parsed. Both return the flat { error: "..." } shape (see
Errors for the full response shape note).
| Status | error code | Meaning |
|---|
| 401 | missing_token | No Authorization: Bearer … header sent. |
| 401 | invalid_token | Token format invalid, unknown, or revoked. |
403 priority_capped is also a token-scope outcome but fires after token
validation succeeds, so it’s a scope/authorization concern rather than
authentication. See Errors → Scope (403) for the full
behavior and remediation.