Overview
Learning how to retrieve a client’s IP address in NestJS is essential for many web applications that depend on geolocation, rate limiting, logging, or authentication. This article delves into several methods to achieve this, tailored for NestJS applications.
Prerequisites
Before we begin, ensure you have the following installed:
- Node.js (>= 10.x)
- NestJS CLI
Also, you should have a basic understanding of TypeScript and NestJS fundamentals to follow along effectively.
Basic Method: Using Request Object
To begin, we will look at the most straightforward approach – accessing the IP directly from the request object.
import { Controller, Get, Req } from '@nestjs/common';
import { Request } from 'express';
@Controller('get-ip')
export class IpController {
@Get()
public getClientIp(@Req() request: Request): string {
return request.ip;
}
}
Note that NestJS uses Express under the hood, and the request.ip is a feature of Express that captures the client’s IP address.
Using Request Headers
In scenarios where your app is behind a proxy or load balancer, retrieving the IP directly from the request might not give you the actual client IP due to IP masquerading.
To overcome this, inspect the X-Forwarded-For header, which proxies typically use to forward the originating IP address of a client connecting to a web server.
import { Controller, Get, Headers } from '@nestjs/common';
@Controller('get-ip')
export class IpController {
@Get('header')
public getClientIpThroughHeader(@Headers('x-forwarded-for') ip: string): string {
const clientIp = ip.split(',')[0];
return clientIp;
}
}
This method splits the X-Forwarded-For header since it can contain a list of IPs if the request passed through multiple proxies.
Creating a Custom Decorator
If getting the IP address is a common task in your application, creating a custom decorator to encapsulate this logic is a good approach.
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
export const ClientIp = createParamDecorator(
(data: unknown, ctx: ExecutionContext): string => {
const request = ctx.switchToHttp().getRequest();
const ip = (request.headers['x-forwarded-for'] || '').split(',')[0] || request.ip;
return ip;
},
);
Using this decorator, the method in any controller can now look like:
import { Controller, Get} from '@nestjs/common';
@Controller('get-ip')
export class IpController {
@Get('decorator')
public getClientIp(@ClientIp() ip: string): string {
return ip;
}
}
Advanced: IP Extraction in Middleware
For applications needing the IP for various middleware-level operations like rate limiting or logging, you can decode the IP at the middleware stage and make it universally available in the request object.
import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';
@Injectable()
export class IpMiddleware implements NestMiddleware {
use(req: Request, res: Response, next: NextFunction) {
req['clientIp'] = (req.headers['x-forwarded-for'] || '').split(',')[0].trim() || req.connection.remoteAddress;
next();
}
}
To apply this middleware globally, alter your main.ts file:
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { IpMiddleware } from './ip.middleware';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.use(new IpMiddleware().use);
await app.listen(3000);
}
bootstrap();
Assessing Client’s IP with Guards
NestJS Guards can also be an effective location for IP assessment, especially when you want to add additional authentication logic based on IP addresses.
...
// The implementation of a guard that checks the IP address would typically involve an canActivate method that contains similar logic to the above examples.
Dealing with IPv6 and Compatibility
The approaches above work for both IPv4 and IPv6. However, IPv6 addresses are sometimes accompanied by a prefix which you may need to strip off depending on your use case. Care should be taken to properly parse and format IP addresses in such scenarios.
Using a Trust Proxy
If you’re utilizing a service like Heroku or other cloud providers, you might need to enable trust proxy settings inside your NestJS app to handle IP retrieval securely and correctly.
// main.ts
const app = await NestFactory.create(AppModule);
app.set('trust proxy', true);
...
By setting ‘trust proxy’, we tell Express to trust the headers set by our proxy and thus the forwarded IP addresses.
Conclusion
Understanding the network configuration of your deployment environment is key to correctly implementing client IP address extraction in a NestJS application. Different scenarios may require different approaches, and it’s important to consider the implications of each to ensure that security and functionality are upheld. With the techniques discussed in this tutorial, you should be positioned to effectively manage and use IP information within your NestJS applications.