# 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 `
  • ` 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 `. 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 ``, `$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 ` — 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: ` (ids live in the page bundle as `createServerReference("",...)`), `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=` → 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.run`s 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.