Changelog
Updated
3 min read

Arcjet changelog 2024-03

Arcjet changelog of product updates for March 2024.

Arcjet changelog 2024-03

Arcjet helps developers protect their apps in just a few lines of code. Implement rate limiting, bot protection, email verification & defend against common attacks.

This is the changelog of product updates for March 2024.

JS SDK

We released 2 new JS SDK versions in March: v1.0.0-alpha.9 and v1.0.0-alpha.10.

Node.js SDK

Our first SDK targeted the Next.js framework so the release of our Node.js SDK broadens our support to all Node.js applications. Whether you're using vanilla node:http or a framework like Express, you can now protect all Node.js code.

import arcjet, { fixedWindow } from "@arcjet/node";
import express from "express";

const app = express();
const port = 3000;

const aj = arcjet({
  // Get your site key from https://app.arcjet.com and set it as an environment
  // variable rather than hard coding.
  key: process.env.ARCJET_KEY,
  rules: [
    // Fixed window rate limit. Arcjet also supports sliding window and token
    // bucket.
    fixedWindow({
      mode: "LIVE", // will block requests. Use "DRY_RUN" to log only
      // Limiting by ip.src is the default if not specified
      //characteristics: ["ip.src"],
      window: "1m", // 1 min fixed window
      max: 1, // allow a single request (for demo purposes)
    }),
  ],
});

app.get("/", async (req, res) => {
  const decision = await aj.protect(req);

  if (decision.isDenied()) {
    res.writeHead(429, { "Content-Type": "application/json" });
    res.end(JSON.stringify({ error: "Too Many Requests" }));
  } else {
    res.writeHead(200, { "Content-Type": "application/json" });
    res.end(JSON.stringify({ message: "Hello World" }));
  }
});

app.listen(port, () => {
  console.log(`Example app listening on port ${port}`);
});

Using Arcjet's Node.js SDK to implement a rate limit on an Express server route.

Rate limit header decorators

Rate limits can be used to protect endpoints from attack, but are also used to enforce quotas for APIs. In the latter case, you may want to inform users about the remaining limits.

The common approach is to add RateLimit and RateLimit-Policy headers as defined by the draft IETF spec. The new @arcjet/decorate package allows you to easily add those headers to your response.

import arcjet, { fixedWindow } from "@arcjet/next";
import { setRateLimitHeaders } from "@arcjet/decorate";
import { NextResponse } from "next/server";

const aj = arcjet({
  key: process.env.ARCJET_KEY,
  rules: [
    fixedWindow({
      mode: "LIVE",
      // Limiting by ip.src is the default if not specified
      //characteristics: ["ip.src"],
      window: "1h",
      max: 60,
    }),
  ],
});

export async function GET(req: Request) {
  const decision = await aj.protect(req);

  const headers = new Headers();

  setRateLimitHeaders(headers, decision);

  if (decision.isDenied()) {
    return NextResponse.json(
      {
        error: "Too Many Requests",
        reason: decision.reason,
      },
      { status: 429, headers },
    );
  }

  return NextResponse.json(
    {
      message: "Hello world",
    },
    { status: 200, headers },
  );
}

Using the @arcjet/decorate package to setRateLimitHeaders on the HTTP response.

Add ad-hoc rules

The aj instance is usually defined outside of the route handler so it can be created once and stay alive across requests for better performance. Rules are defined when you create the instance, but sometimes you might want to adjust the rule from within the handler e.g. to apply different rules for different users.

The withRule API (Next.js docs, Node.js docs) now allows you to do this.

import arcjet, { fixedWindow } from "@arcjet/node";
import http from "node:http";

const aj = arcjet({
  key: process.env.ARCJET_KEY!, // Get your site key from https://app.arcjet.com
  rules: [],
});

function getClient(userId?: string) {
  if (userId) {
    return aj;
  } else {
    // Only rate limit non-users
    return aj.withRule(
      fixedWindow({
        max: 10,
        window: "1m",
      }),
    );
  }
}

const server = http.createServer(async function (
  req: http.IncomingMessage,
  res: http.ServerResponse,
) {
  // This userId is hard coded for the example, but this is where you would do a
  // session lookup and get the user ID.
  const userId = "totoro";

  const decision = await getClient(userId).protect(req);

  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);

Setting an ad-hoc rule using the withRule API in Node.js.

Protecting NextAuth / Auth.js

We use Arcjet on our own dashboard NextAuth login routes to protect against brute-force attacks, so we created integration guides. There is now documentation for protecting NextAuth 4 and Auth.js 5 login routes and example apps for both.

Dashboard

The requests inspector defaults to showing timestamps in your local timezone, but you can now toggle into UTC. Hover over the timestamp to see the other time. Useful if you're following the rule that all servers should be configured in UTC!

Screenshot of the Arcjet dashboard showing the timezone toggle.

Community

We're now running a Discord server if you want to come by and ask any questions.

And I'll leave you with a notable mention on Twitter:

Subscribe by email

Get the full posts by email every week.