Open justinfarrelldev opened 1 month ago
Hi @justinfarrelldev! We don't have official Remix support yet, but Arcjet will work and we know of several people using it without any issues. However, support depends on which Remix adapter you're using - Arcjet will work with the default Remix server (which uses Express) and also with Node or Vercel.
I just tested using our Node SDK in a Remix loader function and it worked correctly. There is a type-mismatch warning when you pass the request
parameter into aj.project()
but you can ignore it.
This uses https://github.com/sergiodxa/remix-utils#getclientipaddress to get the IP address, which is installed with:
npm install remix-utils is-ip
Then you can manually construct the request props with the IP included:
import arcjet, { tokenBucket } from "arcjet";
import type { LoaderFunctionArgs, MetaFunction } from "@remix-run/node";
import { getClientIPAddress } from "remix-utils/get-client-ip-address";
const aj = arcjet({
key: process.env.ARCJET_KEY!, // Get your site key from https://app.arcjet.com
characteristics: ["userId"], // track requests by a custom user ID
rules: [
// Create a token bucket rate limit. Other algorithms are supported.
tokenBucket({
mode: "LIVE", // will block requests. Use "DRY_RUN" to log only
refillRate: 5, // refill 5 tokens per interval
interval: 10, // refill every 10 seconds
capacity: 10, // bucket maximum capacity of 10 tokens
}),
],
});
export async function loader({
request,
}: LoaderFunctionArgs) {
// Construct an object with Arcjet request details
const path = new URL(request.url || "", `http://${request.headers.get("host")}`);
const details = {
ip: getClientIPAddress(request),
method: request.method,
host: request.headers.get("host"),
url: path.pathname,
headers: request.headers,
};
const userId = "user123"; // Replace with your authenticated user ID
const decision = await aj.protect(details, { userId, requested: 5 }); // Deduct 5 tokens from the bucket
console.log("Arcjet decision", decision);
if (decision.isDenied()) {
throw new Response("Too many requests", {
status: 429,
});
} else {
return null;
}
}
...
If you create a custom express server for Remix, then you can also put Arcjet in there e.g. for running Shield on every request. We have an example with a generic Express server at https://github.com/arcjet/arcjet-js/blob/main/examples/nodejs-express-rl/index.js
Hi @justinfarrelldev! We don't have official Remix support yet, but Arcjet will work and we know of several people using it without any issues. However, support depends on which Remix adapter you're using - Arcjet will work with the default Remix server (which uses Express) and also with Node or Vercel.
I just tested using our Node SDK in a Remix loader function and it worked correctly. There is a type-mismatch warning when you pass the
request
parameter intoaj.project()
but you can ignore it.import arcjet, { tokenBucket } from "@arcjet/node"; import type { LoaderFunctionArgs, MetaFunction } from "@remix-run/node"; const aj = arcjet({ key: process.env.ARCJET_KEY!, // Get your site key from https://app.arcjet.com characteristics: ["userId"], // track requests by a custom user ID rules: [ // Create a token bucket rate limit. Other algorithms are supported. tokenBucket({ mode: "LIVE", // will block requests. Use "DRY_RUN" to log only refillRate: 5, // refill 5 tokens per interval interval: 10, // refill every 10 seconds capacity: 10, // bucket maximum capacity of 10 tokens }), ], }); export async function loader({ request, }: LoaderFunctionArgs) { const userId = "user123"; // Replace with your authenticated user ID const decision = await aj.protect(request, { userId, requested: 5 }); // Deduct 5 tokens from the bucket console.log("Arcjet decision", decision); if (decision.isDenied()) { throw new Response("Too many requests", { status: 429, }); } else { return null; } } ...
If you create a custom express server for Remix, then you can also put Arcjet in there e.g. for running Shield on every request. We have an example with a generic Express server at https://github.com/arcjet/arcjet-js/blob/main/examples/nodejs-express-rl/index.js
Awesome, thank you so much for the extremely thorough reply! I'll definitely give it a go 😁
On testing this in production, Remix doesn't actually provide the IP - when you use Arcjet locally it's using a local IP.
From the discussion at https://github.com/remix-run/remix/discussions/2413 the suggestion is to use a utility from https://github.com/sergiodxa/remix-utils#getclientipaddress to get the IP address. We'll look at how we can do this for you in our official SDK, but for now I've adjusted the above code sample (https://github.com/arcjet/arcjet-js/issues/1313#issuecomment-2278377980) to use it.
Hello, I see that this project has Next.js support, however it is unclear whether Remix support is in the works or works out-of-the-box for the Next.js package. Are there perhaps any plans to include Remix (or, I guess since it is being merged with React Router, React Router) support?
Thank you, and I love this project so far! I can tell this will be extremely useful when I develop APIs in the future.