Application Security by Arcjet

Arcjet is a security layer that allows developers to protect their apps with just a few lines of code. Implement rate limiting, bot protection, email validation, and defense against common attacks.

Arcjet is installed as a dependency in your application and doesn’t require an agent or any additional infrastructure. The SDK is currently available for JS & Python applications, with support for other languages coming soon.

Quick start (Next.js)

A quick way to see what Arcjet can do is to deploy the example app. It’s also available at example.arcjet.com.

Clone the GitHub repository:

git clone git@github.com:arcjet/arcjet-example-nextjs-fly.git

Set up a new Fly app:

fly launch --no-deploy

This command will generate a Dockerfile and a fly.toml for you.

Create an Arcjet account and link it to your Fly app:

fly ext arcjet create

This will:

  • Create an Arcjet account linked to your Fly account.
  • Create an Arcjet team mapped to your Fly organization.
  • Create an Arcjet site for your Fly application.
  • Set ARCJET_KEY as a secret on your Fly application.

Deploy to Fly:

fly deploy

Open your app in your browser and try the features.

Review the request details in your Arcjet dashboard:

fly ext arcjet dashboard

Run locally

Arcjet protections run locally as well as when deployed to Fly. This makes it easy to test and debug security rules.

Assuming you have already cloned the example and linked Arcjet to your Fly app (see above):

Log into your Arcjet dashboard to get the ARCJET_KEY for your app.

fly ext arcjet dashboard

Install dependencies:

npm ci

Rename .env.local.example to .env.local and add your Arcjet key. If you want to test the rate limiting authentication, you will also need to add an Auth.js secret and create a GitHub OAuth app.

Start the dev server

npm run dev

Open http://localhost:3000 in your browser.

Protecting your application with Arcjet

Once you have set your ARCJET_KEY secret, you can start using Arcjet to protect your application. Arcjet supports many different web frameworks e.g. Bun, Next.js, Node.js, SvelteKit.

Node.js example

You can also find this example on GitHub.

  1. Install the Arcjet SDK:

    npm i @arcjet/node
    
  2. Add a rate limit to a route in index.ts:

    import arcjet, { tokenBucket } from "@arcjet/node";
    import http from "node:http";
    
    const aj = arcjet({
      key: process.env.ARCJET_KEY!, // Set as a secret on your Fly app
      rules: [
        // Create a token bucket rate limit. Other algorithms are supported.
        tokenBucket({
          mode: "LIVE", // will block requests. Use "DRY_RUN" to log only
          characteristics: ["userId"], // track requests by a custom user ID
          refillRate: 5, // refill 5 tokens per interval
          interval: 10, // refill every 10 seconds
          capacity: 10, // bucket maximum capacity of 10 tokens
        }),
      ],
    });
    
    const server = http.createServer(async function (
      req: http.IncomingMessage,
      res: http.ServerResponse,
    ) {
      const userId = "user123"; // Replace with your authenticated user ID
      const decision = await aj.protect(req, { userId, requested: 5 }); // Deduct 5 tokens from the bucket
      console.log("Arcjet decision", decision);
    
      if (decision.isDenied()) {
        res.writeHead(429, { "Content-Type": "application/json" });
        res.end(
          JSON.stringify({ error: "Too Many Requests", reason: decision.reason }),
        );
      } else {
        res.writeHead(200, { "Content-Type": "application/json" });
        res.end(JSON.stringify({ message: "Hello world" }));
      }
    });
    
    server.listen(8000);
    
  3. Run your application:

    npx tsx --env-file .env.local index.ts
    

Load the application and refresh the page a few times to see the rate limit in action.

Python + FastAPI example

You can also find this example on GitHub.

  1. Install the Arcjet SDK:

    mkdir arcjet-fastapi
    cd arcjet-fastapi
    uv init
    uv add arcjet "fastapi[standard]" uvicorn
    
  2. Create a new file at main.py with the contents:

    import os
    from fastapi import FastAPI, Request
    from fastapi.responses import JSONResponse
    
    from arcjet import (
        arcjet,
        shield,
        detect_bot,
        token_bucket,
        Mode,
        BotCategory,
    )
    
    app = FastAPI()
    
    aj = arcjet(
        key=os.environ["ARCJET_KEY"],  # Get your key from https://app.arcjet.com
        rules=[
            # Shield protects your app from common attacks e.g. SQL injection
            shield(mode=Mode.LIVE),
            # Create a bot detection rule
            detect_bot(
                mode=Mode.LIVE,
                allow=[
                    BotCategory.SEARCH_ENGINE,  # Google, Bing, etc
                    # Uncomment to allow these other common bot categories
                    # See the full list at https://arcjet.com/bot-list
                    # BotCategory.MONITOR, # Uptime monitoring services
                    # BotCategory.PREVIEW, # Link previews e.g. Slack, Discord
                ],
            ),
            # Create a token bucket rate limit. Other algorithms are supported
            token_bucket(
                # Tracked by IP address by default, but this can be customized
                # See https://docs.arcjet.com/fingerprints
                # characteristics: ["ip.src"],
                mode=Mode.LIVE,
                refill_rate=5,  # Refill 5 tokens per interval
                interval=10,  # Refill every 10 seconds
                capacity=10,  # Bucket capacity of 10 tokens
            ),
        ],
    )
    
    @app.get("/")
    async def hello(request: Request):
        # Call protect() to evaluate the request against the rules
        decision = await aj.protect(
            request,
            requested=5,  # Deduct 5 tokens from the bucket
        )
    
        # Handle denied requests
        if decision.is_denied():
            status = 429 if decision.reason.is_rate_limit() else 403
            return JSONResponse(
                {"error": "Denied", "reason": decision.reason.to_dict()},
                status_code=status,
            )
    
        # Check IP metadata (VPNs, hosting, geolocation, etc)
        if decision.ip.is_hosting():
            # Requests from hosting IPs are likely from bots, so they can usually be
            # blocked. However, consider your use case - if this is an API endpoint
            # then hosting IPs might be legitimate.
            # https://docs.arcjet.com/blueprints/vpn-proxy-detection
    
            return JSONResponse(
                {"error": "Denied from hosting IP"},
                status_code=403,
            )
    
        return {"message": "Hello world", "decision": decision.to_dict()}
    
  3. Run your application with your Arcjet key in the environment:

    export ARCJET_ENV=development
    export ARCJET_KEY=ajkey_yourkey
    uv run uvicorn main:app --reload
    

Pricing

See the Arcjet pricing page.

Support

Email: support@arcjet.com

Discord: Join.

See the Arcjet docs for the full support policy.