DEV Community

Bob
Bob

Posted on Originally published at capbypass.pro

AWS WAF challenge vs CAPTCHA: which token you need

Your scraper gets past the AWS WAF page check, the aws-waf-token cookie is set, and then the sign-up or checkout POST comes back 405 with "Request not allowed due to WAF captcha". The token is fine. It is the wrong kind: the page only ran a challenge, and that action is behind a CAPTCHA rule. Send jsapi.js instead of challenge.js and the same request goes through. CapBypass solves either kind in about 1.5 s on average.


Challenge vs CAPTCHA in AWS WAF

AWS WAF has two actions a rule can apply, and both end in the same aws-waf-token cookie:

Challenge CAPTCHA
What the visitor sees nothing, or a short interstitial an image or audio puzzle
Script challenge.js jsapi.js
Host pattern *.token.awswaf.com, *.sdk.awswaf.com *.captcha.awswaf.com, *.captcha-sdk.awswaf.com
Blocked response 202 with a challenge page 405 with a CAPTCHA page
Typical use page loads, browsing, search sign-up, login, checkout, forms

The token is not a single pass/fail flag. It records when the client last passed a challenge and when it last solved a CAPTCHA. A challenge rule checks the first, a CAPTCHA rule checks the second. A token earned through challenge.js has no CAPTCHA solve on it, so a CAPTCHA rule rejects it even though the same cookie loads every page on the site.

Each timestamp is valid for the rule's immunity time, 300 seconds by default in AWS WAF. Site owners can raise or lower it.


Finding which script the target loads

Open the page and the action you want to automate in Chrome DevTools, Network tab, filter awswaf:

  • Only challenge.js on page load, and the form submit works: you need awsChallengeJS.
  • jsapi.js appears, or the form submit returns 405: you need awsApiJs.
  • Both appear: send both. CapBypass picks the right combination.

Copy the full script URL. It follows https://{apiKey}.{accountId}.{region}.token.awswaf.com/{apiKey}/challenge.js or the captcha.awswaf.com/.../jsapi.js equivalent. For login, try challenge.js first and switch to jsapi.js if you get a 405.

AWS WAF challenge vs CAPTCHA flow: a challenge.js token loads the page with 200 but the sign-up POST gets 405, a jsapi.js token passes the sign-up with 200


Solving each with CapBypass

Page access, challenge.js:

curl -s https://api.capbypass.pro/createTask \
  -H 'Content-Type: application/json' \
  -d '{
    "clientKey": "'"$CAPBYPASS_API_KEY"'",
    "task": {
      "type": "AntiAwsWafTaskProxyLess",
      "websiteURL": "https://example.com/products",
      "awsChallengeJS": "https://b516434d791a.aa24f28d.eu-west-1.token.awswaf.com/b516434d791a/challenge.js"
    }
  }'
Enter fullscreen mode Exit fullscreen mode

Protected action, jsapi.js. Point websiteURL at the page that hosts the form:

curl -s https://api.capbypass.pro/createTask \
  -H 'Content-Type: application/json' \
  -d '{
    "clientKey": "'"$CAPBYPASS_API_KEY"'",
    "task": {
      "type": "AntiAwsWafTaskProxyLess",
      "websiteURL": "https://example.com/signup",
      "awsApiJs": "https://b516434d791a.aa24f28d.eu-west-1.captcha.awswaf.com/b516434d791a/jsapi.js"
    }
  }'
Enter fullscreen mode Exit fullscreen mode

Both return a taskId. Poll getTaskResult until status is ready (intervals and timeouts in polling captcha API tasks). The solution carries cookie (aws-waf-token=...), token and userAgent.

With the Python SDK, create and poll is one call:

import os

import requests
from capbypass import CapBypass

client = CapBypass(api_key=os.environ["CAPBYPASS_API_KEY"])

solution = client.solve({
    "type": "AntiAwsWafTaskProxyLess",
    "websiteURL": "https://example.com/signup",
    "awsApiJs": "https://b516434d791a.aa24f28d.eu-west-1.captcha.awswaf.com/b516434d791a/jsapi.js",
}, timeout=120)

session = requests.Session()
session.headers["User-Agent"] = solution["userAgent"]
name, value = solution["cookie"].split("=", 1)
session.cookies.set(name, value, domain="example.com")

resp = session.post("https://example.com/api/signup", json={"email": "test@example.com"})
print(resp.status_code)  # 405 here means the token still lacks a CAPTCHA solve
Enter fullscreen mode Exit fullscreen mode

The same in TypeScript with the TypeScript SDK:

import { CapBypassClient, TaskType } from '@capbypass/sdk';

const client = new CapBypassClient({ apiKey: process.env.CAPBYPASS_API_KEY });

const solution = await client.solve({
  type: TaskType.ANTI_AWS_WAF_PROXYLESS,
  websiteURL: 'https://example.com/signup',
  awsApiJs: 'https://b516434d791a.aa24f28d.eu-west-1.captcha.awswaf.com/b516434d791a/jsapi.js',
}, 120);

const resp = await fetch('https://example.com/api/signup', {
  method: 'POST',
  headers: {
    Cookie: solution.cookie,
    'User-Agent': solution.userAgent,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ email: 'test@example.com' }),
});
console.log(resp.status);
Enter fullscreen mode Exit fullscreen mode

Bonus: +5% credits on every top-up

New to CapBypass? Apply code WELCOME_2026 at checkout for an extra 5% in credits on every top-up, with no minimum and no expiry. Redeem it on the top-up page and put it toward your first AntiAwsWafTaskProxyLess solves.


Own proxy or proxyless

AntiAwsWafTaskProxyLess mints the token from our network. AntiAwsWafTask mints it through a proxy you pass as host:port:user:pass (accepted formats). Over the last 60 days of production traffic the two performed the same:

Task type Success Average solve time
AntiAwsWafTaskProxyLess 97.7% 1.5 s
AntiAwsWafTask (own proxy) 98.7% 1.8 s

Bringing your own proxy costs about 0.3 s per solve and no success. Pick it when the target only lets certain IPs or countries through, or when you want the token minted on the same egress as the rest of your session. Otherwise proxyless is less to operate.

Three proxy errors come back from the own-proxy type, and none of them is a WAF problem:

  • ERROR_PROXY_NOT_DEFINED: you sent AntiAwsWafTask without proxy. Add it or switch to the proxyless type.
  • ERROR_PROXY_CONNECTION_FAILED: the proxy refused, timed out or rejected the credentials. Test it with curl -x first.
  • ERROR_PROXY_BANNED: the target blocked that IP. Use a residential or mobile proxy.

A proxy sent on the proxyless type is dropped, not used. If you want your IP, use AntiAwsWafTask.


Why a valid token still gets rejected

  • The action needs a CAPTCHA solve. A 405 on a form with a token that loads pages fine is the case above. Re-solve with awsApiJs.
  • The request goes to another domain. Tokens are bound to the domain they were minted for. We saw this on a login flow whose sign-up step posted to an API on a different domain: login worked, sign-up got 405 "Request not allowed due to WAF captcha" with a valid token. Check which host receives the POST. If it differs from the domain you solved on, the token will not carry over.
  • The immunity time ran out. After the rule's immunity time (300 seconds by default), the same cookie is challenged again. Solve again rather than caching tokens for long jobs.
  • The action wants a fresh token. Some sign-up and checkout rules require a newly solved CAPTCHA even if your token is valid. Send the old cookie as awsExistingToken along with awsApiJs (and awsApiKey if the page exposes one) to upgrade it.

For the plain page-challenge flow from a scraper, start with bypassing AWS WAF in Python. For native app APIs, see AWS WAF mobile SDK tokens.


FAQ

What is the difference between an AWS WAF challenge and a CAPTCHA?
A challenge is a silent proof-of-work run by challenge.js, used to let browsers load pages. A CAPTCHA is a puzzle served by jsapi.js, usually in front of sign-up, login or checkout. Both write aws-waf-token, but a CAPTCHA rule only accepts a token that includes a CAPTCHA solve.

Why does AWS WAF return 405?
405 is the default response of a CAPTCHA rule when the token has no valid CAPTCHA solve. A challenge rule answers 202 instead. Solve with awsApiJs and retry.

Can I send both challenge.js and jsapi.js?
Yes. Put both awsChallengeJS and awsApiJs in the same task and CapBypass uses the combination the site needs.

Should I use my own proxy for AWS WAF?
Only if the target restricts IPs or you want one egress for the whole session. Over 60 days, own-proxy and proxyless solves had the same success rate, about 98%. Use it on sites you own or have permission to test.

How much does an AWS WAF solve cost?
Both task types cost the same, listed on the pricing page. Failed tasks are not charged.


Originally published on capbypass.pro. CapBypass is an AI-powered captcha-solving API for reCAPTCHA, hCaptcha, Cloudflare Turnstile and AWS WAF.

Top comments (0)