-
-
Notifications
You must be signed in to change notification settings - Fork 389
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
Auth for NestJS and Fastify #698
Comments
Did you checked the examples folder? |
@anteqkois Did you manage to set up the authentication? |
Hi @felixmosh the example directory seem to have code for ExpressAdapter but not for FastifyAdapter. I'm also trying to implement auth for bullboard. Is there any reference for auth with Nest+Fastify? Thanks for the awesome library. |
Nope, I don't have secret examples that are not in the examples folder 😅 |
I'm also struggling trying to figure out how to add Authentication via the Nest.js Module approach. |
For now, I'm just disabling the access of bull board UI in Nginx and access it with ssh and port forwarded to my local. It's a bit cumbersome but works. |
@felixmosh can you reopen this? There is a real need for an example of using Bull Board with NestJS. At the very least this issue can be a call for someone to provide such an example. I've been struggling with this for the past few hours, and there is a lot to understand between Bull Board, NestJS, Passport (most likely), and the underlying server adapter (e.g., Express or Fastify). I understand most of these components individually. Putting them together is proving more difficult than I anticipated. An example would go a long way toward saving many others hours of effort. Edit: Now that I've dug into the code itself, it seems that bull-board/packages/nestjs/src/bull-board.root-module.ts Lines 27 to 41 in eac5169
We effectively need to treat this as a separate middleware that exists almost entirely outside of the NestJS framework. |
@clintonb do you have any improvment for the Nest.js adapter? |
Hey guys, bull-board nestjs package supports "express, fastify" middlewares, so it should be very easy to add authentication.
that will trigger auth basic when you access to "/queues" @felixmosh maybe we can add this in the readme... |
can you make a PR that update the nest.js README file? |
I really wish Bull Board was updated to be a more "Nesty" app instead of operating as an independent Express app. I ultimately did the following:
This ensures that users must be authenticated to access Bull Board, and authentication is powered by existing components (e.g., Passport). Here is come code. // NOTE: BullBoardModule interfaces directly with Express. We implement some custom middleware to
// adapt our NestJS guards into compatible Express middleware so we can avoid duplicating logic.
BullBoardModule.forRootAsync({
imports: [AdminAuthModule],
inject: [RedirectToLoginGuard],
useFactory: (guard: RedirectToLoginGuard) => {
return {
route: '/queues',
adapter: ExpressAdapter,
middleware: [guardToMiddleware(guard)],
};
},
}) /**
* Convert an authentication guard to Express middleware.
*
* This useful for integrating with modules that should be placed behind authentication,
* but don't interface nicely with NestJS.
*/
export function guardToMiddleware(guard: CanActivate) {
return async (req: Request, res: Response, next: NextFunction) => {
try {
class mockControllerClass {}
const context: ExecutionContext = {
// @ts-expect-error This is not relevant
getClass: () => mockControllerClass,
getHandler: () => () => {
// This is intentionally empty.
},
switchToHttp: () => ({
// @ts-expect-error I (clintonb) don't know why TypeScript complains. The code works, though.
getRequest: () => req,
// @ts-expect-error I (clintonb) don't know why TypeScript complains. The code works, though.
getResponse: () => res,
}),
};
if (await guard.canActivate(context)) {
next();
} else {
res.status(403).json({ message: 'Forbidden' });
}
} catch (error) {
next(error);
}
};
} import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { Request, Response } from 'express';
import { Observable } from 'rxjs';
import { IS_PUBLIC_KEY } from '@vori/nest/libs/auth/constants';
@Injectable()
export class RedirectToLoginGuard 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<Request>();
const response = context.switchToHttp().getResponse<Response>();
if (request.isAuthenticated()) {
return true;
}
response.redirect('/auth/login');
return false;
}
} The import { ExecutionContext, Injectable, Logger } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { PassportStrategyName } from '@vori/nest/libs/auth/constants';
@Injectable()
export class AdminAuthGuard extends AuthGuard([
PassportStrategyName.InternalGoogleOauth,
]) {
private readonly logger = new Logger(AdminAuthGuard.name);
async canActivate(context: ExecutionContext): Promise<boolean> {
try {
const result = await super.canActivate(context);
const request = this.getRequest(context);
if (result && request.user) {
this.logger.debug({ user: request.user }, `Authentication succeeded.`);
// NOTE (clintonb): This is crucial to ensuring successful login.
// It's unclear why none of the NestJS docs mention this.
await super.logIn(request);
}
// @ts-expect-error We aren't using Observable
return result;
} catch (err) {
this.logger.error({ err }, `Authentication failed!`);
return false;
}
}
} P.S. Yes, I know I am using Express and this ticket is about Fastify, but I suspect this knowledge applies to both frameworks. |
@clintonb I'm not familiar with Nest.js at all, do u think that the module should be updated? Will you make a PR for it? |
Yes, I think it should be updated, but I don’t have the capacity to do so at this time. It took me two months to get back to my basic installation. 🤣 |
Here's another possible way to use an auth guard. Not as robust as what @clintonb posted above but might be useful. @Module({
imports: [
BullBoardModule.forRootAsync({
useFactory: (jwtAuthStrategy: JwtStrategy) => {
return {
route: "/queues",
adapter: ExpressAdapter,
middleware: async (req, res, next) => {
const authCookie = req.cookies?.["auth"]
if (!authCookie) return res.sendStatus(401)
try {
jwtAuthStrategy.validate(authCookie)
next()
} catch {
res.sendStatus(401)
}
}
}
},
imports: [AuthModule],
inject: [JwtStrategy]
}),
],
})
class SecureBullBoardModule { } |
Is there any way to add auth layer for this configuration? I have tried middleware and npm packages for basic auth but they don't work. With middlewares, there is probably an issue with resolving paths. So now, I don't find any way to add secure auth layer ://
The text was updated successfully, but these errors were encountered: