Skip to content

AWS WAF JS SDK challenge.js — mp_verify returns 400 "Invalid request" with Bot Control TARGETED on CloudFront

0

We are integrating the AWS WAF JavaScript SDK (challenge.js) with Bot Control TARGETED on a CloudFront-protected web application. The SDK loads successfully but token acquisition fails: the POST to mp_verify on edge.sdk.awswaf.com returns HTTP 400 "Invalid request".

Environment:

  • Web ACL scope: CLOUDFRONT (us-east-1)
  • Bot Control rule group: AWSManagedRulesBotControlRuleSet, inspection_level = TARGETED
  • token_domains: configured with custom domain + CloudFront default domain
  • Script: <script src="<ApplicationIntegrationURL>/challenge.js" defer></script> in HTML <head>
  • ApplicationIntegrationURL retrieved from get-web-acl API

What we observe:

  • challenge.js loads fine (HTTP 200)
  • The report endpoint on the same SDK domain works (HTTP 200)
  • The mp_verify POST returns 400 "Invalid request", no CORS headers on the error response, so the browser displays a CORS error (red herring)
  • AwsWafIntegration is defined after script load, but getToken() resolves with an undefined token
  • The aws-waf-token cookie is never set

What we tested (all produce mp_verify 400):

  • override_action { count {} } vs override_action { none {} } on the TARGETED rule
  • With and without a separate Challenge rule action in the Web ACL
  • With and without Bot Control COMMON in the same Web ACL (tested TARGETED alone)
  • With and without an API key (created via create-api-key)
  • challenge.js (from sdk.awswaf.com) vs jsapi.js (from captcha-sdk.awswaf.com)
  • With and without window.awsWafCookieDomainList
  • Real Chrome browser and headless Chromium: same result

Expected behavior: mp_verify should return 200 with a valid challenge token, and the aws-waf-token cookie should be set.

Question: Is there an additional configuration step required for the JS SDK challenge.js to work with Bot Control TARGETED on CloudFront? Is there a known issue with the mp_verify endpoint?

4 Answers
6
Accepted Answer

If report works (200) but mp_verify fails (400), your SDK is talking to AWS, but AWS is refusing to "anchor" a token to your current browser session due to domain mismatch or suspected automation.

To resolve this certainty, check these three specific technical blockers:

  • Public Suffix Restriction: If testing on *.cloudfront.net, ensure window.awsWafCookieDomainList does not have a leading dot. Browsers reject cookies with a leading dot on Public Suffix List domains, causing the SDK to fail the verification handshake.
  • Targeted Signal Interference: Bot Control TARGETED inspects the browser signals during the challenge. If your test environment (e.g., a scripted browser or a window without interaction) triggers a high-confidence bot signal, mp_verify will return a 400 to prevent token issuance. Set all individual rules within the BotControl group to Count (not just the group override) to see if the 400 vanishes.
  • Exact Domain Match: Ensure the Origin header in the mp_verify POST exactly matches an entry in your Token domains list. Even a mismatch between www.domain.com and domain.com in the WAF configuration will trigger a 400.
EXPERT
answered a month ago
4

In Short: The error occurs because WAF cannot map the verification request to your Web ACL due to missing domain authorization or an incorrect SDK endpoint.

The HTTP 400 "Invalid request" on mp_verify indicates a domain or endpoint mismatch. To fix it, ensure these three configurations are exact:

  • Token Domains: You must explicitly add both your custom domain and the *.cloudfront.net domain to the Token domains list in your Web ACL settings.
  • Integration URL: Do not use a generic script URL. You must use the specific Application Integration URL retrieved from the WAF API (Format: https://<id>.us-east-1.sdk.awswaf.com/<name>/challenge.js).
  • API Key: For TARGETED bot control, an API key is mandatory. Create it via aws wafv2 create-api-key for your specific domains and ensure it is active.
EXPERT
answered a month ago
4

Thanks for the suggestions, they helped us find the solution!

The key issue was the token acquisition mechanism. We were trying to use the challenge.js SDK for standalone token acquisition viamp_verify, but the correct approach is to use the WAF Challenge rule action on the initial page load.

What works: A Challenge rule scoped to GET requests on our protected pages. The browser solves the challenge invisibly on page load and acquires the aws-waf-token cookie. Subsequent POST requests pass through with the token already set.

What doesn't work (for reference):

  • challenge.js / jsapi.js standalone token acquisition via mp_verify, always returns 400 regardless of configuration
  • Challenge rule on POST returns HTTP 202 which breaks legacy AJAX frameworks that expect a specific response format

In short: Challenge on GET (page load) = works. Challenge on POST or standalone SDK = doesn't work for our use case. No JS SDK needed.

Thanks again for pointing us in the right direction!

answered a month ago
EXPERT
reviewed a month ago
3

Thanks for the suggestions. I tested all three but the issue persists:

  1. Token Domains - Already configured: token_domains = ["myapp.ninja", "d1someid.cloudfront.net"] (custom domain + CloudFront default domain).

  2. Regional URL - Tested https://<id>.us-east-1.sdk.awswaf.com/<id>/<name>/challenge.js (redirects to us-east-1.token.awswaf.com). Same 400 on mp_verify. Also tested the edge.sdk.awswaf.com URL from get-web-acl API - same result.

  3. API Key - Created via aws wafv2 create-api-key --scope CLOUDFRONT --token-domains myapp.ninja. Also tested with jsapi.js from the captcha-sdk.awswaf.com URL using this key - same 400.

Additional tests (all produce mp_verify 400):

  • override_action { count {} } vs override_action { none {} } on TARGETED rule
  • With/without a separate Challenge rule action in the Web ACL
  • Single TARGETED rule only (COMMON removed from Web ACL)
  • With/without window.awsWafCookieDomainList = ['.myapp.ninja']
  • Real Chrome browser (not headless)

The report endpoint on the same SDK domain works fine (HTTP 200). Only mp_verify fails. The OPTIONS preflight returns Access-Control-Allow-Origin: *, but the POST 400 response has no CORS headers - the browser shows a CORS error but the real error is 400 "Invalid request".

AwsWafIntegration is defined after script load, but getToken() resolves with an undefined token.

Is there an additional setup step in the WAF console (Application Integration tab) that we might be missing? Or could this bespecific to the Web ACL configuration?

answered a month ago
EXPERT
reviewed a month ago

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.