Overview
The @CrudAuth() decorator provides built-in authentication and authorization for CRUD operations. It allows you to filter queries, persist user data, and control access based on the authenticated user.
Basic Usage
Apply the @CrudAuth() decorator to your controller:
import { Controller } from '@nestjs/common';
import { Crud, CrudAuth } from '@nestjsx/crud';
import { User } from './user.entity';
import { UsersService } from './users.service';
@Crud({
model: { type: User },
routes: {
only: ['getOneBase', 'updateOneBase'],
},
})
@CrudAuth({
filter: (user: User) => ({
id: user.id,
}),
})
@Controller('me')
export class MeController {
constructor(public service: UsersService) {}
}
This ensures users can only access their own data.
Configuration Options
The @CrudAuth() decorator accepts an AuthOptions object:
Filter
Automatically filter queries based on the authenticated user:
@CrudAuth({
filter: (user: User) => ({
userId: user.id,
}),
})
The filter is applied to all read operations (getMany, getOne).
Persist
Automatically add user data to create/update operations:
my-projects.controller.ts
@Crud({
model: { type: UserProject },
})
@CrudAuth({
filter: (user: User) => ({
userId: user.id,
}),
persist: (user: User) => ({
userId: user.id,
}),
})
@Controller('my-projects')
export class MyProjectsController {
constructor(public service: UserProjectsService) {}
}
The persist function automatically adds userId to all create and update requests.
OR Conditions
Add OR conditions to your filters:
@CrudAuth({
filter: (user: User) => ({
ownerId: user.id,
}),
or: (user: User) => ({
assignedTo: user.id,
}),
})
This allows users to see records they own OR are assigned to.
Customize serialization based on the user:
@CrudAuth({
property: 'user',
classTransformOptions: (req) => ({
groups: req.user.isAdmin ? ['admin'] : ['user'],
}),
})
Groups
Shorthand for setting serialization groups:
@CrudAuth({
groups: (req) => {
return req.user.isAdmin ? ['admin', 'sensitive'] : ['user'];
},
})
Global Configuration
Set global authentication settings in main.ts:
import { CrudConfigService } from '@nestjsx/crud';
CrudConfigService.load({
auth: {
property: 'user', // Default request property for user
},
});
The property option specifies where to find the authenticated user on the request object (e.g., req.user).
Complete Example
Here’s a comprehensive authentication setup:
import { Controller } from '@nestjs/common';
import { Crud, CrudAuth } from '@nestjsx/crud';
import { Project } from './project.entity';
import { ProjectsService } from './projects.service';
import { User } from '../users/user.entity';
@Crud({
model: { type: Project },
query: {
join: {
users: {},
company: {},
},
},
})
@CrudAuth({
// Only show projects the user owns or is a member of
filter: (user: User) => ({
ownerId: user.id,
}),
or: (user: User) => ({
'users.id': user.id,
}),
// Automatically set owner on create
persist: (user: User) => ({
ownerId: user.id,
}),
// Custom serialization for admins
groups: (req) => {
return req.user.role === 'admin'
? ['admin', 'detailed']
: ['basic'];
},
})
@Controller('my-projects')
export class MyProjectsController {
constructor(public service: ProjectsService) {}
}
Using with Guards
Combine with NestJS guards for authentication:
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
@Injectable()
export class AuthGuard implements CanActivate {
canActivate(context: ExecutionContext): boolean {
const request = context.switchToHttp().getRequest();
// Your authentication logic here
// Set request.user if authenticated
return !!request.user;
}
}
Apply globally:
import { Module } from '@nestjs/common';
import { APP_GUARD } from '@nestjs/core';
import { AuthGuard } from './auth.guard';
@Module({
providers: [
{
provide: APP_GUARD,
useClass: AuthGuard,
},
],
})
export class AppModule {}
Multi-Tenancy Example
Implement multi-tenancy with company-based filtering:
import { Controller } from '@nestjs/common';
import { Crud, CrudAuth } from '@nestjsx/crud';
import { User } from './user.entity';
import { UsersService } from './users.service';
@Crud({
model: { type: User },
params: {
companyId: {
field: 'companyId',
type: 'number',
},
},
})
@CrudAuth({
filter: (user: User) => ({
companyId: user.companyId,
}),
persist: (user: User) => ({
companyId: user.companyId,
}),
})
@Controller('/companies/:companyId/users')
export class UsersController {
constructor(public service: UsersService) {}
}
Advanced Filtering
Use complex conditions in your filters:
@CrudAuth({
filter: (user: User) => {
// Admins see everything
if (user.role === 'admin') {
return {};
}
// Managers see their team's data
if (user.role === 'manager') {
return {
teamId: user.teamId,
};
}
// Regular users see only their data
return {
userId: user.id,
};
},
})
Request Property
Access the user from different request properties:
@CrudAuth({
property: 'currentUser', // Use req.currentUser instead of req.user
filter: (user: User) => ({
id: user.id,
}),
})
Security Best Practices
Always validate and sanitize user input, even when using @CrudAuth(). The decorator filters data but doesn’t prevent malicious requests.
Always Use Guards
Combine @CrudAuth() with authentication guards to ensure only authenticated users can access endpoints.
Filter Sensitive Data
Use the filter option to ensure users can only access their own data or data they’re authorized to see.
Validate Ownership
For update and delete operations, ensure users can only modify resources they own.
Use Serialization
Combine with serialization to control which fields different user roles can see.
Troubleshooting
User Not Found on Request
If the user object is not found:
- Ensure your authentication guard sets
request.user
- Verify the
property configuration matches your setup
- Check that the guard executes before CRUD operations
Filters Not Applied
If filters aren’t working:
- Verify the filter function returns a valid condition object
- Check that field names match your entity properties
- Ensure the user object has the expected properties