0

I work with a monorepo which includes several NestJS apps, all deployed separately. An authentication guard is needed to parse JWTs and since it's the same one for all apps, I need to make it "common". My strategy is the following structure:

- root
- - packages
- - - app1
- - - app2
- - - guards
- - - - src
- - - - dist

The way our company works with monorepos is by building common packages, and importing from dist. So the guard I want should be written under guards/src, then built and imported from guards/dist, so for example:

// app1/src/main.ts
import { AuthGuard } from 'guards/dist`;

async function bootstrap() {
  // ...
  app.useGlobalGuards(new AuthGuard());
  // ...
}

The issue is as follows: Following the NestJS docs for JSW handling I built my guard:

@Injectable()
export class AuthGuard implements CanActivate {
  constructor(private jwtService: JwtService) {}
}

But when using it in the above example (in new AuthGuard()), I am required to provide the argument jwtService which would normally be injected by a module. But this guard isn't used in a module, nor would I want to include the JwtService in every app separately - that defeats the purpose of a common auth guard!

I'm not sure how to target this. The options I see now are:

  1. Make guards export a module instead of an injectable. (issue: how to implement guards this way?)
  2. Skip JwtService and use another library for parsing JWTs. (issue: specific solution that doesn't solve future similar issues).
  3. Instantiate JwtService myself, instead of relying on dependency injection. (issue: defeats Nest's architecture design).

What say you?

1 Answer 1

1

I think you're missing the other way to create a global guard in Nest. You can use the APP_GUARD provider in a custom provider in any module in your application and get the guard globally bound. E.g.

@Module({
  imports: AllTheOtherImportsForYourApp,
  providers: [
    {
      provide: APP_GUARD,
      useClass: AuthGuard,
    }
  ]
})
export class AppModule {}

Now, no need for app.useGlobalGuards() or anything like that.

This approach works for APP_PIPE, APP_INTERCEPTOR, and APP_FILTER and the APP_* providers can be used more than once.

Sign up to request clarification or add additional context in comments.

11 Comments

Thank you. I am aware of this method, but it does not solve the issue where AuthGuard requires JwtService. In your solution, as I myself mentioned, I would have to add JwtService as a provider.
No, you wouldn't. That's why you use useClass, so Nest knows of this class and creates it for you, doing all of the dependency injection you're used to. That's literally why this approach exists
This is demonstrably incorrect. I just tried what you suggested, and, as expected, Nest complains that JwtService is not available in the AppModule scope. This means that either way I have to somethow inject or instantiate it.
Most likely because JwtService comes from importing JwtModule and your AuthModule (which I presume imports JwtModule and is imported by AppModule) does not make use of module re-exporting by also exporting JwtModule
there is no AuthModule, only an AughGuard which lives on its own. From the Nest docs I got the impression that's the way to do it if all I need is a guard, rather than an entire auth module with extra functionality.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.