Skip to content

Testing Arcjet

Unlike network-based security solutions, Arcjet can run locally, in staging and in production. This makes it easy to test your security rules before deploying them.

You can also automate testing against your Arcjet-projected routes using standard testing libraries.

Testing using Newman

Newman is an open source command-line collection runner for Postman. It allows you to define requests in Postman format and run them from the command line without requiring Postman itself.

You can find our full example of how to test Arcjet with Express and Newman on GitHub. The key files are:

The example README explains how to start the test application and then execute the tests using Newman.

To adapt these to your own application you would modify the tests/*.json files to point to your application endpoints, and then run them using the Newman CLI. This allows you to automate testing and run multiple iterations e.g. to test a rate limit.

Testing triggering rules

Arcjet runs the same in production as locally. This ensures that the behavior you see in development is the same as in production. However, there are ways to trigger the different rules.

  • Shield: Send 5 requests with the special header x-arcjet-suspicious: true to trigger the shield rule on the next request.
  • Rate limiting: Make more requests than the rate limit allows.
  • Bot protection: Bot detection uses multiple heuristics so the quickest way to get a bot detection DENY response is to make a request that is always considered a bot. With a deny rule set to CURL you should see a DENY response if you make a request using the curl command. See Identifying Bots for more information.
  • Email validation: Use an email address that has invalid syntax or does not match any other rules you have configured e.g. has no MX records or if from a disposable email service.

Sampling

Arcjet is designed to run on every request. When testing your rules, you can use DRY_RUN mode to see how your rules would behave without actually enforcing them. The result will be logged, but all requests will be allowed. This is useful for testing your rules without affecting your users.

You can also write a simple sampling function to set the Arcjet rules using withRule based on a desired sample rate. This allows you to test your rules on a subset of your traffic.

This Next.js middleware example shows how to trigger Arcjet Shield and bot detection rules in live mode on 10% of your traffic.

/middleware.ts
import arcjet, { detectBot, shield } from "@arcjet/next";
import { NextRequest, NextResponse } from "next/server";
export const config = {
// matcher tells Next.js which routes to run the middleware on. This runs
// the middleware on all routes except for static assets.
matcher: ["/((?!_next/static|_next/image|favicon.ico).*)"],
};
const sampleRate = 0.1; // 10% of requests
const aj = arcjet({
key: process.env.ARCJET_KEY!,
// You could include one or more base rules to apply to all requests
rules: [],
});
function shouldSampleRequest(sampleRate: number) {
// sampleRate should be between 0 and 1, e.g., 0.1 for 10%, 0.5 for 50%
return Math.random() < sampleRate;
}
// Shield and bot rules will be configured with live mode if the request is
// sampled, otherwise only Shield will be configured with dry run mode
function sampleSecurity() {
if (shouldSampleRequest(sampleRate)) {
console.log("Rule is LIVE");
return aj
.withRule(
shield(
{ mode: "LIVE" }, // will block requests if triggered
),
)
.withRule(
detectBot({
mode: "LIVE",
allow: [], // "allow none" will block all detected bots
}),
);
} else {
console.log("Rule is DRY_RUN");
return aj.withRule(
shield({
mode: "DRY_RUN", // Only logs the result
}),
);
}
}
export default async function middleware(request: NextRequest) {
const decision = await sampleSecurity().protect(request);
if (decision.isDenied()) {
if (decision.reason.isBot()) {
return NextResponse.json({ error: "You are a bot" }, { status: 403 });
} else if (decision.reason.isShield()) {
return NextResponse.json({ error: "Shields up!" }, { status: 403 });
} else {
return NextResponse.json({ error: "Unauthorized" }, { status: 403 });
}
} else {
return NextResponse.next();
}
}

Discussion