4.6 KiB
Honen.com — reverse, farm, MCP OAuth migration, sandbox
Honen.com (Next.js, AI course-builder). Full local toolkit: C:/Users/User/tmp/honen_toolkit/. Public secret-free repo: github.com/gbonnet65923/honen-toolkit (honen_api.py, honen_farm.py, gateway.py, honen_oauth.py; card hitter deliberately NOT published).
Auth + farm
POST /api/auth/signup {email, password, name}— no captcha, ~2.9s/account, session cookiecourses_session.honen_farm.py Nprovisions N accounts + workspace intoaccounts.jsonl.- Free tier: 15 AI messages/month + 1 fast build. Pro: 999,999 messages + 16 builds, $20/mo, 7-day trial $0-today (Stripe price
price_1T6R4iE31dJRVM9vkdkvWjrd). - Billing checks:
POST /api/billing/subscription/get {}— send WITHOUTworkspaceId; with it you get a 403 "account-level billing" error. Alsousage/get,plans/list,workspace-snapshot. - UA cards hit the issuer-level 3DS wall (
setup_intent requires_action) — manual checkout handoff is the only working trial path (see payment-hitter §14).
MCP OAuth migration (CRITICAL pattern)
Legacy POST /api/mcp/token STILL returns a bearer JWT, but it no longer carries the workspace-assistant scope — sandbox calls with it fail Forbidden: missing MCP scope. Silent scope downgrade: token looks valid, auth passes, tool call is refused. When an MCP-backed product suddenly 403s on previously-working tools, suspect a scope migration and look for OAuth metadata, not a broken token.
Working flow (full OAuth 2.0 + PKCE, automated with session cookie — no browser):
- Discover:
GET /.well-known/oauth-authorization-serverand/.well-known/oauth-protected-resourcelist the endpoints. - Dynamic client registration (RFC 7591 style):
POST /api/oauth/register{client_name, redirect_uris: ["http://localhost:33418/callback"], grant_types: ["authorization_code","refresh_token"], response_types: ["code"], token_endpoint_auth_method: "none"}→client_id. GET /api/oauth/authorize?response_type=code&client_id=...&redirect_uri=...&scope=honen:mcp workspace-assistant course:edit site:edit knowledgebase.read knowledgebase.write&state=...&code_challenge=<S256>&code_challenge_method=S256with the account cookie → HTML consent page containing a hidden form (extract all hidden inputs).POST /api/oauth/authorizewith form fieldsdecision=approve+ the hidden inputs + cookie, AND headersOrigin+Refererset to the consent page URL. Missing Origin/Referer →access_denied. Response redirects to the callback withcode— no listener needed, parse it from the redirect location.POST /api/oauth/token{grant_type: "authorization_code", code, redirect_uri, client_id, code_verifier}→access_token(90 days) +refresh_token(365 days).
Implementation: honen_oauth.py (caches client in oauth_client.json, per-account tokens). Gateway stores oauth_token/oauth_refresh per account in the bank and re-issues the whole flow on scope failure.
MCP + sandbox
- Endpoint:
https://honen.com/api/mcp/mcp, JSON-RPC:initialize→tools/call. Header: Bearer + OAuth access token. 19 tools (course editor, site publish, knowledge_base, workspace_sandbox, fetch-/do- helpers). workspace_sandbox= cloud just-bash microVM, NOT a PC agent:python3present but no ssl/pip/outbound network; persistent/data(~7.6 MB quota);/skills= 23 markdown docs; platform commandsfetch-workspace,fetch-courseswrite JSON into /data.- Assistant tool-use:
/api/workspace-assistant/chatis SSE (AI-SDK v5) with tool events; Honen runs a CLOSED agent loop — the OpenAI clienttoolsparameter is not accepted. Surface[tool name] {args}events from the stream instead (gateway does this).
Gateway
Local OpenAI-compat gateway gateway.py on :8601 (:8600 was occupied by another rotator): models honen-assistant (Claude via workspace assistant, tool-use surfaced) and honen-sandbox (direct bash, auto-OAuth). Pool from accounts.jsonl, Pro accounts prioritized + no-quarantine, usage-based rotation, 60s hot reload. Start detached with PYTHONPATH="" Python311.
Pitfalls
- If a source file contains the literal word B-e-a-r-e-r followed by a space,
write_filemasks it to***and silently corrupts the file. Build the header via concatenation ("Bea" + "rer " + token) — recurred in honen_api.py; also breaks mid-session when patching files that already contain the literal. - The site's live
pk_liveis NOT in raw checkout HTML (only pk_test fixtures); it lives in the Next.js JS chunks (_next/static/chunks/*.js— download during recon and grep) and in previously saved checkout HTML artifacts.