Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow Controller-Level guards to explicitly override global guards #14352

Closed
1 task done
davidmunoz-dev opened this issue Dec 25, 2024 · 1 comment
Closed
1 task done
Labels
needs triage This issue has not been looked into type: enhancement 🐺

Comments

@davidmunoz-dev
Copy link

Is there an existing issue that is already proposing this?

  • I have searched the existing issues

Is your feature request related to a problem? Please describe it

The current behavior of global guards applied via APP_GUARD makes it impossible to override or exclude them at the controller level using @UseGuards(). While workarounds such as metadata checks or scoped guards exist, these approaches feel unintuitive and can add unnecessary boilerplate to projects.
Developers could expect @UseGuards() at the controller or route level to override global guards when explicitly defined, but this does not work as anticipated.

This limitation can lead to frustration and confusion for developers, especially when trying to apply guards selectively without affecting other routes.

@Module({
    imports: [
        AdminControllersModule,
    ],
    controllers: [],
    providers: [
        {
            provide: APP_GUARD,
            useClass: JwtAuthGuard,
        },
        {
            provide: APP_GUARD,
            useClass: AdminUserGuard,
        },
    ],
})

Describe the solution you'd like

Introduce a mechanism in NestJS that allows controller-level or route-level guards (applied using @UseGuards()) to explicitly override global guards. This could work as follows:

If @UseGuards() is applied to a controller or route, it overrides any global guards for that scope.
Provide an additional optional parameter in @UseGuards() to specify whether the override is complete (removes global guards) or additive (merges with global guards).

Example:

@Controller()
@ApiTags('Health Admin')
@UseGuards(NoAuthGuard, { override: true }) // Explicitly disables global guards
export class HealthAdminController {
    @Get()
    getHealth(): string {
        return "[Admin]: I'm healthy!";
    }
}

This would allow developers to have full control over guard application without relying on metadata or custom logic in global guards.

I have no idea how APP_GUARD is implemented under the hood, I think it relies on useGlobalGuards, so I have no clue how difficult this would be.

Teachability, documentation, adoption, migration strategy

Teachability: This feature aligns with intuitive expectations. Developers already use @UseGuards() to apply guards at different levels. Extending this decorator to override global guards fits naturally into the existing API and mental model.

Documentation: Update the @UseGuards() section in the NestJS documentation to include an example of overriding global guards. Include a note on how to migrate existing workarounds (like metadata) to use this feature.

Adoption: Since this feature does not break existing functionality, adoption would be seamless. Developers can start using it for new projects without affecting existing codebases.

Migration Strategy: Existing applications using metadata or scoped guards can continue to work as is. No migration is required unless developers want to adopt the new feature for better clarity and simplicity.

What is the motivation / use case for changing the behavior?

The motivation is to provide developers with a straightforward and consistent way to manage guard application in NestJS. Key use cases include:

Simplifying controller logic by allowing @UseGuards() to override global guards without relying on metadata or custom guard logic.

Reducing boilerplate code when certain routes or controllers must bypass global security policies.

Improving developer experience by aligning behavior with expectations—@UseGuards() should control all guards at its scope.

This feature would enhance NestJS's flexibility while maintaining security and clarity in guard management. It would also reduce confusion among new developers and align with the principle of least surprise.

@davidmunoz-dev davidmunoz-dev added needs triage This issue has not been looked into type: enhancement 🐺 labels Dec 25, 2024
@kamilmysliwiec
Copy link
Member

Use Reflector for this https://docs.nestjs.com/guards#setting-roles-per-handler

Thank you for taking the time to submit your report! From the looks of it, this could be better discussed on our Discord. If you haven't already, please join here and send a new post in the #⁠ 🐈 nestjs-help forum. Make sure to include a link to this issue, so you don't need to write it all again. We have a large community of helpful members, who will assist you in getting this to work.

@nestjs nestjs locked and limited conversation to collaborators Dec 27, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
needs triage This issue has not been looked into type: enhancement 🐺
Projects
None yet
Development

No branches or pull requests

2 participants