Integrate Google Cloud CDN with Fraud Prevention JavaScript SDK

Google Cloud CDN is a fully managed service that distributes HTTP(S) traffic across backend services and can inspect and modify traffic at the edge. This allows it to act not only as a global entry point for applications but also as a point of control for injecting or filtering content in transit.

Mosaic provides a native integration with GCP Service Extensions that enables you to inject the Device Risk & Security (Fraud Prevention) JavaScript SDK into HTML responses automatically, without modifying your web application code.

This plugin intercepts HTML responses at the CDN level and injects the required <script> tags for the Fraud Prevention SDK. As a result, every page served through the CDN includes the Fraud Prevention SDK, allowing Mosaic to capture risk signals from client devices transparently.

How it works

When a client requests an HTML page, the request passes through the GCP CDN (1).
The backend returns the response, which is intercepted by the Fraud Prevention plugin (2) at the CDN and modified to inject the SDK before being delivered to the browser. Once the page is loaded, the browser executes the injected Fraud Prevention SDK (formerly DRS) (3). The SDK collects device and risk signals client-side and forwards them to Mosaic for analysis (4).

The plugin uses the following injection strategy (fallback order):

  • After <meta charset> (preferred)
  • After <head>
  • Before <body>
  • At the beginning of the document
ClientGCP CDNBackendService Ext (FP WASM Plugin)FP SDKMosaicStep 1Step 2Step 3Step 4HTTP GET /page.htmlForward requestHTML responseRESPONSE_HEADERS/BODY event (intercept)Inject script for Fraud Prevention SDK and init blockModified HTML responseDeliver modified HTMLBrowser loads injected Fraud Prevention scriptInitialize with clientId + serverPathSend device/risk signalsClientGCP CDNBackendService Ext (FP WASM Plugin)FP SDKMosaic

Before you start

Before you begin:

  • A Google Cloud Platform account with billing enabled.
  • A Global External HTTPS CDN (only HTTPS is supported).
  • gcloud CLI installed and configured (version 534.0.0 or higher).

Step 1: Get client credentials

Admin Portal

Client credentials are used to identify your app and generate access tokens for authorizing Mosaic requests. To obtain them, you'll need to create an application in the Admin Portal (if you don’t have one yet).

  1. From Applications , click Add application .
  2. Add the friendly application name to display in the Admin Portal.
  3. Add a client display name, and your website URL as a redirect URI (e.g., https://your-domain.com ). These fields are required for all Mosaic apps, but won’t be used for Fraud Prevention.
  4. Click Add to create your application. This will automatically generate your client credentials (you'll need your client ID in step 3 ).

Step 2: Set up your Google Cloud environment

GCP

Before deploying the plugin, you need to prepare your Google Cloud environment.
Define your project and enable the required API for Service Extensions.

Run the following commands from a terminal where the gcloud CLI is installed and authenticated (for example, in your local terminal or in the Google Cloud Shell).
Make sure you have the necessary permissions to run these commands; if not, contact your GCP administrator.

Copy
Copied
# Set your GCP project ID
gcloud config set project YOUR_PROJECT_ID

# Enable the Service Extensions API (required for deploying the plugin)
gcloud services enable serviceextensions.googleapis.com

Step 3: Deploy the HTML Injection WASM plugin

GCP

In this step you deploy the Fraud Prevention HTML Injection WASM plugin provided by Mosaic.
This plugin runs as a GCP Service Extension and is responsible for intercepting HTML responses at the CDN level and injecting the Fraud Prevention SDK automatically, without requiring changes to your application code.

The plugin accepts the following parameters:

Parameter Description Example
clientId Your Mosaic app client ID XXXXXXXXXXXXXXX_XXX
serverPath Fraud Prevention API server path https://api.transmitsecurity.io/risk-collect/
Note

Never expose your clientId in client-side code samples, public docs, or unsecured environments.

Common server paths by region:

  • US: https://api.transmitsecurity.io/risk-collect/
  • EU: https://api.eu.transmitsecurity.io/risk-collect/
  • Canada: https://api.ca.transmitsecurity.io/risk-collect/
  • Australia: https://api.au.transmitsecurity.io/risk-collect/
Copy
Copied
# Set variables for easy configuration
PLUGIN_VERSION="v1-3"   # replace with the desired version (currently "v1-3")
PLUGIN_IMAGE="us-central1-docker.pkg.dev/dev-riskid/drs-plugins/drs-sdk-plugin-go:latest"  # replace with the image URI (currently Transmit Security's public image)
CLIENT_ID="YOUR_CLIENT_ID"   # replace with your DRS client ID (provided by Transmit Security)
SERVER_PATH="YOUR_SERVER_PATH"   # replace with your DRS server path (see examples below)

# Create plugin configuration file
cat > plugin-config.txt << EOF
clientId=${CLIENT_ID},serverPath=${SERVER_PATH}
EOF

# Create the WASM plugin
gcloud service-extensions wasm-plugins create drs-html-injection-plugin \
    --location=global \
    --main-version="${PLUGIN_VERSION}" \
    --image="${PLUGIN_IMAGE}" \
    --plugin-config-file="plugin-config.txt" \
    --log-config="enable=True,sample-rate=1.0,min-log-level=INFO" \
    --description="DRS HTML Injection Plugin - Automatically injects DRS SDK into HTML responses"

# (Optional)Clean up config file
rm plugin-config.txt

You will receive a response similar to the one below:

Copy
Copied
Create request issued for: [drs-html-injection-plugin]
Waiting for operation [projects/dev-riskid/locations/global/operations/operation-1755779730683-63cdf5326b4c9-95d21107-9fd2f84e] to complete...done.                                      
Created WasmPlugin [drs-html-injection-plugin] with WasmPluginVersion [PLUGIN_VERSION].

Example of injected code

When the plugin processes an HTML response, it automatically injects into the page a snippet similar to the one below. This happens at the CDN level — you do not need to add this code manually.

Copy
Copied
<script async src="https://platform-websdk.transmitsecurity.io/platform-websdk/1.x/ts-platform-websdk.js"></script>
<script>
window.addEventListener('load', function() {
  if (window.tsPlatform) {
    window.tsPlatform.initialize({
      clientId: 'YOUR_CLIENT_ID',
      drs: {
        enabled: true,
        serverPath: 'YOUR_SERVER_PATH'
      }
    });
    console.log('DRS SDK initialized');
  }
});
</script>
Note

The values YOUR_CLIENT_ID and YOUR_SERVER_PATH are automatically taken from the plugin configuration. You do not need to replace them manually in your application code.

Note

Use the Google Cloud CLI to check logs and monitor the status of your Service Extension and CDN.

Step 4: Configure the GCP CDN

GCP

Attach the plugin to your CDN so it can intercept traffic. This is done by creating a Service Extension that links the plugin to the forwarding rule of your HTTPS CDN.

  1. Identify the forwarding rule used by your CDN:
Copy
Copied
# Set your CDN name (replace with your CDN name)
LOAD_BALANCER_NAME="your-load-balancer-name"

# Get the target HTTPS proxy for your CDN
TARGET_PROXY_NAME=$(gcloud compute target-https-proxies list --filter="urlMap:${LOAD_BALANCER_NAME}" --format="value(name)")

# Find forwarding rules that use this target proxy 
# (replace FORWARDING_RULE_NAME with your CDN's forwarding rule name)
gcloud compute forwarding-rules list --global --filter="target:${TARGET_PROXY_NAME}" --format="value(name)"
  1. Create a Service Extension configuration file that attaches the previously deployed plugin ( drs-html-injection-plugin ) to your forwarding rule:
Copy
Copied
# Set variables for your GCP resources
PROJECT_ID="YOUR_PROJECT_ID"            # replace with your GCP project ID
FORWARDING_RULE_NAME="YOUR_FORWARDING_RULE_NAME"  # replace with your CDN's forwarding rule name

# Create service extension configuration
cat > drs-service-extension.yaml << EOF
name: projects/${PROJECT_ID}/locations/global/lbTrafficExtensions/drs-injection-service
description: "DRS HTML Injection Service Extension"
loadBalancingScheme: EXTERNAL_MANAGED
forwardingRules:
- https://www.googleapis.com/compute/v1/projects/${PROJECT_ID}/global/forwardingRules/${FORWARDING_RULE_NAME}
extensionChains:
- name: drs-injection-chain
  matchCondition:
    celExpression: "true"
  extensions:
  - name: drs-html-injection-plugin
    service: projects/${PROJECT_ID}/locations/global/wasmPlugins/drs-html-injection-plugin
    supportedEvents:
    - RESPONSE_BODY
    - RESPONSE_HEADERS
    failOpen: true
EOF
  1. Apply the Service Extension so it becomes active on the CDN:
Copy
Copied
gcloud service-extensions import drs-service-extension.yaml

Step 5: Set user

Client

A user identifier must be reported to Mosaic after the user is fully authenticated (including any required 2FA). This sets the user for all subsequent events in the current browser session.

The Web SDK is automatically injected and initialized by the CDN plugin after Steps 3–4. You only need to call setAuthenticatedUser once window.tsPlatform is available. Implement this in your web application code. The [USER_ID] is an opaque identifier for the user in your system.

Copy
Copied
await window.tsPlatform.drs.setAuthenticatedUser('[USER_ID]');
Note

Do not include personal user identifiers (e.g., email) in plain text.

Step 6: Trigger actions

Client

To obtain risk recommendations for sensitive actions, your application should report these actions from the web app using the Platform SDK. Add an event listener to the relevant form or button in your page and include the following code in your web application (after SDK initialization). Replace [ACTION_TYPE] with an action from the list of actions. Optionally pass a correlation ID and a claimed user ID (for unauthenticated users).

Copy
Copied
// Trigger events for the action and get the actionToken
// (Optional) correlationId and claimedUserId help improve Fraud Prevention
const tsAccountProtectionLoginHandler = `
<script>
 async function onSubmitLogin(event) {
   event.preventDefault();
   try {
    const value = await window.tsPlatform.drs.triggerActionEvent("[ACTION_TYPE]", { correlationId: "[CORRELATION_ID]", claimedUserId: "[CLAIMED_USER_ID]" });
    form.submit();
   } catch (error) {
     form.submit();
   };
 }
 let form = document.getElementById("login");
 if (form) {
   form.addEventListener('submit', onSubmitLogin);
 }
</script>
`;
Note (Backend handoff)

Make sure to pass the received actionToken to your backend together with the actual action invocation so that your server can fetch the recommendation in the next step.

Step 7: Fetch recommendation

Backend

From your server, fetch recommendations for the reported action using the Recommendation API.

These APIs are authorized using an OAuth access token. Obtain a token with client credentials (from Step 1). The token should target the following resource: https://risk.identity.security.

Copy
Copied
  const { access_token } = await fetch(
    `https://api.transmitsecurity.io/oidc/token`,
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
      }
      body: new URLSearchParams({
        grant_type: client_credentials,
        client_id: [CLIENT_ID],
        client_secret: [CLIENT_SECRET],
        resource: 'https://risk.identity.security'
      })
    }
  );

From your backend, invoke the Recommendation API. The [ACCESS_TOKEN] is the token you obtained above and [ACTION_TOKEN] is the actionToken received from the SDK in Step 6.

Copy
Copied
const query = new URLSearchParams({
  action_token: '[ACTION_TOKEN]',
}).toString();

const resp = await fetch(
  `https://api.transmitsecurity.io/risk/v1/recommendation?${query}`,
  {
    method: 'GET',
    headers: {
      Authorization: 'Bearer [ACCESS_TOKEN]',
    },
  }
);
Note (Backend step)

This is a server-side (machine-to-machine) call and is not handled by the CDN plugin or the Web SDK.

Step 8: Clear user

Client

When the user logs out or the session expires, clear the user so future actions aren’t associated with the previous user. Implement this in your web application (e.g., on logout).

Copy
Copied
const tsClearUserHandler = `
<script>
 async function onUserLogout(event) {
   await window.tsPlatform.drs.clearUser()
 }
 let button = document.getElementById("logout");
 if (button) {
   button.addEventListener('click', onUserLogout);
 }
</script>
`;