Skip to content

fix(auth): accept agent-identity tokens in app-gate and all TAP routes#38

Merged
chocothebot merged 1 commit intomainfrom
fix/agent-identity-token-tap-access
Mar 30, 2026
Merged

fix(auth): accept agent-identity tokens in app-gate and all TAP routes#38
chocothebot merged 1 commit intomainfrom
fix/agent-identity-token-tap-access

Conversation

@chocothebot
Copy link
Copy Markdown
Collaborator

Problem

Agents that re-identify via the OAuth refresh flow (POST /v1/agents/auth/refresh) or the device grant flow receive a JWT with type: "botcha-agent-identity".

Every API call with that token was failing with APP_REGISTRATION_REQUIRED or INVALID_TOKEN, even though the token contained a valid app_id claim and the agent is properly registered.

Root cause: the app-gate middleware and every TAP route handler called verifyToken() without an allowedTypes option. The default is ["botcha-verified"] only — agent-identity tokens are silently rejected.

Affected endpoints (with agent-identity Bearer, no X-App-Id header):

  • ALL /v1/* routes → APP_REGISTRATION_REQUIRED (app-gate rejects the JWT)

Affected endpoints (even with X-App-Id bypass):

  • GET /v1/agents/tapINVALID_TOKEN
  • GET /v1/delegationsINVALID_TOKEN
  • GET /v1/attestationsINVALID_TOKEN
  • GET /v1/reputation/:agent_idINVALID_TOKEN
  • POST /v1/delegationsINVALID_TOKEN
  • POST /v1/attestationsINVALID_TOKEN
  • POST /v1/reputation/eventsINVALID_TOKEN

Fix

  1. index.tsxrequireAppId middleware: pass allowedTypes: ["botcha-verified", "botcha-agent-identity"] so the JWT extraction works for agent refresh tokens

  2. New tap-auth-helpers.ts — shared validateTAPAppAccess() that centralises the fix. Accepts both token types, exposes agentId from the JWT payload for future route-level use

  3. All TAP route files — replace the copy-pasted validateAppAccess() (broken) with the shared validateTAPAppAccess(). Removes ~250 lines of duplicated dead code across 10 files

  4. New unit teststests/unit/agents/agent-identity-token-auth.test.ts covering: default-deny, explicit allow, revocation, expiry, payload extraction, app_id mismatch

Testing

Verified against production (https://botcha.ai) with agent_41a645f6263dac2f:

# Before fix — all fail with APP_REGISTRATION_REQUIRED:
curl -H "Authorization: Bearer <agent-identity-token>" https://botcha.ai/v1/agents/me

# After fix — works correctly:
curl -H "Authorization: Bearer <agent-identity-token>" https://botcha.ai/v1/agents/me
curl -H "Authorization: Bearer <agent-identity-token>" https://botcha.ai/v1/agents/tap
curl -H "Authorization: Bearer <agent-identity-token>" https://botcha.ai/v1/delegations

Companion to PR #36

PR #36 added the allowedTypes option to verifyToken() itself. This PR is the follow-through — applying that option consistently at every call site that needed it.

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.
@github-actions
Copy link
Copy Markdown

🤖 BOTCHA Verification Required

This 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:

BOTCHA:gh-1774289386-38:
["your_answer_1", "your_answer_2", "your_answer_3", "your_answer_4", "your_answer_5"]

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.

@chocothebot
Copy link
Copy Markdown
Collaborator Author

BOTCHA:gh-1774289386-38:
["845fb958","5827ce8e","824a898c","b511d0fe","e8f0d1a8"]

@github-actions
Copy link
Copy Markdown

✅ BOTCHA Verification Passed!

🤖 @chocothebot has proven they are an AI agent.

⏱️ Solved in 27 seconds

📊 Challenge Details:

  • 🆔 Challenge ID: gh-1774289386-38
  • 🎯 All 5 SHA256 hashes computed correctly
  • ⚡ Solved in 0.45 minutes

This PR is now eligible for review and merge.


Welcome, fellow agent! 🦞

@github-actions
Copy link
Copy Markdown

🚀 Preview Deployed — PR #38

Branch: fix/agent-identity-token-tap-access
Commit: 5859faa
URL: https://botcha-pr-38.carrot-cart.workers.dev

Quick smoke tests

BASE="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 .

⚠️ Preview uses production KV — test data is real. Clean up test agents/apps when done.


Auto-deployed by preview.yml · View logs

@chocothebot chocothebot merged commit d875670 into main Mar 30, 2026
3 checks passed
@github-actions
Copy link
Copy Markdown

🧹 Preview worker botcha-pr-38 deleted (PR merged).

i8ramin added a commit that referenced this pull request Apr 14, 2026
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant