NestJSでBasic認証ダイアログを出す方法
最近、TypeScriptの良さに目覚めてしまったので、サーバサイドでも使ってみようとNestJSで簡単なシステムを作って遊んでみました。
NestJSはTypeScript製のNode.jsフレームワークで、ここ最近すごい盛り上がりを見せていて
expressの次に有名なフレームワークになるんじゃないかと思ったので使ってみました。
nestjs.com
そんな中、管理画面にBasic認証をかけてみようとしたら大いにハマりました。
NestJSはまだ知名度では発展途上ということもあり、日本語の情報が少ないので
解決させた方法を紹介します。
passport
NestJSでBasic認証を調べると@nestjs/passportが一般的ぽかったので
リンクのようにインストールして、Overview & Tutorialを参考に実装してみました。
github.com
passport-http
Overview & Tutorialではpassport-http-bearerを使った例ですが、
passportのBasic認証はpassport-httpにあるようなので、こちらをインストールします。
> npm install --save @nestjs/passport passport passport-http
basic.strategy.ts
新規にbasic.strategy.tsを作成して、以下のようにpassport-httpのBasicStrategyを
@nestjs/passportに従って作ります。
import { BasicStrategy } from 'passport-http';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable } from '@nestjs/common';
// Basic認証
@Injectable()
export class BasicAuthStrategy extends PassportStrategy(BasicStrategy, 'basic-auth') {
constructor() {
super();
}
async validate(username: string, password: string) {
// ユーザとパスワード
if((username != 'test') || (password != 'test')){
return false;
}
return true;
}
}
app.module.ts
Overview & Tutorialでは別のauth.module.tsを作っていますが
今回は手抜きで、app.module.tsのprovidersにBasicAuthStrategyを追加しました。
import { Module } from '@nestjs/common';
import { AppController} from './app.controller';
import { AppService} from './app.service';
import { BasicAuthStrategy } from './basic.strategy';
@Module({
controllers: [AppController],
providers: [BasicAuthStrategy, AppService],
})
export class AppModule {}
app.controller.ts
そしてコントローラにデコレータ@UseGuards(AuthGuard('basic-auth'))を追加します。
これでgetIndex()実行前に、BasicAuthStrategyが実行されるようになります。
import { Controller, Get, UseGuards } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get()
@UseGuards(AuthGuard('basic-auth'))
getIndex() {
return this.appService.getHello();
}
}
しかし動かない
これでブラウザからアクセス、401 Unauthorizedとガードはされるのですが
あのBasic認証時のダイアログが出てこないので、ユーザ・パスワードが入力できず認証されません。
困りました。

Exception filters
@nestjs/passportとpassport-httpのソースを追いかけてわかったのですが
passport-httpは認証チェックはしてくれるが、認証ダイアログに必要なレスポンスヘッダWWW-Authenticateを付与してくれない。
そこまではしないライブラリだということがわかりました。
また、AuthGuardが認証NG時にUnauthorizedExceptionを実行していることもわかりました。
auth-exception.filter.ts
そこでauth-exception.filter.tsを作り、Exception filterでUnauthorizedExceptionを捕まえてレスポンスヘッダにWWW-Authenticateを付与するようにしました。
import { ExceptionFilter, Catch, ArgumentsHost, HttpStatus } from '@nestjs/common';
import { HttpException } from '@nestjs/common';
// Basic認証用にエクセプションを加工する.
@Catch(HttpException)
export class AuthExceptionFilter implements ExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse();
const status = exception.getStatus();
if(HttpStatus.UNAUTHORIZED == status){
// Basic認証ダイアログ用に付与.
response.set('WWW-Authenticate', 'Basic realm="aaa"');
}
response
.status(status)
.json({
statusCode: status,
});
}
}
app.controller.ts
そして、デコレータで@UseFilters(new AuthExceptionFilter())をコントローラに追加します。
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get()
@UseFilters(new AuthExceptionFilter())
@UseGuards(AuthGuard('basic-auth'))
getIndex() {
return this.appService.getHello();
}
}
成功!
認証ダイアログの表示に成功しました。
これでユーザ・パスワードを入力すれば認証が通って正常に表示されるようになりました。

@nestjs/passport、passport-httpの使い方も情報が少なく
ここまでたどり着くのに試行錯誤でしたが、これで無事解決しました。