ApiKey Authentication for NestJS using Passport JS

Afolabi Mayowa
4 min readApr 22, 2020

--

Since I started working as a backend software engineer for close to 4 years now, I have had the opportunity of working on several projects that needed several types of authentication systems. From using single sign on to social media sign in to JWT, to OAuth systems. One thing is constant we need a means of securing our applications that are equally secure and easy to implement.

Securing nestjs web apps using passports

Several frameworks have several authentications baked in which makes it very easy to implement. NestJS, for example, comes with support for normal sign in using username and password and JWT.

NestJS implements both authentications using the Passport JS library.

Passport is the most popular node.js authentication library, well-known by the community and successfully used in many production applications. It has been implemented in several other languages and frameworks like PHP(Laravel). It’s straightforward to integrate this library with a NestJs application using the @nestjs/passport module. Passport has a rich ecosystem of strategies that implement various authentication mechanisms. While simple in concept, the set of Passport strategies you can choose from is large and presents a lot of variety. Passport abstracts these varied steps into a standard pattern, and the @nestjs/passport module wraps and standardizes this pattern into familiar Nest constructs.

In this article, we will be focusing on implementing apiKey authentication using the Passport-LocalAPIKey strategy. We will also be implementing it using middleware in NestJs instead of a guard so it can be easily adopted.

To get started, install these packages to your NestJs project.

$ npm install --save @nestjs/passport passport passport-headerapikey

This will install the necessary packages needed to implement the authentication. Next will need to register the passport itself into our project. We will start by creating an Auth Module, an Auth service, and an Auth middleware.

$ nest g module auth

$ nest g service auth

$ nest g middleware middleware/auth

Open the auth module and put in the contents

import { Module } from ‘@nestjs/common’;import { AuthService } from ‘./auth.service’;import { PassportModule } from ‘@nestjs/passport’;import { ApiKeyStrategy } from ‘./apiKey.strategy’;@Module({imports: [PassportModule],providers: [AuthService, ApiKeyStrategy],})export class AuthModule {}

If you notice we added the PassportModule to the imports. We will also now be creating our ApiKeyStrategy file as we can see in the providers.

. In the auth folder create a file called `apiKey.strategy.ts`. add the contents below inside it.

import { HeaderAPIKeyStrategy } from ‘passport-headerapikey’;import { PassportStrategy } from ‘@nestjs/passport’;import { Injectable } from ‘@nestjs/common’;import { AuthService } from ‘./auth.service’;@Injectable()export class ApiKeyStrategy extends PassportStrategy(HeaderAPIKeyStrategy) {constructor(private authService: AuthService) {super({ header: ‘apiKey’, prefix: ‘’ }, true, (apikey, done, req) => {const checkKey = authService.validateApiKey(apikey);if (!checkKey) {return done(false);}return done(true);});}}

In this file, we imported the HeaderAPIKeyStrategy. We also created a class ApiKeyStrategy which extends PassportStrategy class. The PassportStrategy class needs a strategy for it to work, hence the PassportStrategy(HeaderAPIKeyStrategy). Inside the constructor of our ApiKeyStrategy class, will need to configure the extended HeaderApiKeyStrategy with

super(
{ header: ‘x-api-key’, prefix: ‘’ },
true, (apikey, done, req) => {
const checkKey = authService.validateApiKey(apikey);if (!checkKey) {return done(false);}return done(true);});

You can find the full documentation here http://www.passportjs.org/packages/passport-headerapikey/

Inside our Auth service, we define a function that validates our apiKey. but for the sake of this tutorial, we will be using a simple array to serve as our database. But in a normal application, the API key will need to be confirmed from a real database or secure method of storing keys of your choice.

Copy this into your auth service.

import { Injectable } from ‘@nestjs/common’;@Injectable()export class AuthService {// KEYSprivate apiKeys: string[] = ['ca03na188ame03u1d78620de67282882a84','d2e621a6646a4211768cd68e26f21228a81',];validateApiKey(apiKey: string) {return this.apiKeys.find(apiK => apiKey === apiK);}}

Next, we will move to build our middleware. Open up the middleware in middleware/auth.middleware.ts

import {Injectable,NestMiddleware,UnauthorizedException,} from ‘@nestjs/common’;import * as passport from ‘passport’;@Injectable()export class AuthMiddleware implements NestMiddleware {use(req: any, res: any, next: () => void) {passport.authenticate(‘headerapikey’,{ session: false, failureRedirect: ‘/api/unauthorized’ },value => {if (value) {next();} else {throw new UnauthorizedException();}},)(req, res, next);}}

Now we are going to apply our middleware in our root api. Go to the app.module.ts.

import { Module, MiddlewareConsumer } from ‘@nestjs/common’;import { AppController } from ‘./app.controller’;import { AppService } from ‘./app.service’;import { AuthMiddleware } from ‘./middleware/auth.middleware’;import { AuthModule } from ‘./auth/auth.module’;@Module({imports: [AuthModule,],controllers: [AppController],providers: [AppService],})export class AppModule {configure(consumer: MiddlewareConsumer) {consumer.apply(AuthMiddleware).forRoutes(‘’);}}

Here we import the auth module. then we apply the middleware in the App module class as

configure(consumer: MiddlewareConsumer) {

consumer.apply(AuthMiddleware).forRoutes(‘’);

}

Now we can now test the api. Go to any api testing app like postman.

Successful request

For the wrong API keys, we get this as response .

You can find the full source code on GitHub at https://github.com/devmayor/NestJs-apikey-authentication-using-passport

--

--

Afolabi Mayowa

Adding value to the world 1 piece of code at a time. Currently working @Andela.