NestJS passing Authorization header to HttpService

Viewed 12776

I have a NestJS application which acts as a proxy between a front-end and multiple other back-ends.

I basically want to be able to pass a specific header (Authorization) from incoming @Req (requests) in the controller to the HttpService that then talks to the other back-ends.

user controller (has access to request) -> user service (injects httpService that somehow already picks the Authorization header) -> External backends.

Right now I need to extract the token from @Headers and then pass token to service which has to paste it to all HttpService calls.

Thanks in advance!

3 Answers

I'm not sure if this will help you, but maybe if you get the header from the controller and put it in your services function...

// Controller:

@Get()
getAll(@Request() req){
    const header = req.headers;
    return this._zoneService.sendToHttp(header);
}

Maybe microservices can be better ?

Ok, I managed to solve this by actually using a middleware that I initially thought. I am not a 100% sure this is the NEST way but intercepting the underlying axios reference of the HttpService did the trick:

@Injectable()
export class BearerMiddleware implements NestMiddleware {
  constructor(private readonly httpService: HttpService) {}
  use(req: Request, res: Response, next: Function) {
    this.httpService.axiosRef.interceptors.request.use(request => {
      request.headers = {
        ...request.headers,
        Authorization: req.headers.Authorization || '',
      };
      return request;
    });
    next();
  }
}

Besides the middleware answer, I have another version using interceptor:

@Injectable()
export class HttpServiceInterceptor implements NestInterceptor {
  constructor(private httpService: HttpService) {}
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
  
    // ** if you use normal HTTP module **
    const ctx = context.switchToHttp();
    const token = ctx.getRequest().headers['authorization'];

    // ** if you use GraphQL module **
    const ctx = GqlExecutionContext.create(context);
    const token = ctx.getContext().token;

    if (ctx.token) {
      this.httpService.axiosRef.defaults.headers.common['authorization'] =
        token;
    }
    return next.handle().pipe();
  }
}

If you use GraphQLModule, do not forget to pass token to context:

GraphQLModule.forRoot({
  debug: true,
  playground: true,
  autoSchemaFile: 'schema.gql',
  context: ({ req }) => {
    return { token: req.headers.authorization };
  },
}),

Once preparation work is ready, let's use interceptors

The interceptor can be injected into a certain controller:

@UseInterceptors(HttpServiceInterceptor)
export class CatsController {}

or register a global interceptor like following:

@Module({
  providers: [
    {
      provide: APP_INTERCEPTOR,
      useClass: HttpServiceInterceptor,
    },
  ],
})
export class AppModule {}
Related