Arcjet IP detection reference
The Arcjet IP detection library provides a utility to find the public IP of a Request.
What are Arcjet utilities?
Arcjet utilities are independent libraries that do not require the use of the main Arcjet SDK - they can be used with or without other Arcjet rules.
We take the pain out of implementing security tasks through these utilities to provide a security as code approach to developer-first security.
The public IP of a Request is difficult to discern, but some platforms provide
specific mechanisms for accessing it - such as the X-Real-IP header added or
overwritten by Vercel. The @arcjet/ip library provides a streamlined API over
these mechanisms based on the current platform.
Install
Section titled “Install”npm install -S @arcjet/ipimport ip from "@arcjet/ip";
// Some Request-like object, such as node's `http.IncomingMessage`, `Request` or// Next.js' `NextRequest`const request = new Request("/your-route");
// Returns the first non-private IP address detectedconst publicIp = ip(request);console.log(publicIp);Platform protections
Section titled “Platform protections”Additional guards can be applied with the platform option, such as
{ platform: "fly-io" }, { platform: "cloudflare" }, or
{ platform: "vercel" }.
import ip from "@arcjet/ip";
// Some Request-like object, such as node's `http.IncomingMessage`, `Request` or// Next.js' `NextRequest`const request = new Request("/your-route");
// Also optionally takes a platform for additional protectionconst platformGuardedPublicIp = ip(request, { platform: "fly-io" });console.log(platformGuardedPublicIp);Proxy filtering
Section titled “Proxy filtering”Most proxies will add themselves in the chain of public IP addresses. Trusted
proxies may be specified with the proxies option, and they will be
ignored when detecting a public IP.
import ip from "@arcjet/ip";
// Some Request-like object, such as node's `http.IncomingMessage`, `Request` or// Next.js' `NextRequest`const request = new Request("/your-route");
// You can also pass a list of trusted proxies to ignoreconst proxyExcludedPublicIp = ip(request, { proxies: [ "100.100.100.100", // A single IP "100.100.100.0/24", // A CIDR for the range ],});console.log(proxyExcludedPublicIp);Proxy services
Section titled “Proxy services”The proxies option also accepts proxy services alongside plain IP addresses.
A proxy service knows the IP ranges that belong to a particular provider and the
header that provider uses to pass through the real client IP. When a request
arrives from one of the service’s IP ranges, the real client IP is read from
that header instead of the connecting address.
This is safer than trusting a header on its own: the header is only used when the connecting address falls within the service’s verified IP ranges, so a direct client cannot spoof it.
Cloudflare
Section titled “Cloudflare”The cloudflare() helper is the proxy service for
Cloudflare. When a request comes from a Cloudflare
IP range, ip() reads the real client IP from the CF-Connecting-IP (or
CF-Connecting-IPv6) header that Cloudflare sets.
import ip, { cloudflare } from "@arcjet/ip";
// Some Request-like object, such as node's `http.IncomingMessage`, `Request` or// Next.js' `NextRequest`const request = new Request("/your-route");
// Pass the `cloudflare()` proxy service to read the real client IP from// Cloudflare's `CF-Connecting-IP` header, but only when the request comes from// a known Cloudflare IP rangeconst publicIp = ip(request, { proxies: [cloudflare()],});console.log(publicIp);The Cloudflare IP ranges are bundled with @arcjet/ip and kept up to date as
the package is released. If Cloudflare publishes a new range before the SDK has
been updated, you can override the bundled ranges with the ranges option. This
replaces the bundled list rather than adding to it, so supply the full set
of ranges from cloudflare.com/ips plus any new
range:
import ip, { cloudflare } from "@arcjet/ip";
const request = new Request("/your-route");
// Override the bundled Cloudflare ranges with your own list. This *replaces*// the bundled ranges, so include the full list from https://www.cloudflare.com/ips/// plus any new range Cloudflare has added that the SDK doesn't know about yet.const publicIp = ip(request, { proxies: [ cloudflare({ ranges: [ // The current Cloudflare ranges... "173.245.48.0/20", "103.21.244.0/22", // ...plus a new range not yet bundled in the SDK "203.0.113.0/24", ], }), ],});console.log(publicIp);ip(request: RequestLike, options?: Options)
Section titled “ip(request: RequestLike, options?: Options)”Look up an IP address in a Request-like object, such as Request, Node’s
http.IncomingMessage, or Next.js’ NextRequest.
Types:
type RequestLike = { info?: PartialInfo | null | undefined; ip?: unknown; requestContext?: PartialRequestContext | null | undefined; socket?: PartialSocket | null | undefined; headers: Headers | Record<string, string[] | string | undefined>;};type Options = { platform?: Platform | null | undefined; proxies?: readonly (string | Cidr | ProxyService)[] | null | undefined;};type Platform = "cloudflare" | "firebase" | "fly-io" | "render" | "vercel";cloudflare(options?: CloudflareOptions)
Section titled “cloudflare(options?: CloudflareOptions)”Returns a ProxyService for Cloudflare that can be passed in the proxies
option. Pass ranges to override the bundled Cloudflare IP ranges (this replaces
the bundled list).
Types:
type ProxyService = { kind: "service"; name: string; ranges: ReadonlyArray<string | Cidr>; clientIp: ReadonlyArray<ClientIpHeader>;};type CloudflareOptions = { ranges?: readonly string[] | null | undefined;};What next?
Section titled “What next?”Arcjet can protect your entire app or individual routes with just a few lines of code. Using the main Arcjet SDK you can setup bot protection, rate limiting for your API, minimize fraudulent registrations with the signup form protection and more.