A cryptographically-verified CF Access JWT (signature vs team JWKS + audience +
email allow-list) now counts as the owner, so browser requests through the CF
tunnel don't need the owner token copied onto each device. Fails closed → owner
token remains the fallback (LAN-direct + dev/tests unaffected). Opt-in via
CF_ACCESS_TEAM_DOMAIN / CF_ACCESS_AUD / CF_ACCESS_OWNER_EMAILS.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Owner bearer token was compared with === / !==, which short-circuits on the
first differing byte and leaks token length+prefix via response timing
(security-sweep-2026-06-01.md). New timingSafeStrEqual (crypto.timingSafeEqual
with a length pre-check so it never throws on length mismatch); wired into both
owner.js and agent_auth.js.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add lib/api/middleware/agent_auth.js: agentOrOwner accepts the owner
token (kind=user actor) or a hashed agent token (kind=agent actor
carrying capabilities + scopes). /api router now mounts this in place
of ownerOnly so agent tokens become first-class.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>