Integrating Approov with Fastly Compute@Edge and WAF

Injecting Deterministic Mobile Bot Protection into the Bot and API Security Solution You Already Use

Fastly’s API security solution (ex Signal Sciences) 

The mobile app visibility and protection provided by Approov enhances the backend security already deployed in Fastly, providing a reliable way to stop any mobile bot traffic. This article shows step-by-step how to do it.

Introduction

Backend app sec gives you web bot detection and behavioral detection, and Approov’s expertise in mobile API security gives you app and device visibility and attestation. In hybrid environments where users interact with both a web app and a mobile app, using backend app security for web protection and Approov for mobile API security ensures that bots cannot simply shift from web to mobile APIs.

Approov can work with any backend security solution because the result of the app and device attestation analysis is captured in a standard JWT token, integrated into every request. This makes the backend API checking straightforward since almost all backend app security solutions (and any languages and technologies) support JWT checking.

All you need to do is integrate the lightweight platform-specific Approov SDK with your app and then start checking Approov tokens. For the mobile app integration, there are SDK quickstarts available for native or cross-platform apps on iOS, Android and HarmonyOS.

This layered approach covers multiple entry points while isolating security strategies based on interaction type, ensuring more precise control over legitimate and illegitimate access.

For backend integration, again a range of  back end quickstarts are available. 

If there isn't already a quickstart for an integration you need, we provide other tools to make it easy for you to do it yourself or you can talk to us about what you need.

This article gives a step by step guide to integration with Fastly’s WAF security solution via Fastly Compute@Edge. 

Step by Step Guide to Integrating Approov with Fastly WAF, Compute@Edge Platform and Edge Dictionaries

Integrating Approov token checking with Fastly’s security solution involves using Fastly’s Compute@Edge platform and Edge Dictionaries to enforce JWT validation at the edge—before requests reach your origin API. This helps ensure only genuine, untampered mobile apps (as verified by Approov) can access your APIs.

Fastly also has a WAF (ex Signal Sciences)  which can be part of the solution although it's actually not needed to integrate with Approov. Compute@Edge integration is actually all you need for effective Approov integration. 

Summary: WAF vs Compute@Edge

Feature

Fastly WAF (Signal Sciences)

Compute@Edge

Header presence check

✅ Yes

✅ Yes

Regex for format

✅ Yes

✅ Yes

Signature verification

❌ Not possible

✅ Full JWT validation

Claim inspection

❌ Limited (unless decoded manually)

✅ Deep inspection and logic handling

Performance at edge

✅ High

✅ High


Why Integrate Approov with Fastly WAF?

  • Approov provides mobile app attestation, ensuring only genuine apps can access backend APIs.
  • Fastly Next-Gen WAF (previously Signal Sciences) provides dynamic, application-layer threat detection and mitigation.
  • Integrating the two enhances API security posture by validating app integrity before traffic even reaches application logic.

Integration Goal

🔐 Validate the Approov-Token (a short-lived, signed JWT) at the Fastly edge using Compute@Edge logic. If the token is:

  • ✅ Valid → forward request to origin
  • ❌ Invalid or missing → reject with 403

Prerequisites

  1. Approov SDK integrated in your mobile apps.
  2. Approov tokens sent in the Approov-Token HTTP header.
  3. Fastly Compute@Edge enabled (Rust or JavaScript environment).
  4. Access to Approov token verification secret.
  5. Optional: Edge Dictionary for secure secret management.

Integration Steps

1. Set Up Fastly Compute@Edge Service

Create a new Compute@Edge service using either:

  • Rust (recommended for performance and flexibility)
  • JavaScript (faster to prototype)

2. Securely Store the Approov Secret

Use one of the following:

  • Edge Dictionary (for simple, securely stored values)
  • Backend secret fetch (e.g., from HashiCorp Vault or external API, less common)

Example (Edge Dictionary):

bash

CopyEdit

fastly dictionary create --service-id=[SERVICE_ID] --name=approov_keys

fastly dictionary-item create --dictionary-id=[DICT_ID] --item-key="approov_secret" --item-value="SHARED_SECRET_HERE"

3. Write Token Validation Logic (Rust Example)

In main.rs for a Rust-based Compute@Edge service:

rust

CopyEdit

use fastly::{Request, Response, Error};

use jwt_simple::prelude::*;

use std::str;


fn validate_token(token: &str, secret: &str) -> bool {

    let key = HS256Key::from_bytes(secret.as_bytes());

    match key.verify_token::<NoCustomClaims>(token, None) {

        Ok(_) => true,

        Err(_) => false,

    }

}


#[fastly::main]

fn main(req: Request) -> Result<Response, Error> {

    let token_header = req.get_header("Approov-Token");

    let secret = "SHARED_SECRET_HERE"; // replace with dictionary lookup


    match token_header {

        Some(token_value) => {

            let token = token_value.to_str().unwrap_or_default();

            if validate_token(token, secret) {

                return Ok(req.send("origin_backend")?);

            } else {

                return Ok(Response::from_status(403).with_body("Invalid Approov token"));

            }

        }

        None => {

            return Ok(Response::from_status(403).with_body("Missing Approov token"));

        }

    }

}


For production use, replace hardcoded secret with a lookup from a Fastly Edge Dictionary.

4. Add JWT Dependency

Add to Cargo.toml:

toml

CopyEdit

jwt-simple = "0.11"

5. Deploy to Fastly

bash

CopyEdit

fastly compute publish

6. Test the Integration

  • Use Postman or cURL to send a request with a valid Approov-Token.
  • Confirm:
    • ✅ Valid token → passes to origin
    • ❌ Invalid or missing token → 403 Forbidden

Optional Enhancements

Feature

How

Claim validation (e.g., exp, sub, did)

Use ClaimsVerificationOptions in the JWT library.

Token binding (user-token or device ID)

Extract did or bind token to user session.

Rate limiting or blocking by failure count

Track in external log aggregator (e.g., Datadog) or Fastly logs.

Monitoring and Logging

  • Enable Fastly real-time logging to track:
    • Token validation failures
    • Origin request volume
    • Threat patterns

Fastly WAF (Signal Sciences) Rules – Basic Enforcement

While WAF rules can’t validate JWT cryptographically, you can add enforcement logic to detect missing, malformed, or suspicious tokens.

1. Require Header Presence

Create a WAF rule:

  • Rule Type: Request Header
  • Condition: Approov-Token is absent
  • Action: Block or alert
Label: Missing Approov Token

2. Enforce JWT Format (Regex Match)


Create a WAF rule to validate JWT structure (three base64url parts):

  • Rule Type: Request Header
  • Condition: Approov-Token does not match regex

regex

CopyEdit

^[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+$

  • Action: Block or flag
  • Label: Malformed JWT

3. Block Specific Token Contents (Optional)

If a compromised token has a known iss, aud, or sub, you can match against decoded header/claims—but this requires a helper service to decode first, or you match based on known substrings in base64.

Fastly Compute@Edge – Full JWT Validation

For full cryptographic validation, use Compute@Edge (JavaScript or Rust):

JS/Rust Workflow:

  1. Extract the Approov-Token from the request headers.
  2. Validate the JWT:
    • Check expiration (exp)
    • Verify signature using Approov’s public key
  3. Check claims (e.g., sub, app_version, device_id)
  4. Allow or deny based on the result.

Pseudocode (JavaScript)

javascript

CopyEdit

import jwt from '@tsndr/cloudflare-worker-jwt'; // Similar in structure


async function handleRequest(request) {

  const token = request.headers.get("Approov-Token");

  if (!token) return new Response("Unauthorized", { status: 401 });


  const publicKey = `-----BEGIN PUBLIC KEY-----

  ...Approov RSA key here...

  -----END PUBLIC KEY-----`;


  const isValid = await jwt.verify(token, publicKey, "RS256");

  if (!isValid) return new Response("Invalid Token", { status: 403 });

  const payload = jwt.decode(token).payload;

  if (payload.exp < Date.now() / 1000) return new Response("Expired", { status: 403 });

  return fetch(request);

}

Pros and Cons of This Integration

✅ Pros

❌ Cons

Token validated at the edge—zero load on origin

Requires Compute@Edge deployment and logic

Short-lived tokens reduce replay and token theft risk

Fastly doesn’t natively support JWT decoding—external library needed

Easy to update secret via Edge Dictionary

Secrets not rotatable per-session unless bound to external service