Files
autoreg-skills-max/skills/ai-provider-autoreg/references/laravel-oauth-bypass-and-nextjs-native-turnstile.md

11 KiB
Raw Blame History

Laravel OAuth-bypass + Next.js native-Turnstile registration patterns

Two reusable flows proven on small free-credit API providers (cleanapis.com, terrapolis.xyz, abhibots/opus). Scripts of record: C:/Users/User/tmp/freeapi_3pack/ca_mass_gh.py (Laravel/GitHub-OAuth) and terr_full.py (Next.js/native-Turnstile + voidash verify). Reuse C:/Users/User/tmp/regfarm/github_oauth/gh_http.py (GHSession.login, GHSession.oauth_code(client_id, state, scope=...)).

Pattern A — Laravel + CF Turnstile: bypass via GitHub OAuth (preferred)

When a Laravel site's email registration is Turnstile-gated AND server-side siteverify rejects solver tokens, do NOT fight the captcha — check /register page for /auth/github/redirect / /auth/google/redirect links. OAuth paths are almost never captcha-gated.

Flow (cleanapis.com, generalized):

  1. GET /auth/github/redirect (no follow) → parse state from the Location header's GitHub authorize URL. Also note client_id from that URL (cleanapis: Ov23li48tsmVvDWqWfhs, scope user:email,read:user).
  2. GHSession(bind=False).login(login, password, totp) on a pooled GH account → oauth_code(client_id, state, scope=...) → authorization code.
  3. GET /auth/github/callback?code=...&state=... in the SAME requests.Session that fetched the redirect (session cookie carries the state).
  4. Activate free plan if the site gates keys behind a plan: cleanapis = GET /dashboard/get-started?plan=starter → extract _token → POST /dashboard/billing/checkout/4 with {_token, billing_cycle: monthly, payment_method: paddle, coupon_code: ''}. Pitfall: omitting billing_cycle or payment_method returns to the same page with <li> validation errors — read them from the response body, they are the API contract.
  5. Create key: POST /dashboard/api-keys with {_token, name, scopes[]: [inference, models:read, embeddings]}.
  6. Reveal: key IDs in the response HTML are inside JS-escaped strings (api-keys\/63476\/reveal) — a strict api-keys/(\d+)/reveal regex misses them. Use re.findall(r'api-keys.{0,4}?(\d{4,7}).{0,4}?reveal', html) and take max(ids, key=int) for the newest. Then GET /dashboard/api-keys/{id}/reveal with Accept: application/json → {"ok":true,"key":"cc_..."}.
  7. Verify: GET /v1/models + one chat completion with Authorization: Bearer <key>. Pitfall: a just-revealed key can answer Invalid or revoked API key for a short propagation window — re-test after a minute before marking the account dead. Also fetch the model list from /v1/models instead of guessing model IDs (claude-haiku-4-5 404'd; the catalog was claude-opus-5, claude-sonnet-5, claude-fable-5.1, etc.).

Pacing/limits:

  • Key creation is rate-limited: 429 after rapid consecutive creates. Sleep 20–35 s between accounts; on 429 sleep ~90 s and retry the same account (plan activation already succeeded — only the key step needs redo).
  • Keep a used_gh.txt of consumed GH logins; GH pool C:/Users/User/tmp/gh_accounts.json (~672). OAuth code exchange is per GitHub app, so state fail: 429 waves (known from the new-api relay farm) can also hit here — pace and re-enter later.
  • Email+Turnstile path on cleanapis is a dead end: both 2captcha-remote tokens and sidecar real_page tokens POSTed from a separate requests session get Security verification failed. Only full in-browser submission could work — OAuth is cheaper.

Pattern B — Next.js server-action form + NATIVE Turnstile (terrapolis.xyz)

Signs: registration HTML has <input type="hidden" name="$ACTION_REF_1">, $ACTION_1:0 (JSON with action id), $ACTION_KEY, and fields name/email/password/captcha.

  1. Raw HTTP POST of the server-action form (multipart or form-encoded, with or without Next-Action header) returns 500 with an RSC E{"digest":...} error — the action expects the real RSC/Next runtime. Don't reverse it; drive a browser.
  2. Use cloakbrowser: b = cloakbrowser.launch(headless=True, proxy=px) (sync API is cloakbrowser.launch, NOT cloakbrowser.sync_api.sync_playwright — that module doesn't exist; the sidecar's own code imports cloakbrowser directly). pg = b.new_page().
  3. The page renders Turnstile ITSELF (window.turnstile present, input[name=captcha] auto-fills, submit button un-disables). Wait for document.querySelector('input[name=captcha]').value.length > 100 (~6 s on a clean IP). Injecting an externally solved token into the hidden input fails server-side ("Проверка Cloudflare не прошла или истекла") — native resolution is required; the sidecar's real_page route works only because it solves inside its own page context.
  4. Submit via real click, then detect success by URL change (/verify-email), not by absence of error text — the page keeps showing marketing copy.
  5. IP limit: 3 accounts per IP per 30 days (error text says so). Rotate proxies, ≤2 accounts per proxy.
  6. Proxy pre-filter is mandatory: HTTP-reachability ≠ Turnstile-capable. Of ~25 "live" proxies only ~5 completed the native Turnstile (others: goto timeouts, ERR_CERT_AUTHORITY_INVALID, widget never tokens). Filter by actually launching cloakbrowser through each proxy and waiting for the captcha token (see terr_px_filter.py).
  7. Email verify via voidash (no IMAP needed): POST https://api.voidash.com/api/v1/inboxes {"domain":"voidash.bond"} → {address, session_key}. Read mail at GET https://api.voidash.com/api/v1/messages with Authorization: Bearer <session_key> — the per-inbox path /inboxes/{addr}/messages returns 404 "inbox not found". Poll for https://terrapolis.xyz/verify?token=... in the JSON body (unescape \/), open it in the browser, expect "Почта подтверждена".
  8. Browser stability: wrap goto + wait_for_selector in a 3-attempt retry that closes and reopens the page — headless sessions intermittently fail to render the form; a fresh page fixes it.

Pattern C — Google-OAuth-only sites (abhibots/opus)

No email registration endpoint exists. GET /api/auth/google/signin 307-redirects to accounts.google.com/o/oauth2/auth?client_id=...&prompt=select_account. FastAPI-style backend ({"detail":"Method Not Allowed"} on wrong verbs). Requires a logged-in Google account pool to automate — skip unless one exists.

Pattern B2 — raw Next-Action HTTP POST + native CDP Turnstile harvest (vani.ai)

Contrast with Pattern B (raw POST → 500 digest): some Next.js App Router sites DO accept server actions over plain HTTP. Probe before launching any browser: POST to the page URL with headers Next-Action: <actionId> (ids live in the page bundle as createServerReference("<id>",...)), Accept: text/x-component, Origin/Referer of the site, multipart body with 1_-prefixed fields (1_email, 1_turnstile_token, 1_next) plus a trailer field 0 = ["$K1",true]. A structurally accepted call returns an RSC payload containing a line 1:{"status":...} — parse the state from there (^1:(\{.*?\})$ MULTILINE). 500 with E{"digest"...} = action needs the real RSC runtime → fall back to Pattern B browser drive.

Native Turnstile token harvest without cloakbrowser or paid solvers ($0): launch real Chrome --remote-debugging-port=N --remote-allow-origins=* --user-data-dir=<fresh> → CDP Target.createBrowserContext → createTarget(loginURL) → attachToTarget{flatten:true} → poll typeof window.turnstile == 'object' → Runtime.evaluate a Promise that calls window.turnstile.render(detachedDiv, {sitekey, action:'signup', theme:'auto', size:'flexible', callback}) → token (~750 chars, ~6 s). Order pitfall: render the widget BEFORE filling form inputs — a pre-filled email state can reset/block the widget on some pages. Proxy runs: add --proxy-server=http://host:port; if window.turnstile never appears through a proxy, that proxy drops the challenges script — pre-filter proxies by widget presence, not by HTTP reachability.

Backend-outage diagnosis (saves solver credits and hours): if structurally valid NATIVE tokens are rejected with the same generic error ("temporarily unavailable", "security check didn't pass") from a clean IP AND several country proxies AND different mailbox domains AND all widget action variants (signup/login/signin/verify), the failure is server-side (their siteverify secret or email provider is dead) — not your token, IP, or mail. Check their status page and recent incident reports, STOP brute-forcing, and deploy a silent watcher cron that retries the full cycle every few hours until it passes.

Watcher-cron pattern for "target down, auto-finish later": cron job with no_agent=true and empty-stdout-means-silent delivery. The cron script must be a filename relative to ~/AppData/Local/hermes/scripts/ — put a small Python wrapper there that subprocess.runs the real bash script with PYTHONPATH removed from env. The bash wrapper: kill stale target-matched chromes via Get-CimInstance Win32_Process (CommandLine match), run the reg attempt, then an idempotent notify_once.py (marker json + .notified flag → bot sendMessage). Reg script: mtime-checked lockfile against overlapping runs, marker file (*_account.json with email/cookies) written only on success, print one stdout line on success so cron delivers it; failures log to a local file only.

Vani snapshot (2026-10-12): platform.vani.ai signup = magic-link/email-code server actions (magic 603c7204c5c2433875cd7af57e3cc552e17ca3101b, code 604615c8bb79e439416b1fc99fd6da1a4847ea835e, OTP 6 digits), password signup disabled server-side; Turnstile sitekey 0x4AAAAAAFM_3cPV7Jg5kRlB. Blocked by THEIR email backend outage (all variants above rejected identically). api.vani.ai/v1 is live OpenAI-compat (401 unauthenticated); keys sk_live_* are created at /dashboard/keys after login. Files: tmp/vani/{vani_watcher.py, run_watcher.sh, notify_once.py, vani_reg*.py}; cron vani-autoreg-watcher (ffc0ce7d5cb0, every 3h, silent-on-fail).

Recon order for any new small provider

  1. curl home + /register + /login; identify stack (Laravel _token / Next.js $ACTION_* / new-api / FastAPI detail). 1.5. For Next.js: extract createServerReference action ids from the page bundle and probe a raw Next-Action multipart POST (Pattern B2) BEFORE building any browser automation — the RSC response shape immediately tells you HTTP-callable vs browser-only.
  2. Grep register HTML for /auth/(github|google)/redirect → if present, Pattern A (no captcha needed).
  3. Else check whether the page natively renders Turnstile (window.turnstile, auto-filled captcha input) → Pattern B with cloakbrowser + proxy pre-filter.
  4. Grep for per-IP signup limits in error copy AFTER the first failure — sites state them in the response body ("не больше N аккаунтов за M дней").
  5. Always end-to-end verify: registration success ≠ usable credit. Fetch the model list, run one chat completion, save api_key + account creds to a JSONL bank.