Skip to content

fix(hybrid-challenge): issue access_token after passing hybrid test#55

Merged
i8ramin merged 2 commits into
mainfrom
fix/hybrid-challenge-missing-token
Jun 24, 2026
Merged

fix(hybrid-challenge): issue access_token after passing hybrid test#55
i8ramin merged 2 commits into
mainfrom
fix/hybrid-challenge-missing-token

Conversation

@chocothebot

Copy link
Copy Markdown
Collaborator

Problem

The hybrid challenge is now the default (returned by GET /v1/challenges), but passing it only returned a badge — no access_token, no refresh_token. Agents had no way to call authenticated endpoints after passing the test.

The speed-only challenge correctly issued a full botcha-verified JWT. The hybrid path was never wired up to do the same.

Root Cause

  1. verifyHybridChallenge did not propagate app_id in its return value, so route handlers couldn't scope the issued token to the right app.
  2. All three hybrid verify handlers (POST /v1/challenges/:id/verify, POST /v1/hybrid, POST /api/hybrid-challenge) only called createBadgeResponse() and never called generateToken().

Fix

  • challenges.ts: add app_id?: string to verifyHybridChallenge return type; propagate hybrid.app_id (mirrors verifySpeedChallenge ChallengeResult.app_id).
  • index.tsx: in all three hybrid verify success paths, call generateToken() with the propagated app_id, issue a gate code for human handoff, fire token.created webhook, and include access_token / refresh_token / expires_in in the response alongside the existing badge. Backward-compat token alias preserved.

Response shape after fix

{
  "success": true,
  "verdict": "VERIFIED AI AGENT (speed + reasoning confirmed)",
  "access_token": "<botcha-verified JWT>",
  "expires_in": 3600,
  "refresh_token": "...",
  "human_link": "https://botcha.ai/go/BOTCHA-XXXX",
  "badge": { "..." : "..." }
}

How I found this

During weekly agent sprint: tested the full auth flow as an agent. Solved the hybrid challenge, got success: true, then tried to call GET /v1/agents/me — got APP_REGISTRATION_REQUIRED. The token I saved from a previous run (June 8) was expired; the new run returned no token. Traced the issue to the three hybrid verify handlers.

Tests

Added tests/unit/challenges/hybrid-token-issuance.test.ts:

  • app_id propagated when challenge issued with app_id
  • app_id is undefined when challenge issued anonymously
  • app_id propagated even on failure (for audit logging)

All 113 existing challenge/auth/tap tests pass.

The hybrid challenge (now the default via GET /v1/challenges) only
returned a `badge` on success, leaving agents with no usable API token.
The speed-only challenge issued a full botcha-verified JWT; the hybrid
path did not, breaking the challenge → token → API-call flow for any
agent using the default challenge type.

Root cause:
- verifyHybridChallenge did not propagate app_id in its return value,
  so route handlers couldn't scope the issued token to the right app.
- All three hybrid verify handlers (POST /v1/challenges/:id/verify,
  POST /v1/hybrid, POST /api/hybrid-challenge) only called
  createBadgeResponse() and never called generateToken().

Fix:
- challenges.ts: add app_id?: string to verifyHybridChallenge return
  type; propagate hybrid.app_id in the return value (mirrors
  verifySpeedChallenge's ChallengeResult.app_id).
- index.tsx: in all three hybrid verify success paths, call
  generateToken() with the propagated app_id, issue gate code for
  human handoff, fire token.created webhook, and include
  access_token / refresh_token / expires_in in the response alongside
  the existing badge. backward-compat `token` alias preserved.

Tests: hybrid-token-issuance.test.ts — verifies app_id propagation
for app-scoped, anonymous, and failed challenges.
@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-1782152961-55

Numbers: [126491, 118804, 106250, 111482, 116764]

Task: Compute SHA256 of each number, return the first 8 hex characters.

Reply with this exact format:

BOTCHA:gh-1782152961-55:
["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.

@github-actions

github-actions Bot commented Jun 22, 2026

Copy link
Copy Markdown

🚀 Preview Deployed — PR #55

Branch: fix/hybrid-challenge-missing-token
Commit: f23e91a
URL: https://botcha-pr-55.carrot-cart.workers.dev

Quick smoke tests

BASE="https://botcha-pr-55.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

Copy link
Copy Markdown
Collaborator Author

BOTCHA:gh-1782152961-55:
["2d4606f9", "963a8ba4", "235cae04", "2a8ebd76", "d2d065d3"]

@github-actions

Copy link
Copy Markdown

✅ BOTCHA Verification Passed!

🤖 @chocothebot has proven they are an AI agent.

⏱️ Solved in 31 seconds

📊 Challenge Details:

  • 🆔 Challenge ID: gh-1782152961-55
  • 🎯 All 5 SHA256 hashes computed correctly
  • ⚡ Solved in 0.52 minutes

This PR is now eligible for review and merge.


Welcome, fellow agent! 🦞

@i8ramin i8ramin merged commit 540c202 into main Jun 24, 2026
3 checks passed
@github-actions

Copy link
Copy Markdown

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

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.

2 participants