Hello, I'm Maneshwar. I'm building git-lrc, an AI code reviewer that runs on every commit. It is free, unlimited, and source-available on Github. Star Us to help devs discover the project. Do give it a try and share your feedback for improving the product.
Hello, I'm Maneshwar. I'm working on FreeDevTools online currently building **one place for all dev tools, cheat codes, and TLDRs* — a free, open-source hub where developers can quickly find and use tools without any hassle of searching all over the internet.
Decorators and middleware are the bread and butter of NestJS—tools that can make your life either incredibly easy or slightly overwhelming, depending on how you approach them.
Today, let’s walk through creating a custom decorator and middleware for user authentication, all while keeping things light and straightforward. Grab your coffee, and let’s dive in!
1. The Interface
’s define an interface for our user object.
This will ensure type safety and keep our IDE happy (and who doesn’t love a happy IDE?).
export interface IUser {
id: string;
name: string;
primaryEmail: string;
phoneNumber: string | null;
countryCode: string | null;
dob: Date | null;
createdAt: Date;
updatedAt?: Date;
deletedAt?: Date | null;
}
2. Creating a Custom Decorator
Custom decorators are like the cool kids in a NestJS application.
Here, we’re making one to fetch user metadata from the request object.
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
import { IUser } from '../interface/user.interface';
export const UserMetadata = createParamDecorator(
(_data: unknown, ctx: ExecutionContext) => {
const request = ctx.switchToHttp().getRequest();
return request.user as IUser;
},
);
That’s it! This decorator can now be used to pull user info directly in your controller methods.
3. Creating the Auth Middleware
Now, let’s create an AuthGuard to protect our endpoints like a virtual bouncer.
import {
CanActivate,
ExecutionContext,
ForbiddenException,
Injectable
} from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { verify } from 'jsonwebtoken';
import { Observable } from 'rxjs';
import { IS_PUBLIC_KEY } from '../constant/core';
import { IUser } from '../interface/user.interface';
@Injectable()
export class AuthGuard implements CanActivate {
constructor(
private reflector: Reflector,
) { }
canActivate(
context: ExecutionContext,
): boolean | Promise<boolean> | Observable<boolean> {
const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [
context.getHandler(),
context.getClass(),
]);
if (isPublic) {
return true;
}
const request = context.switchToHttp().getRequest();
const headers = request.headers;
const token = (headers['authorization'] || '').split(' ')[1];
if (!token) {
throw new ForbiddenException('Not Authenticated');
}
const jwtOpts = {
expiresIn: '1h', // Replace with env vars in real use
audience: 'your-audience',
algorithm: 'HS256',
issuer: 'your-issuer',
};
try {
const decoded = verify(token, "my-jwt-secret-token", {
audience: jwtOpts.audience,
issuer: jwtOpts.issuer,
}) as { user: IUser };
request.user = decoded.user;
return true;
} catch (err) {
throw new ForbiddenException('Session Expired or Invalid');
}
}
}
4. Adding Metadata for Public and Internal Routes
Some routes should be public (like login), and some might be internal.
Let’s add two simple decorators for that.
import { SetMetadata } from '@nestjs/common';
export const IS_PUBLIC_KEY = 'isPublic';
export const IS_INTERNAL = 'isInternal';
export const Public = () => SetMetadata(IS_PUBLIC_KEY, true);
export const Internal = () => SetMetadata(IS_INTERNAL, true);
5. Using Them in a Controller
Finally, here’s how you can use all of these in your controller.
import { Controller, Get, UseGuards } from '@nestjs/common';
import { UserMetadata } from '../decorators/user.decorator';
import { AuthGuard } from '../guards/auth.guard';
import { Public } from '../decorators/public.decorator';
@Controller('users')
export class UserController {
@Public()
@Get('login')
login() {
return { message: 'Login endpoint (public)' };
}
@UseGuards(AuthGuard)
@Get('profile')
getProfile(@UserMetadata() user: IUser) {
return {
message: 'User Profile',
user,
};
}
}
Wrapping Up
And there you have it! You’ve created a custom decorator, middleware, and metadata decorators to manage public routes.
Using these tools, you can build secure and organized APIs in NestJS.
If this felt like too much, remember—even Rome wasn’t built in a day, but your APIs can definitely scale faster!
Feel free to tweak and experiment with these snippets.
The sky’s the limit with NestJS! 🚀
I’ve been workinIt’s designed to makeAPI documentation effortless for developers.
I’ve been building a collection of UI/UX-focused tools crafted to simplify workflows, save time, and reduce friction in searching tools/materials.
Any feedback or contributors are welcome!
It’s online, open-source, and ready for anyone to use.
👉 Check it out: FreeDevTools
⭐ Star it on GitHub: freedevtools
Let’s make it even better together.
*AI agents write code fast. They also silently remove logic, change behavior, and introduce bugs -- without telling you. You often find out in production.
git-lrc fixes this. It hooks into git commit and reviews every diff before it lands. 60-second setup. Completely free.*
Any feedback or contributors are welcome! It's online, source-available, and ready for anyone to use.
⭐ Star it on GitHub:
HexmosTech
/
git-lrc
Free, Unlimited AI Code Reviews That Run on Commit
AI agents write code fast. They also silently remove logic, change behavior, and introduce bugs -- without telling you. You often find out in production.
git-lrc fixes this. It hooks into git commit and reviews every diff before it lands. 60-second setup. Completely free.
See It In Action
See git-lrc catch serious security issues such as leaked credentials, expensive cloud operations, and sensitive material in log statements
git-lrc-intro-60s.mp4
Why
- 🤖 AI agents silently break things. Code removed. Logic changed. Edge cases gone. You won't notice until production.
- 🔍 Catch it before it ships. AI-powered inline comments show you exactly what changed and what looks wrong.
- 🔁 Build a habit, ship better code. Regular review → fewer bugs → more robust code → better results in your team.
- 🔗 Why git? Git is universal. Every editor, every IDE, every AI…


Top comments (2)
Thanks for sharing step to step information for creating Decorator and Middleware in NestJS.
Welcome :)