NestJSでエンタープライズレベルの認証システムを構築する際、Passportは最も信頼性の高い選択肢です。Node.jsエコシステムで長年使われてきたPassportライブラリを、NestJSの依存性注入システムと統合することで、柔軟で拡張性のある認証基盤を実現できます。本記事では、@nestjs/passportパッケージを使用したLocalStrategy(ユーザー名/パスワード認証)とJwtStrategy(トークン検証)の実装方法を解説します。
実行環境と前提条件#
本記事の内容を実践するにあたり、以下の環境を前提としています。
| 項目 |
バージョン・要件 |
| Node.js |
20以上 |
| npm |
10以上 |
| NestJS |
11.x |
| @nestjs/passport |
11.x |
| @nestjs/jwt |
11.x |
| passport |
0.7.x |
| passport-local |
1.x |
| passport-jwt |
4.x |
| TypeScript |
5.x |
| OS |
Windows / macOS / Linux |
| エディタ |
VS Code(推奨) |
事前に以下の準備を完了してください。
- NestJS CLIのインストール済み
- NestJSプロジェクトの作成済み
- Module、Controller、Service、Guardの基本理解
- JWTの仕組みについての基礎知識
NestJSプロジェクトの作成方法はNestJS入門記事を参照してください。
Passportとは何か#
Passportは、Node.jsで最も広く使われている認証ライブラリです。500以上の認証戦略(Strategy)をサポートしており、ユーザー名/パスワード認証からOAuth、OpenID Connectまで、あらゆる認証方式に対応できます。
flowchart TB
subgraph Passport["Passportフレームワーク"]
Core[Passport Core]
Core --> S1[LocalStrategy]
Core --> S2[JwtStrategy]
Core --> S3[OAuth2Strategy]
Core --> S4[GoogleStrategy]
Core --> S5[その他500以上]
end
subgraph NestJS["NestJS統合"]
NP["@nestjs/passport"]
NP --> PS[PassportStrategy]
PS --> AG[AuthGuard]
end
S1 & S2 --> NP
style Core fill:#4CAF50,color:#fff
style NP fill:#E91E63,color:#fff@nestjs/passportの役割#
@nestjs/passportは、Passportの認証戦略をNestJSのアーキテクチャにシームレスに統合するためのラッパーモジュールです。
| 機能 |
説明 |
| PassportStrategy |
認証戦略をNestJSのProviderとして実装するための基底クラス |
| AuthGuard |
認証戦略を適用するためのGuard |
| PassportModule |
Passportの設定を管理するモジュール |
| validate()メソッド |
認証ロジックを実装するためのフック |
直接的なJWT検証との違い#
前回の記事で実装したJWT検証アプローチと、Passportを使用したアプローチの違いを理解しましょう。
| 観点 |
直接的なJWT検証 |
Passportを使用 |
| 実装方法 |
JwtServiceで直接検証 |
JwtStrategyのvalidate()で検証 |
| 拡張性 |
新しい認証方式の追加に手間がかかる |
新しいStrategyを追加するだけ |
| コード量 |
シンプルな場合は少ない |
やや多いが構造化されている |
| 複数認証 |
条件分岐が複雑になる |
複数Strategyを自然に組み合わせ可能 |
| エコシステム |
自前実装が必要 |
500以上のStrategy利用可能 |
小規模なアプリケーションでは直接的なJWT検証で十分ですが、複数の認証方式を組み合わせる場合やOAuth連携を見据える場合は、Passportの採用が推奨されます。
パッケージのインストール#
Passport認証に必要なパッケージをインストールします。
1
2
3
4
5
6
7
8
|
# Passport関連パッケージ
npm install --save @nestjs/passport passport passport-local passport-jwt
# JWT関連パッケージ(未インストールの場合)
npm install --save @nestjs/jwt
# 型定義ファイル
npm install --save-dev @types/passport-local @types/passport-jwt
|
インストール後、package.jsonの依存関係を確認してください。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
{
"dependencies": {
"@nestjs/jwt": "^11.0.2",
"@nestjs/passport": "^11.0.5",
"passport": "^0.7.0",
"passport-jwt": "^4.0.1",
"passport-local": "^1.0.0"
},
"devDependencies": {
"@types/passport-jwt": "^4.0.2",
"@types/passport-local": "^1.0.38"
}
}
|
認証モジュールの構成#
Passport認証を実装するためのモジュール構成を設計します。
flowchart TB
subgraph AuthModule["AuthModule"]
AS[AuthService]
LS[LocalStrategy]
JS[JwtStrategy]
AC[AuthController]
end
subgraph UsersModule["UsersModule"]
US[UsersService]
end
subgraph External["外部モジュール"]
PM[PassportModule]
JM[JwtModule]
end
AuthModule --> UsersModule
AuthModule --> PM
AuthModule --> JM
LS --> AS
JS --> AS
AS --> US
style LS fill:#FF5722,color:#fff
style JS fill:#4CAF50,color:#fffファイル構成#
src/
├── auth/
│ ├── auth.module.ts
│ ├── auth.service.ts
│ ├── auth.controller.ts
│ ├── strategies/
│ │ ├── local.strategy.ts
│ │ └── jwt.strategy.ts
│ ├── guards/
│ │ ├── local-auth.guard.ts
│ │ └── jwt-auth.guard.ts
│ ├── dto/
│ │ └── login.dto.ts
│ └── constants.ts
└── users/
├── users.module.ts
└── users.service.ts
UsersModuleの実装#
認証に必要なユーザー情報を管理するモジュールを実装します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
// src/users/users.service.ts
import { Injectable } from '@nestjs/common';
export interface User {
userId: number;
username: string;
password: string;
roles: string[];
}
@Injectable()
export class UsersService {
// 本番環境ではデータベースから取得
private readonly users: User[] = [
{
userId: 1,
username: 'admin',
password: '$2b$10$abcdefghijklmnopqrstuv', // bcryptハッシュ化済み
roles: ['admin', 'user'],
},
{
userId: 2,
username: 'user',
password: '$2b$10$wxyzabcdefghijklmnopqr', // bcryptハッシュ化済み
roles: ['user'],
},
];
async findOne(username: string): Promise<User | undefined> {
return this.users.find((user) => user.username === username);
}
async findById(userId: number): Promise<User | undefined> {
return this.users.find((user) => user.userId === userId);
}
}
|
1
2
3
4
5
6
7
8
9
|
// src/users/users.module.ts
import { Module } from '@nestjs/common';
import { UsersService } from './users.service';
@Module({
providers: [UsersService],
exports: [UsersService],
})
export class UsersModule {}
|
本番環境では、TypeORMやPrismaなどのORMを使用してデータベースからユーザー情報を取得します。パスワードは必ずbcryptなどでハッシュ化して保存してください。
LocalStrategyの実装#
LocalStrategyは、ユーザー名とパスワードによる認証を処理します。ログインエンドポイントで使用される戦略です。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
// src/auth/strategies/local.strategy.ts
import { Strategy } from 'passport-local';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { AuthService } from '../auth.service';
@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy) {
constructor(private authService: AuthService) {
super();
}
async validate(username: string, password: string): Promise<any> {
const user = await this.authService.validateUser(username, password);
if (!user) {
throw new UnauthorizedException('ユーザー名またはパスワードが正しくありません');
}
return user;
}
}
|
PassportStrategyの仕組み#
PassportStrategyは、Passportの戦略クラスをNestJSのProviderとして利用するためのミックスイン関数です。
sequenceDiagram
participant C as クライアント
participant G as LocalAuthGuard
participant P as Passport
participant LS as LocalStrategy
participant AS as AuthService
C->>G: POST /auth/login (username, password)
G->>P: authenticate('local')
P->>LS: validate(username, password)
LS->>AS: validateUser(username, password)
AS-->>LS: ユーザー情報 or null
alt ユーザー有効
LS-->>P: ユーザー情報
P-->>G: request.user = ユーザー情報
G-->>C: 認証成功
else ユーザー無効
LS-->>P: UnauthorizedException
P-->>G: 認証失敗
G-->>C: 401 Unauthorized
endLocalStrategyのオプション#
デフォルトでは、リクエストボディのusernameとpasswordフィールドが使用されます。別のフィールド名を使用する場合は、super()にオプションを渡します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
// メールアドレスでログインする場合
@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy) {
constructor(private authService: AuthService) {
super({
usernameField: 'email',
passwordField: 'password',
});
}
async validate(email: string, password: string): Promise<any> {
const user = await this.authService.validateUserByEmail(email, password);
if (!user) {
throw new UnauthorizedException();
}
return user;
}
}
|
JwtStrategyの実装#
JwtStrategyは、リクエストに含まれるJWTトークンを検証します。保護されたエンドポイントへのアクセス時に使用されます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
// src/auth/strategies/jwt.strategy.ts
import { ExtractJwt, Strategy } from 'passport-jwt';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { jwtConstants } from '../constants';
import { UsersService } from '../../users/users.service';
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor(private usersService: UsersService) {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKey: jwtConstants.secret,
});
}
async validate(payload: any) {
// payloadはJWTのデコード結果
// トークン無効化チェックやユーザー存在確認をここで行う
const user = await this.usersService.findById(payload.sub);
if (!user) {
throw new UnauthorizedException('ユーザーが見つかりません');
}
return { userId: payload.sub, username: payload.username, roles: user.roles };
}
}
|
JwtStrategyのオプション詳細#
| オプション |
説明 |
| jwtFromRequest |
JWTをどこから抽出するか指定 |
| ignoreExpiration |
有効期限切れトークンを許可するか(通常はfalse) |
| secretOrKey |
トークン署名の検証に使用する秘密鍵 |
| algorithms |
使用するアルゴリズム(デフォルト: HS256) |
| issuer |
トークンの発行者を検証 |
| audience |
トークンの対象者を検証 |
JWTの抽出方法#
ExtractJwtには複数の抽出メソッドが用意されています。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
import { ExtractJwt } from 'passport-jwt';
// Authorizationヘッダーからベアラートークンとして抽出(推奨)
ExtractJwt.fromAuthHeaderAsBearerToken()
// クエリパラメータから抽出
ExtractJwt.fromUrlQueryParameter('token')
// リクエストボディから抽出
ExtractJwt.fromBodyField('access_token')
// カスタムヘッダーから抽出
ExtractJwt.fromHeader('x-access-token')
// 複数の方法を組み合わせ
ExtractJwt.fromExtractors([
ExtractJwt.fromAuthHeaderAsBearerToken(),
ExtractJwt.fromUrlQueryParameter('token'),
])
|
AuthServiceの実装#
ユーザー検証とJWTトークン生成を担当するサービスを実装します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
// src/auth/auth.service.ts
import { Injectable } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { UsersService } from '../users/users.service';
import * as bcrypt from 'bcrypt';
@Injectable()
export class AuthService {
constructor(
private usersService: UsersService,
private jwtService: JwtService,
) {}
async validateUser(username: string, password: string): Promise<any> {
const user = await this.usersService.findOne(username);
if (user && (await bcrypt.compare(password, user.password))) {
// パスワードを除外したユーザー情報を返す
const { password: _, ...result } = user;
return result;
}
return null;
}
async login(user: any) {
// JWTのペイロードを作成
const payload = {
username: user.username,
sub: user.userId,
roles: user.roles,
};
return {
access_token: this.jwtService.sign(payload),
token_type: 'Bearer',
expires_in: 3600, // 1時間
};
}
}
|
認証ガードの実装#
LocalStrategyとJwtStrategyに対応するGuardを作成します。
1
2
3
4
5
6
|
// src/auth/guards/local-auth.guard.ts
import { Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
@Injectable()
export class LocalAuthGuard extends AuthGuard('local') {}
|
1
2
3
4
5
6
|
// src/auth/guards/jwt-auth.guard.ts
import { Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {}
|
AuthGuardの動作原理#
AuthGuardは、指定された戦略名に基づいてPassportの認証プロセスを実行します。
sequenceDiagram
participant R as リクエスト
participant AG as AuthGuard('jwt')
participant P as Passport
participant JS as JwtStrategy
participant C as Controller
R->>AG: canActivate()
AG->>P: authenticate('jwt')
P->>JS: トークン抽出 & 検証
JS->>JS: validate(payload)
alt 認証成功
JS-->>P: ユーザー情報
P-->>AG: request.user設定
AG-->>R: true
R->>C: ハンドラ実行
else 認証失敗
JS-->>P: UnauthorizedException
AG-->>R: 401 Unauthorized
endカスタムエラーハンドリング#
AuthGuardを拡張して、カスタムエラーハンドリングを実装できます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
// src/auth/guards/jwt-auth.guard.ts
import {
ExecutionContext,
Injectable,
UnauthorizedException,
} from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {
canActivate(context: ExecutionContext) {
// カスタムロジックを追加可能
return super.canActivate(context);
}
handleRequest(err: any, user: any, info: any) {
// infoにはJWTエラーの詳細情報が含まれる
if (err || !user) {
if (info?.name === 'TokenExpiredError') {
throw new UnauthorizedException('トークンの有効期限が切れています');
}
if (info?.name === 'JsonWebTokenError') {
throw new UnauthorizedException('無効なトークンです');
}
throw err || new UnauthorizedException('認証が必要です');
}
return user;
}
}
|
AuthModuleの実装#
すべてのコンポーネントを統合するモジュールを作成します。
1
2
3
4
|
// src/auth/constants.ts
export const jwtConstants = {
secret: process.env.JWT_SECRET || 'your-super-secret-key-change-in-production',
};
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
// src/auth/auth.module.ts
import { Module } from '@nestjs/common';
import { PassportModule } from '@nestjs/passport';
import { JwtModule } from '@nestjs/jwt';
import { AuthService } from './auth.service';
import { AuthController } from './auth.controller';
import { UsersModule } from '../users/users.module';
import { LocalStrategy } from './strategies/local.strategy';
import { JwtStrategy } from './strategies/jwt.strategy';
import { jwtConstants } from './constants';
@Module({
imports: [
UsersModule,
PassportModule,
JwtModule.register({
secret: jwtConstants.secret,
signOptions: { expiresIn: '1h' },
}),
],
providers: [AuthService, LocalStrategy, JwtStrategy],
controllers: [AuthController],
exports: [AuthService],
})
export class AuthModule {}
|
PassportModuleのオプション#
セッションを使用する場合や、デフォルトの戦略を指定する場合は、PassportModule.register()を使用します。
1
2
3
4
5
|
// セッションを使用する場合
PassportModule.register({ session: true })
// デフォルトの戦略を指定する場合
PassportModule.register({ defaultStrategy: 'jwt' })
|
AuthControllerの実装#
ログインエンドポイントとプロフィール取得エンドポイントを実装します。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
// src/auth/dto/login.dto.ts
import { IsString, IsNotEmpty, MinLength } from 'class-validator';
export class LoginDto {
@IsString()
@IsNotEmpty()
username: string;
@IsString()
@IsNotEmpty()
@MinLength(8)
password: string;
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
// src/auth/auth.controller.ts
import {
Controller,
Post,
Get,
UseGuards,
Request,
Body,
HttpCode,
HttpStatus,
} from '@nestjs/common';
import { AuthService } from './auth.service';
import { LocalAuthGuard } from './guards/local-auth.guard';
import { JwtAuthGuard } from './guards/jwt-auth.guard';
import { LoginDto } from './dto/login.dto';
@Controller('auth')
export class AuthController {
constructor(private authService: AuthService) {}
@UseGuards(LocalAuthGuard)
@Post('login')
@HttpCode(HttpStatus.OK)
async login(@Request() req, @Body() loginDto: LoginDto) {
// LocalAuthGuardが認証を処理し、req.userにユーザー情報を設定
return this.authService.login(req.user);
}
@UseGuards(JwtAuthGuard)
@Get('profile')
getProfile(@Request() req) {
return req.user;
}
@UseGuards(JwtAuthGuard)
@Get('me')
getCurrentUser(@Request() req) {
return {
userId: req.user.userId,
username: req.user.username,
roles: req.user.roles,
};
}
}
|
複数の認証戦略を組み合わせる#
Passportの強みは、複数の認証戦略を柔軟に組み合わせられることです。
戦略の名前付け#
デフォルトでは、各戦略は固有の名前を持ちます(local、jwtなど)。カスタム名を付ける場合は、PassportStrategyの第二引数で指定します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
// 名前付き戦略の例
@Injectable()
export class JwtRefreshStrategy extends PassportStrategy(Strategy, 'jwt-refresh') {
constructor() {
super({
jwtFromRequest: ExtractJwt.fromBodyField('refresh_token'),
ignoreExpiration: false,
secretOrKey: jwtConstants.refreshSecret,
});
}
async validate(payload: any) {
return { userId: payload.sub, username: payload.username };
}
}
|
1
2
3
|
// 対応するGuard
@Injectable()
export class JwtRefreshGuard extends AuthGuard('jwt-refresh') {}
|
複数のGuardを連鎖させる#
複数のGuardを順番に適用する場合、配列で指定します。
1
2
3
4
5
6
7
|
// 認証後にロールをチェック
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles('admin')
@Get('admin/dashboard')
getAdminDashboard() {
return { message: '管理者ダッシュボード' };
}
|
フォールバック認証#
複数の認証方式のいずれかで認証を許可する場合、カスタムGuardを作成します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
// src/auth/guards/combined-auth.guard.ts
import { Injectable, ExecutionContext } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
@Injectable()
export class CombinedAuthGuard extends AuthGuard(['jwt', 'api-key']) {
canActivate(context: ExecutionContext) {
return super.canActivate(context);
}
handleRequest(err: any, user: any, info: any, context: ExecutionContext, status?: any) {
// 最初に成功した戦略のユーザーを返す
if (user) {
return user;
}
// すべて失敗した場合はエラー
throw err || new Error('認証に失敗しました');
}
}
|
グローバルGuardとPublicエンドポイント#
すべてのエンドポイントをデフォルトで保護し、特定のエンドポイントのみ公開する設計を実装します。
1
2
3
4
5
|
// src/auth/decorators/public.decorator.ts
import { SetMetadata } from '@nestjs/common';
export const IS_PUBLIC_KEY = 'isPublic';
export const Public = () => SetMetadata(IS_PUBLIC_KEY, true);
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
// src/auth/guards/jwt-auth.guard.ts
import {
ExecutionContext,
Injectable,
UnauthorizedException,
} from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { AuthGuard } from '@nestjs/passport';
import { IS_PUBLIC_KEY } from '../decorators/public.decorator';
@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {
constructor(private reflector: Reflector) {
super();
}
canActivate(context: ExecutionContext) {
const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [
context.getHandler(),
context.getClass(),
]);
if (isPublic) {
return true;
}
return super.canActivate(context);
}
handleRequest(err: any, user: any, info: any) {
if (err || !user) {
throw err || new UnauthorizedException();
}
return user;
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
// src/app.module.ts
import { Module } from '@nestjs/common';
import { APP_GUARD } from '@nestjs/core';
import { AuthModule } from './auth/auth.module';
import { JwtAuthGuard } from './auth/guards/jwt-auth.guard';
@Module({
imports: [AuthModule],
providers: [
{
provide: APP_GUARD,
useClass: JwtAuthGuard,
},
],
})
export class AppModule {}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
// 公開エンドポイントの例
@Controller('auth')
export class AuthController {
@Public()
@Post('login')
@UseGuards(LocalAuthGuard)
async login(@Request() req) {
return this.authService.login(req.user);
}
@Public()
@Post('register')
async register(@Body() registerDto: RegisterDto) {
return this.authService.register(registerDto);
}
// 認証必須(グローバルGuardが適用される)
@Get('profile')
getProfile(@Request() req) {
return req.user;
}
}
|
動作確認#
実装した認証システムをcURLで確認します。
ログインテスト#
1
2
3
4
|
# ログインリクエスト
curl -X POST http://localhost:3000/auth/login \
-H "Content-Type: application/json" \
-d '{"username": "admin", "password": "password123"}'
|
期待されるレスポンス:
1
2
3
4
5
|
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600
}
|
保護されたエンドポイントへのアクセス#
1
2
3
4
5
6
|
# トークンなしでアクセス(401エラー)
curl http://localhost:3000/auth/profile
# トークン付きでアクセス
curl http://localhost:3000/auth/profile \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
期待されるレスポンス:
1
2
3
4
5
|
{
"userId": 1,
"username": "admin",
"roles": ["admin", "user"]
}
|
ベストプラクティス#
Passport認証を本番環境で運用する際のベストプラクティスをまとめます。
セキュリティに関する推奨事項#
| 項目 |
推奨事項 |
| JWT秘密鍵 |
環境変数で管理し、256ビット以上の強力な値を使用 |
| パスワード |
bcryptでハッシュ化(ソルトラウンド10以上) |
| トークン有効期限 |
アクセストークンは短め(15分〜1時間) |
| HTTPS |
本番環境では必ずHTTPS通信を使用 |
| レート制限 |
ログインエンドポイントにレート制限を適用 |
構造に関する推奨事項#
1
2
3
4
5
6
7
8
9
10
11
12
13
|
// 環境変数の使用例
// src/auth/constants.ts
export const jwtConstants = {
secret: process.env.JWT_SECRET,
expiresIn: process.env.JWT_EXPIRES_IN || '1h',
refreshSecret: process.env.JWT_REFRESH_SECRET,
refreshExpiresIn: process.env.JWT_REFRESH_EXPIRES_IN || '7d',
};
// バリデーション
if (!jwtConstants.secret) {
throw new Error('JWT_SECRET環境変数が設定されていません');
}
|
まとめ#
本記事では、NestJSとPassportを使用した認証システムの実装方法を解説しました。
学習した主なポイント:
@nestjs/passportパッケージの役割と導入方法
PassportStrategyを継承したLocalStrategy、JwtStrategyの実装
validate()メソッドによる認証ロジックのカスタマイズ
AuthGuardを使用したルート保護
- 複数の認証戦略を組み合わせる方法
- グローバルGuardと
@Public()デコレータによる柔軟な認可制御
Passportを活用することで、拡張性と保守性に優れた認証基盤を構築できます。OAuth連携やソーシャルログインなど、将来的な機能追加にも柔軟に対応できる設計が可能です。
参考リンク#