

**Introducing a new console experience for AWS WAF**

You can now use the updated experience to access AWS WAF functionality anywhere in the console. For more details, see [Working with the console](https://docs.aws.amazon.com/waf/latest/developerguide/working-with-console.html). 

# AWS WAF JavaScript integrations
<a name="waf-javascript-api"></a>

This section explains how to use the AWS WAF JavaScript integrations.

You can use the JavaScript integration APIs to implement AWS WAF application integrations in your browsers and other devices that execute JavaScript. 

CAPTCHA puzzles and silent challenges can only run when browsers are accessing HTTPS endpoints. Browser clients must be running in secure contexts in order to acquire tokens. 
+ The intelligent threat APIs let you manage token authorization through a silent client-side browser challenge, and to include the tokens in the requests that you send to your protected resources. 
+ The CAPTCHA integration API adds to the intelligent threat APIs, and lets you customize the placement and characteristics of the CAPTCHA puzzle in your client applications. This API leverages the intelligent threat APIs to acquire AWS WAF tokens for use in the page after the end user successfully completes the CAPTCHA puzzle. 

By using these integrations, you ensure that the remote procedure calls by your client contain a valid token. When these integration APIs are in place on your application's pages, you can implement mitigating rules in your protection pack (web ACL), such as blocking requests that don't contain a valid token. You can also implement rules that enforce the use of the tokens that your client applications obtain, by using the Challenge or CAPTCHA actions in your rules. 

**Example implementation of intelligent threat APIs**  
The following listing shows basic components of a typical implementation of the intelligent threat APIs in a web application page. 

```
<head>
<script type="text/javascript" src="protection pack (web ACL) integration URL/challenge.js" defer></script>
</head>
<script>
const login_response = await AwsWafIntegration.fetch(login_url, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: login_body
  });
</script>
```

**Example implementation of CAPTCHA JavaScript API**  
The CAPTCHA integration API lets you customize your end users' CAPTCHA puzzle experience. The CAPTCHA integration leverages the JavaScript intelligent threat integration, for browser verification and token management, and adds a function for configuring and rendering the CAPTCHA puzzle. 

The following listing shows basic components of a typical implementation of the CAPTCHA JavaScript API in a web application page. 

```
<head>
    <script type="text/javascript" src="<Integration URL>/jsapi.js" defer></script>
</head>

<script type="text/javascript">
    function showMyCaptcha() {
        var container = document.querySelector("#my-captcha-container");
        
        AwsWafCaptcha.renderCaptcha(container, {
            apiKey: "...API key goes here...",
            onSuccess: captchaExampleSuccessFunction,
            onError: captchaExampleErrorFunction,
            ...other configuration parameters as needed...
        });
    }
    
    function captchaExampleSuccessFunction(wafToken) {
        // Use WAF token to access protected resources
        AwsWafIntegration.fetch("...WAF-protected URL...", {
            method: "POST",
            ...
        });
    }
    
    function captchaExampleErrorFunction(error) {
        /* Do something with the error */
    }
</script>

<div id="my-captcha-container">
    <!-- The contents of this container will be replaced by the captcha widget -->
</div>
```

**Topics**
+ [Providing domains for use in the tokens](waf-js-challenge-api-set-token-domain.md)
+ [Using the JavaScript API with content security policies](waf-javascript-api-csp.md)
+ [Using the intelligent threat JavaScript API](waf-js-challenge-api.md)
+ [Using the CAPTCHA JavaScript API](waf-js-captcha-api.md)

# Providing domains for use in the tokens
<a name="waf-js-challenge-api-set-token-domain"></a>

This section explains how to provide additional domains for tokens.

By default, when AWS WAF creates a token, it uses the host domain of the resource that’s associated with the protection pack (web ACL). You can provide additional domains for the tokens that AWS WAF creates for the JavaScript APIs. To do this, configure the global variable `window.awsWafCookieDomainList`, with one or more token domains. 

When AWS WAF creates a token, it uses the most appropriate, shortest domain from among the combination of the domains in `window.awsWafCookieDomainList` and the host domain of the resource that’s associated with the protection pack (web ACL). 

Example settings: 

```
window.awsWafCookieDomainList = ['.aws.amazon.com']
```

```
window.awsWafCookieDomainList = ['.aws.amazon.com', 'abc.aws.amazon.com']
```

You can't use public suffixes in this list. For example, you can't use `gov.au` or `co.uk` as token domains in the list.

The domains that you specify in this list must be compatible with your other domains and domain configurations: 
+ The domains must be ones that AWS WAF will accept, based on the protected host domain and the token domain list that's configured for the protection pack (web ACL). For more information, see [AWS WAF protection pack (web ACL) token domain list configuration](waf-tokens-domains.md#waf-tokens-domain-lists). 
+ If you use the JavaScript CAPTCHA API, at least one domain in your CAPTCHA API key must be an exact match for one of the token domains in `window.awsWafCookieDomainList` or it must be the apex domain of one of those token domains. 

  For example, for the token domain `mySubdomain.myApex.com`, the API key `mySubdomain.myApex.com` is an exact match and the API key `myApex.com` is the apex domain. Either key matches the token domain. 

  For more information about the API keys, see [Managing API keys for the JS CAPTCHA API](waf-js-captcha-api-key.md). 

If you use the `AWSManagedRulesACFPRuleSet` managed rule group, you might configure a domain that matches the one in the account creation path that you provided to the rule group configuration. For more information about this configuration, see [Adding the ACFP managed rule group to your web ACL](waf-acfp-rg-using.md).

If you use the `AWSManagedRulesATPRuleSet` managed rule group, you might configure a domain that matches the one in the login path that you provided to the rule group configuration. For more information about this configuration, see [Adding the ATP managed rule group to your protection pack (web ACL)](waf-atp-rg-using.md).

# Using the JavaScript API with content security policies
<a name="waf-javascript-api-csp"></a>

This section provides an example configuration to allowlist the AWS WAF apex domain.

If you apply content security policies (CSP) to your resources, for your JavaScript implementation to work, you need to allowlist the AWS WAF apex domain `awswaf.com`. The JavaScript SDKs make calls to different AWS WAF endpoints, so allowlisting this domain provides the permissions that the SDKs need to operate.

The following shows an example configuration to allowlist the AWS WAF apex domain: 

```
connect-src 'self' https://*.awswaf.com;
script-src 'self' https://*.awswaf.com;
script-src-elem 'self' https://*.awswaf.com;
```

If you try to use the JavaScript SDKs with resources that use CSP, and you haven't allowlisted the AWS WAF domain, you'll receive errors like the following: 

```
Refused to load the script ...awswaf.com/<> because it violates the following Content Security Policy directive: “script-src ‘self’
```

# Using the intelligent threat JavaScript API
<a name="waf-js-challenge-api"></a>

This section provides instructions for using the intelligent threat JavaScript API in your client application.

The intelligent threat APIs provide operations for running silent challenges against the user's browser, and for handling the AWS WAF tokens that provide proof of successful challenge and CAPTCHA responses. 

Implement the JavaScript integration first in a test environment, then in production. For additional coding guidance, see the sections that follow. 

 

**To use the intelligent threat APIs**

1. **Install the APIs** 

   If you use the CAPTCHA API, you can skip this step. When you install the CAPTCHA API, the script automatically installs the intelligent threat APIs.

   1. Sign in to the AWS Management Console and open the AWS WAF console at [https://console.aws.amazon.com/wafv2/homev2](https://console.aws.amazon.com/wafv2/homev2). 

   1. In the navigation pane, choose **Application integration**. On the **Application integration** page, you can see tabbed options. 

   1. Select **Intelligent threat integration**

   1. In the tab, select the protection pack (web ACL) that you want to integrate with. The protection pack (web ACL) list includes only protection packs (web ACLs) that use the `AWSManagedRulesACFPRuleSet` managed rule group, the `AWSManagedRulesATPRuleSet` managed rule group, or the targeted protection level of the `AWSManagedRulesBotControlRuleSet` managed rule group. 

   1. Open the **JavaScript SDK** pane, and copy the script tag for use in your integration. 

   1. In your application page code, in the `<head>` section, insert the script tag that you copied for the protection pack (web ACL). This inclusion causes your client application to automatically retrieve a token in the background on page load. 

      ```
      <head>
          <script type="text/javascript" src="protection pack (web ACL) integration URL/challenge.js” defer></script>
      <head>
      ```

      This `<script>` listing is configured with the `defer` attribute, but you can change the setting to `async` if you want a different behavior for your page. 

1. **(Optional) Add domain configuration for the client's tokens** – By default, when AWS WAF creates a token, it uses the host domain of the resource that’s associated with the protection pack (web ACL). To provide additional domains for the JavaScript APIs, follow the guidance at [Providing domains for use in the tokens](waf-js-challenge-api-set-token-domain.md). 

1. **Code your intelligent threat integration** – Write your code to ensure that token retrieval completes before the client sends its requests to your protected endpoints. If you are already using the `fetch` API to make your call, you can substitute the AWS WAF integration `fetch` wrapper. If you don't use the `fetch` API, you can use the AWS WAF integration `getToken` operation instead. For coding guidance, see the following sections. 

1. **Add token verification in your protection pack (web ACL)** – Add at least one rule to your protection pack (web ACL) that checks for a valid challenge token in the web requests that your client sends. You can use rule groups that check and monitor challenge tokens, like the targeted level of the Bot Control managed rule group, and you can use the Challenge rule action to check, as described in [CAPTCHA and Challenge in AWS WAF](waf-captcha-and-challenge.md). 

   The protection pack (web ACL) additions verify that requests to your protected endpoints include the token that you've acquired in your client integration. Requests that include a valid, unexpired token pass the Challenge inspection and do not send another silent challenge to your client. 

1. **(Optional) Block requests that are missing tokens** – If you use the APIs with the ACFP managed rule group, the ATP managed rule group, or the targeted rules of the Bot Control rule group, these rules don't block requests that are missing tokens. To block requests that are missing tokens, follow the guidance at [Blocking requests that don't have a valid AWS WAF token](waf-tokens-block-missing-tokens.md). 

**Topics**
+ [Intelligent threat API specification](waf-js-challenge-api-specification.md)
+ [How to use the integration `fetch` wrapper](waf-js-challenge-api-fetch-wrapper.md)
+ [How to use the integration `getToken`](waf-js-challenge-api-get-token.md)

# Intelligent threat API specification
<a name="waf-js-challenge-api-specification"></a>

This section lists the specification for the methods and properties of the intelligent threat mitigation JavaScript APIs. Use these APIs for intelligent threat and CAPTCHA integrations.

**`AwsWafIntegration.fetch()`**  
Sends the HTTP `fetch` request to the server using the AWS WAF integration implementation. 

**`AwsWafIntegration.getToken()`**  
Retrieves the stored AWS WAF token and stores it in a cookie on the current page with name `aws-waf-token`, and the value set to the token value. 

**`AwsWafIntegration.hasToken()`**  
Returns a boolean indicating whether the `aws-waf-token` cookie currently holds an unexpired token. 

If you're also using the CAPTCHA integration, see the specification for that at [CAPTCHA JavaScript API specification](waf-js-captcha-api-specification.md).

# How to use the integration `fetch` wrapper
<a name="waf-js-challenge-api-fetch-wrapper"></a>

This section provides instructions for using the integration `fetch` wrapper.

You can use the AWS WAF `fetch` wrapper by changing your normal `fetch` calls to the `fetch` API under the `AwsWafIntegration` namespace. The AWS WAF wrapper supports all of the same options as the standard JavaScript `fetch` API call and adds the token handling for the integration. This approach is generally the simplest way to integrate your application. 

**Before the wrapper implementation**  
The following example listing shows standard code before implementing the `AwsWafIntegration` `fetch` wrapper.

```
const login_response = await fetch(login_url, {
	    method: 'POST',
	    headers: {
	      'Content-Type': 'application/json'
	    },
	    body: login_body
	  });
```

**After the wrapper implementation**  
The following listing shows the same code with the `AwsWafIntegration` `fetch` wrapper implementation.

```
const login_response = await AwsWafIntegration.fetch(login_url, {
	    method: 'POST',
	    headers: {
	      'Content-Type': 'application/json'
	    },
	    body: login_body
	  });
```

# How to use the integration `getToken`
<a name="waf-js-challenge-api-get-token"></a>

This section explains how to use the `getToken` operation.

AWS WAF requires your requests to protected endpoints to include the cookie named `aws-waf-token` with the value of your current token. 

The `getToken` operation is an asynchronous API call that retrieves the AWS WAF token and stores it in a cookie on the current page with name `aws-waf-token`, and the value set to the token value. You can use this token cookie as needed in your page. 

When you call `getToken`, it does the following: 
+ If an unexpired token is already available, the call returns it immediately.
+ Otherwise, the call retrieves a new token from the token provider, waiting for up to 2 seconds for the token acquisition workflow to complete before timing out. If the operation times out, it throws an error, which your calling code must handle. 

The `getToken` operation has an accompanying `hasToken` operation, which indicates whether the `aws-waf-token` cookie currently holds an unexpired token. 

`AwsWafIntegration.getToken()` retrieves a valid token and stores it as a cookie. Most client calls automatically attach this cookie, but some don't. For example, calls made across host domains don't attach the cookie. In the implementation details that follow, we show how to work with both types of client calls. 

**Basic `getToken` implementation, for calls that attach the `aws-waf-token` cookie**  
The following example listing shows standard code for implementing the `getToken` operation with a login request.

```
const login_response = await AwsWafIntegration.getToken()
	    .catch(e => {
	        // Implement error handling logic for your use case
	    })
	    // The getToken call returns the token, and doesn't typically require special handling
	    .then(token => {
	        return loginToMyPage()
	    })
	
	async function loginToMyPage() {
	    // Your existing login code
	}
```

**Submit form only after token is available from `getToken`**  
The following listing shows how to register an event listener to intercept form submissions until a valid token is available for use. 

```
<body>
	  <h1>Login</h1>
	  <p></p>
	  <form id="login-form" action="/web/login" method="POST" enctype="application/x-www-form-urlencoded">
	    <label for="input_username">USERNAME</label>
	    <input type="text" name="input_username" id="input_username"><br>
	    <label for="input_password">PASSWORD</label>
	    <input type="password" name="input_password" id="input_password"><br>
	    <button type="submit">Submit<button>
	  </form>
	
	<script>
	  const form = document.querySelector("#login-form");
	
	  // Register an event listener to intercept form submissions
	  form.addEventListener("submit", (e) => {
	      // Submit the form only after a token is available 
	      if (!AwsWafIntegration.hasToken()) {
	          e.preventDefault();
	          AwsWafIntegration.getToken().then(() => {
	              e.target.submit();
	          }, (reason) => { console.log("Error:"+reason) });
	        }
	    });
	</script>
	</body>
```

**Attaching the token when your client doesn't attach the `aws-waf-token` cookie by default**  
`AwsWafIntegration.getToken()` retrieves a valid token and stores it as a cookie, but not all client calls attach this cookie by default. For example, calls made across host domains don't attach the cookie. 

The `fetch` wrapper handles these cases automatically, but if you aren't able to use the `fetch` wrapper, you can handle this by using a custom `x-aws-waf-token` header. AWS WAF reads tokens from this header, in addition to reading them from the `aws-waf-token` cookie. The following code shows an example of setting the header. 

```
const token = await AwsWafIntegration.getToken();
const result = await fetch('/url', {
    headers: {
        'x-aws-waf-token': token,
    },
});
```

By default, AWS WAF only accepts tokens that contain the same domain as the requested host domain. Any cross-domain tokens require corresponding entries in the protection pack (web ACL) token domain list. For more information, see [AWS WAF protection pack (web ACL) token domain list configuration](waf-tokens-domains.md#waf-tokens-domain-lists). 

For additional information about cross-domain token use, see [aws-samples/aws-waf-bot-control-api-protection-with-captcha](https://github.com/aws-samples/aws-waf-bot-control-api-protection-with-captcha).

# Using the CAPTCHA JavaScript API
<a name="waf-js-captcha-api"></a>

This section provides instructions for using the CAPTCHA integration API.

The CAPTCHA JavaScript API allows you to configure the CAPTCHA puzzle and place it where you want in your client application. This API leverages the features of the intelligent threat JavaScript APIs to acquire and use AWS WAF tokens after an end user successfully completes a CAPTCHA puzzle. 

Implement the JavaScript integration first in a test environment, then in production. For additional coding guidance, see the sections that follow. 

**To use the CAPTCHA integration API**

1. **Install the API**

   1. Sign in to the AWS Management Console and open the AWS WAF console at [https://console.aws.amazon.com/wafv2/homev2](https://console.aws.amazon.com/wafv2/homev2). 

   1. In the navigation pane, choose **Application integration**. On the **Application integration** page, you can see tabbed options. 

   1. Select **CAPTCHA integration**.

   1. Copy the listed JavaScript integration script tag for use in your integration.

   1. In your application page code, in the `<head>` section, insert the script tag that you copied. This inclusion makes the CAPTCHA puzzle available for configuration and use. 

      ```
      <head>
          <script type="text/javascript" src="integrationURL/jsapi.js" defer></script>
      </head>
      ```

      This `<script>` listing is configured with the `defer` attribute, but you can change the setting to `async` if you want a different behavior for your page. 

      The CAPTCHA script also automatically loads the intelligent threat integration script if it isn't already present. The intelligent threat integration script causes your client application to automatically retrieve a token in the background on page load, and provides other token management functionality that you need for your use of the CAPTCHA API. 

1. **(Optional) Add domain configuration for the client's tokens** – By default, when AWS WAF creates a token, it uses the host domain of the resource that’s associated with the protection pack (web ACL). To provide additional domains for the JavaScript APIs, follow the guidance at [Providing domains for use in the tokens](waf-js-challenge-api-set-token-domain.md). 

1. **Get the encrypted API key for the client** – The CAPTCHA API requires an encrypted API key that contains a list of valid client domains. AWS WAF uses this key to verify that the client domain you're using with the integration is approved to use AWS WAF CAPTCHA. To generate your API key, follow the guidance at [Managing API keys for the JS CAPTCHA API](waf-js-captcha-api-key.md).

1. **Code your CAPTCHA widget implementation** – Implement the `renderCaptcha()` API call in your page, at the location where you want to use it. For information about configuring and using this function, see the following sections, [CAPTCHA JavaScript API specification](waf-js-captcha-api-specification.md) and [How to render the CAPTCHA puzzle](waf-js-captcha-api-render.md). 

   The CAPTCHA implementation integrates with the intelligent threat integration APIs for token management and to run fetch calls that use the AWS WAF tokens. For guidance about using these APIs, see [Using the intelligent threat JavaScript API](waf-js-challenge-api.md).

1. **Add token verification in your protection pack (web ACL)** – Add at least one rule to your protection pack (web ACL) that checks for a valid CAPTCHA token in the web requests that your client sends. You can use the CAPTCHA rule action to check, as described in [CAPTCHA and Challenge in AWS WAF](waf-captcha-and-challenge.md). 

   The protection pack (web ACL) additions verify that requests going to your protected endpoints include the token that you've acquired in your client integration. Requests that include a valid, unexpired CAPTCHA token pass the CAPTCHA rule action inspection and do not present your end user with another CAPTCHA puzzle. 

After you've implemented the JavaScript API, you can review the CloudWatch metrics for CAPTCHA puzzle attempts and solutions. For metrics and dimension details, see [Account metrics and dimensions](waf-metrics.md#waf-metrics-account).

**Topics**
+ [CAPTCHA JavaScript API specification](waf-js-captcha-api-specification.md)
+ [How to render the CAPTCHA puzzle](waf-js-captcha-api-render.md)
+ [Handling a CAPTCHA response from AWS WAF](waf-js-captcha-api-conditional.md)
+ [Managing API keys for the JS CAPTCHA API](waf-js-captcha-api-key.md)

# CAPTCHA JavaScript API specification
<a name="waf-js-captcha-api-specification"></a>

This section lists the specification for the methods and properties of the CAPTCHA JavaScript APIs. Use the CAPTCHA JavaScript APIs to run custom CAPTCHA puzzles in your client applications. 

This API builds on the intelligent threat APIs, which you use to configure and manage AWS WAF token acquisition and use. See [Intelligent threat API specification](waf-js-challenge-api-specification.md). .

**`AwsWafCaptcha.renderCaptcha(container, configuration)`**  
Presents an AWS WAF CAPTCHA puzzle to the end user and, upon success, updates the client token with the CAPTCHA validation. This is available only with the CAPTCHA integration. Use this call along with the intelligent threat APIs to manage token retrieval and to provide the token in your `fetch` calls. See the intelligent threat APIs at [Intelligent threat API specification](waf-js-challenge-api-specification.md).  
Unlike the CAPTCHA interstitial that AWS WAF sends, the CAPTCHA puzzle rendered by this method displays the puzzle immediately, without an initial title screen.     
**`container`**  
The `Element` object for the target container element on the page. This is commonly retrieved by calling `document.getElementById()` or `document.querySelector()`.  
Required: Yes  
Type: `Element`  
**configuration**  
An object containing CAPTCHA configuration settings, as follows****:    
**`apiKey`**   
The encrypted API key that enables permissions for the client's domain. Use the AWS WAF console to generate your API keys for your client domains. You can use one key for up to five domains. For information, see [Managing API keys for the JS CAPTCHA API](waf-js-captcha-api-key.md).   
Required: Yes  
Type: `string`  
**`onSuccess: (wafToken: string) => void;`**   
Called with a valid AWS WAF token when the end user successfully completes a CAPTCHA puzzle. Use the token in the requests that you send to the endpoints that you protect with an AWS WAF protection pack (web ACL). The token provides proof and the timestamp of the latest successful puzzle completion.   
Required: Yes  
**`onError?: (error: CaptchaError) => void;`**   
Called with an error object when an error occurs during the CAPTCHA operation.   
Required: No  
**`CaptchaError` class definition** – The `onError` handler supplies an error type with the following class definition.   

```
CaptchaError extends Error {
    kind: "internal_error" | "network_error" | "token_error" | "client_error";
    statusCode?: number;
}
```
+ `kind` – The kind of error returned. 
+ `statusCode` – The HTTP status code, if available. This is used by `network_error` if the error is due to an HTTP error.  
**`onLoad?: () => void;`**   
Called when a new CAPTCHA puzzle loads.  
Required: No  
**`onPuzzleTimeout?: () => void;`**   
Called when a CAPTCHA puzzle isn't completed before it expires.  
Required: No  
**`onPuzzleCorrect?: () => void;`**   
Called when a correct answer is provided to a CAPTCHA puzzle.  
Required: No  
**`onPuzzleIncorrect?: () => void;`**   
Called when an incorrect answer is provided to a CAPTCHA puzzle.  
Required: No  
**`defaultLocale`**   
The default locale to use for the CAPTCHA puzzle. The written instructions for CAPTCHA puzzles are available in Arabic (ar-SA), simplified Chinese (zh-CN), Dutch (nl-NL), English (en-US), French (fr-FR), German (de-DE), Italian (it-IT), Japanese (ja-JP), Brazilian Portuguese (pt-BR), Spanish (es-ES), and Turkish (tr-TR). Audio instructions are available for all of the written languages except Chinese and Japanese, which default to English. To change the default language, provide the international language and locale code, for example, `ar-SA`.  
Default: The language currently in use in the end user's browser  
Required: No  
Type: `string`  
**`disableLanguageSelector`**   
If set to `true`, the CAPTCHA puzzle hides the language selector.   
Default: `false`  
Required: No  
Type: `boolean`  
**`dynamicWidth`**   
If set to `true`, the CAPTCHA puzzle changes width for compatibility with the browser window width.   
Default: `false`  
Required: No  
Type: `boolean`  
**`skipTitle`**   
If set to `true`, the CAPTCHA puzzle doesn't display the puzzle title heading **Solve the puzzle**.   
Default: `false`  
Required: No  
Type: `boolean`

# How to render the CAPTCHA puzzle
<a name="waf-js-captcha-api-render"></a>

This section provides an example `renderCaptcha` implementation.

You can use the AWS WAF `renderCaptcha` call where you want to in your client interface. The call retrieves a CAPTCHA puzzle from AWS WAF, renders it, and sends the results to AWS WAF for verification. When you make the call, you provide the puzzle rendering configuration and the callbacks that you want to run when your end users complete the puzzle. For details about the options, see the preceding section, [CAPTCHA JavaScript API specification](waf-js-captcha-api-specification.md).

Use this call in conjunction with the token management functionality of the intelligent threat integration APIs. This call gives your client a token that verifies the successful completion of the CAPTCHA puzzle. Use the intelligent threat integration APIs to manage the token and to provide the token in your client's calls to the endpoints that are protected with AWS WAF protection packs (web ACLs). For information about the intelligent threat APIs, see [Using the intelligent threat JavaScript API](waf-js-challenge-api.md).

**Example implementation**  
The following example listing shows a standard CAPTCHA implementation, including the placement of the AWS WAF integration URL in the `<head>` section. 

This listing configures the `renderCaptcha` function with a success callback that uses the `AwsWafIntegration.fetch` wrapper of the intelligent threat integration APIs. For information about this function, see [How to use the integration `fetch` wrapper](waf-js-challenge-api-fetch-wrapper.md).

```
<head>
    <script type="text/javascript" src="<Integration URL>/jsapi.js" defer></script>
</head>

<script type="text/javascript">
    function showMyCaptcha() {
        var container = document.querySelector("#my-captcha-container");
        
        AwsWafCaptcha.renderCaptcha(container, {
            apiKey: "...API key goes here...",
            onSuccess: captchaExampleSuccessFunction,
            onError: captchaExampleErrorFunction,
            ...other configuration parameters as needed...
        });
    }
    
    function captchaExampleSuccessFunction(wafToken) {
        // Captcha completed. wafToken contains a valid WAF token. Store it for
        // use later or call AwsWafIntegration.fetch() to use it easily.
        // It will expire after a time, so calling AwsWafIntegration.getToken()
        // again is advised if the token is needed later on, outside of using the
        // fetch wrapper.
        
        // Use WAF token to access protected resources
        AwsWafIntegration.fetch("...WAF-protected URL...", {
            method: "POST",
            headers: {
                "Content-Type": "application/json",
            },
            body: "{ ... }" /* body content */
        });
    }
    
    function captchaExampleErrorFunction(error) {
        /* Do something with the error */
    }
</script>

<div id="my-captcha-container">
    <!-- The contents of this container will be replaced by the captcha widget -->
</div>
```

**Example configuration settings**  
The following example listing shows the `renderCaptcha` with non-default settings for the width and the title options. 

```
        AwsWafCaptcha.renderCaptcha(container, {
            apiKey: "...API key goes here...",
            onSuccess: captchaExampleSuccessFunction,
            onError: captchaExampleErrorFunction,
            dynamicWidth: true, 
            skipTitle: true
        });
```

For full information about the configuration options, see [CAPTCHA JavaScript API specification](waf-js-captcha-api-specification.md).

# Handling a CAPTCHA response from AWS WAF
<a name="waf-js-captcha-api-conditional"></a>

This section provides an example of handling a CAPTCHA response.

An AWS WAF rule with a CAPTCHA action terminates the evaluation of a matching web request if the request doesn't have a token with a valid CAPTCHA timestamp. If the request is a `GET` text/html call, the CAPTCHA action then serves the client an interstitial with a CAPTCHA puzzle. When you don't integrate the CAPTCHA JavaScript API, the interstitial runs the puzzle and, if the end user successfully solves it, automatically resubmits the request. 

When you integrate the CAPTCHA JavaScript API and customize your CAPTCHA handling, you need to detect the terminating CAPTCHA response, serve your custom CAPTCHA, and then if the end user successfully solves the puzzle, resubmit the client's web request. 

The following code example shows how to do this. 

**Note**  
The AWS WAF CAPTCHA action response has a status code of HTTP 405, which we use to recognize the CAPTCHA response in this code. If your protected endpoint uses an HTTP 405 status code to communicate any other type of response for the same call, this example code will render a CAPTCHA puzzle for those responses as well. 

```
<!DOCTYPE html>
<html>
<head>
    <script type="text/javascript" src="<Integration URL>/jsapi.js" defer></script>
</head>
<body>
    <div id="my-captcha-box"></div>
    <div id="my-output-box"></div>

    <script type="text/javascript">
    async function loadData() {
        // Attempt to fetch a resource that's configured to trigger a CAPTCHA
        // action if the rule matches. The CAPTCHA response has status=HTTP 405.
        const result = await AwsWafIntegration.fetch("/protected-resource");

        // If the action was CAPTCHA, render the CAPTCHA and return

        // NOTE: If the endpoint you're calling in the fetch call responds with HTTP 405
        // as an expected response status code, then this check won't be able to tell the
        // difference between that and the CAPTCHA rule action response.

        if (result.status === 405) {
            const container = document.querySelector("#my-captcha-box");
            AwsWafCaptcha.renderCaptcha(container, {
                apiKey: "...API key goes here...",
                onSuccess() {
                    // Try loading again, now that there is a valid CAPTCHA token
                    loadData();
                },
            });
            return;
        }

        const container = document.querySelector("#my-output-box");
        const response = await result.text();
        container.innerHTML = response;
    }

    window.addEventListener("load", () => {
        loadData();
    });
    </script>
</body>
</html>
```

# Managing API keys for the JS CAPTCHA API
<a name="waf-js-captcha-api-key"></a>

This section provides instructions for generating and deleting API keys.

To integrate AWS WAF CAPTCHA into a a client application with the JavaScript API, you need the JavaScript API integration tag and the encrypted API key for the client domain where you want to run your CAPTCHA puzzle. 

The CAPTCHA application integration for JavaScript uses the encrypted API keys to verify that the client application domain has permission to use the AWS WAF CAPTCHA API. When you call the CAPTCHA API from your JavaScript client, you provide an API key with a domain list that includes a domain for the current client. You can list up to 5 domains in a single encrypted key. 

**API key requirements**  
The API key that you use in your CAPTCHA integration must contain a domain that applies to the client where you use the key. 
+ If you specify a `window.awsWafCookieDomainList` in your client's intelligent threat integration, then at least one domain in your API key must be an exact match for one of the token domains in `window.awsWafCookieDomainList` or it must be the apex domain of one of those token domains. 

  For example, for the token domain `mySubdomain.myApex.com`, the API key `mySubdomain.myApex.com` is an exact match and the API key `myApex.com` is the apex domain. Either key matches the token domain. 

  For information about the setting the token domain list, see [Providing domains for use in the tokens](waf-js-challenge-api-set-token-domain.md).
+ Otherwise, the current domain must be contained in the API key. The current domain is the domain that you can see in the browser address bar. 

The domains that you use must be ones that AWS WAF will accept, based on the protected host domain and the token domain list that's configured for the web ACL. For more information, see [AWS WAF protection pack (web ACL) token domain list configuration](waf-tokens-domains.md#waf-tokens-domain-lists).

**How to choose the Region for your API key**  
AWS WAF can generate CAPTCHA API keys in any Region where AWS WAF is available. 

As a general rule, you should use the same Region for your CAPTCHA API key as you use for your protection pack (web ACL). If you expect a global audience for a regional protection pack (web ACL), however, you can obtain a CAPTCHA JavaScript integration tag that's scoped to CloudFront and an API key that's scoped to CloudFront, and use them with a regional protection pack (web ACL). This approach allows clients to load a CAPTCHA puzzle from the Region that's closest to them, which reduces latency. 

CAPTCHA API keys that are scoped to Regions other than CloudFront are not supported for use across multiple Regions. They can only be used in the Region they are scoped to. 

**To generate an API key for your client domains**  
To obtain the integration URL and generate and retrieve the API keys through the console. 

1. Sign in to the AWS Management Console and open the AWS WAF console at [https://console.aws.amazon.com/wafv2/homev2](https://console.aws.amazon.com/wafv2/homev2). 

1. In the navigation pane, choose **Application integration**. 

1. In the pane, **protection packs (web ACLs) that are enabled for application integration**, select the Region that you want to use for your API key. You can also select the Region in the **API keys** pane of the **CAPTCHA integration** tab.

1. Choose the tab **CAPTCHA integration**. This tab provides the CAPTCHA JavaScript integration tag, which you can use in your integration, and the API keys listing. Both are scoped to the selected Region.

1. In the **API keys** pane, choose **Generate key**. The key generation dialogue appears. 

1. Enter the client domains that you want to include in the key. You can enter up to 5. When you're finished, choose **Generate key**. The interface returns to the CAPTCHA integration tab, where your new key is listed. 

   Once created, an API key is immutable. If you need to make changes to a key, generate a new key and use that instead. 

1. (Optional) Copy the newly generated key for use in your integration. 

You can also use the REST APIs or one of the language-specific AWS SDKs for this work. The REST API calls are [CreateAPIKey](https://docs.aws.amazon.com/waf/latest/APIReference/API_CreateAPIKey.html) and [ListAPIKeys](https://docs.aws.amazon.com/waf/latest/APIReference/API_ListAPIKeys.html). 

**To delete an API key**  
To delete an API key, you must use the REST API or one of the language specific AWS SDKs. The REST API call is [DeleteAPIKey](https://docs.aws.amazon.com/waf/latest/APIReference/API_DeleteAPIKey.html). You can't use the console to delete a key. 

After you delete a key, it can take up to 24 hours for AWS WAF to disallow use of the key in all regions. 