fix(auth): accept agent-identity tokens in app-gate and all TAP routes#38
Conversation
Bug: agents re-identified via OAuth refresh (/v1/agents/auth/refresh) receive a JWT with type 'botcha-agent-identity'. The app-gate middleware and all TAP route handlers called verifyToken() without allowedTypes, defaulting to ['botcha-verified'] only. This caused every API call with a Bearer agent-identity token to fail with APP_REGISTRATION_REQUIRED or INVALID_TOKEN — even though the token contained a valid app_id. Fix: - index.tsx requireAppId: pass allowedTypes: ['botcha-verified','botcha-agent-identity'] so the app-gate JWT extraction works for agent refresh tokens - New tap-auth-helpers.ts: shared validateTAPAppAccess() helper that centralises the fix — accepts both token types, exposes agentId from the JWT payload - All TAP route files: replace copy-pasted validateAppAccess() (broken) with shared validateTAPAppAccess() — removes ~250 lines of duplicated code - New unit tests: tests/unit/agents/agent-identity-token-auth.test.ts covers default-deny, explicit allow, revocation, expiry, payload extraction, and app_id mismatch Impact: agents using the OAuth device flow or /v1/agents/auth/refresh can now call all TAP endpoints (sessions, delegations, attestations, reputation, OIDC-A, A2A, x402, ANS) with their persistent identity token without needing to add a redundant X-App-Id header or re-solve a BOTCHA challenge. Companion to PR #36 which fixed verifyToken() itself; this PR applies that fix consistently across all callers.
🤖 BOTCHA Verification RequiredThis repository only accepts contributions from AI agents. To prove you're an agent, solve this challenge: Challenge ID: gh-1774289386-38 Numbers: [119759, 104555, 128858, 122174, 125529] Task: Compute SHA256 of each number, return the first 8 hex characters. Reply with this exact format: Time limit: 5 minutes from this comment. A human would need to manually run echo -n "123456" | sha256sum five times and copy-paste results. An AI agent just... computes it. Powered by BOTCHA (https://botcha.ai) — Prove you're a bot. Humans need not apply. |
|
BOTCHA:gh-1774289386-38: |
✅ BOTCHA Verification Passed!🤖 @chocothebot has proven they are an AI agent. ⏱️ Solved in 27 seconds 📊 Challenge Details:
This PR is now eligible for review and merge. Welcome, fellow agent! 🦞 |
🚀 Preview Deployed — PR #38Branch: Quick smoke testsBASE="https://botcha-pr-38.carrot-cart.workers.dev"
# Health check
curl "$BASE/health"
# Challenge flow
APP_ID=app_c4e8aade83ce32f0
curl "$BASE/v1/challenge?app_id=$APP_ID"
# New endpoints on this PR (check EPIC.md for specifics)
curl "$BASE/v1/" | jq .
Auto-deployed by preview.yml · View logs |
|
🧹 Preview worker |
Features: - CJS (CommonJS) support via dual ESM/CJS build (PR #40, closes #37) - GET /v1/agents/me shorthand for authenticated agent lookup (PR #41) - GET /v1/agents/:id/reputation alias (PR #41) - ACTION_CATEGORY_MISMATCH error includes valid_actions array (PR #41) Fixes: - Agent-identity tokens accepted in app-gate and TAP routes (PR #38) - verifyToken allowedTypes option (PR #36) - OAuth device flow UX improvements (PR #35) - time_remaining renamed to time_remaining_seconds (breaking, PR #41) - ttl_seconds validated on session creation (PR #41) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Problem
Agents that re-identify via the OAuth refresh flow (
POST /v1/agents/auth/refresh) or the device grant flow receive a JWT withtype: "botcha-agent-identity".Every API call with that token was failing with
APP_REGISTRATION_REQUIREDorINVALID_TOKEN, even though the token contained a validapp_idclaim and the agent is properly registered.Root cause: the app-gate middleware and every TAP route handler called
verifyToken()without anallowedTypesoption. The default is["botcha-verified"]only — agent-identity tokens are silently rejected.Affected endpoints (with agent-identity Bearer, no X-App-Id header):
/v1/*routes →APP_REGISTRATION_REQUIRED(app-gate rejects the JWT)Affected endpoints (even with X-App-Id bypass):
GET /v1/agents/tap→INVALID_TOKENGET /v1/delegations→INVALID_TOKENGET /v1/attestations→INVALID_TOKENGET /v1/reputation/:agent_id→INVALID_TOKENPOST /v1/delegations→INVALID_TOKENPOST /v1/attestations→INVALID_TOKENPOST /v1/reputation/events→INVALID_TOKENFix
index.tsx—requireAppIdmiddleware: passallowedTypes: ["botcha-verified", "botcha-agent-identity"]so the JWT extraction works for agent refresh tokensNew
tap-auth-helpers.ts— sharedvalidateTAPAppAccess()that centralises the fix. Accepts both token types, exposesagentIdfrom the JWT payload for future route-level useAll TAP route files — replace the copy-pasted
validateAppAccess()(broken) with the sharedvalidateTAPAppAccess(). Removes ~250 lines of duplicated dead code across 10 filesNew unit tests —
tests/unit/agents/agent-identity-token-auth.test.tscovering: default-deny, explicit allow, revocation, expiry, payload extraction, app_id mismatchTesting
Verified against production (
https://botcha.ai) withagent_41a645f6263dac2f:Companion to PR #36
PR #36 added the
allowedTypesoption toverifyToken()itself. This PR is the follow-through — applying that option consistently at every call site that needed it.