UNPKG

get-client-ip

Version:

📍 A Lightweight Utility for Extracting the Real Client IP Address from Incoming HTTP Requests

72 lines (69 loc) 2.87 kB
import { IncomingHttpHeaders } from 'node:http'; type NonEmptyArray<T> = [T, ...T[]]; /** Minimal request interface — any object with headers and socket (Express v4, v5, etc.). */ interface IpRequest { ip?: string; headers: IncomingHttpHeaders; socket?: { remoteAddress?: string; }; clientIp?: string; clientIps?: NonEmptyArray<string>; } /** * Extracts the client's IP address from an incoming Express request. * * This function works both as a standalone utility and as Express middleware. * It attempts to detect the IP by inspecting common proxy-related headers * such as `forwarded` (RFC 7239), `x-forwarded-for`, `x-real-ip`, and others. If no valid IP is found * in the headers, it falls back to `req.socket.remoteAddress`. * Header fallback is skipped when `req.socket.remoteAddress` is a public address, * reducing spoofing risk for direct internet-facing connections. * * When used as middleware, it populates: * - `req.clientIp`: The first valid IP address found. * - `req.clientIps`: A non-empty array of all valid IPs found. * * **Security note — trust boundary:** This function checks `req.ip` first (which * respects Express's `trust proxy` setting). When `req.ip` is falsy, it * reads forwarding headers **only** if the socket peer (`req.socket.remoteAddress`) * is a recognized private/proxy address. When the socket identity is absent or * public, headers are **not** trusted and the function falls back to * `req.socket.remoteAddress` directly. In production behind a reverse proxy, * configure Express's `trust proxy` so `req.ip` is populated correctly and * treated as the primary source of truth. * * @param req - The Express request object. * @param res - (Optional) The Express response object. Included to support middleware signature. * @param next - (Optional) The next function in the Express middleware chain. * * @returns The first detected client IP address as a string, or `undefined` if none is found. * * @throws Will throw an error if the `req` argument is not defined. * * @example * // Standalone usage: * app.get('/standalone-ip', (req, res) => { * const ip = getClientIp(req); * res.status(200).json({ ip }); * }); * * @example * // Middleware usage: * app.use(getClientIp); * app.get('/middleware-ip', (req, res) => { * res.status(200).json({ ip: req.clientIp, ips: req.clientIps }); * }); */ declare function getClientIp(req: IpRequest, res?: unknown, next?: (...args: any[]) => void): string | undefined; declare global { namespace Express { interface Request { /** The first IP address extracted from the request. */ clientIp?: string; /** All IP addresses extracted from the request. */ clientIps?: NonEmptyArray<string>; } } } export { type IpRequest, getClientIp };