はじめに
NestJS と Firebase Auth を組み合わせることで、スケーラブルで安全な認証基盤を素早く構築できます。本記事では、カスタム Guard の実装からロールベースアクセス制御まで、実装手順を解説します。
Firebase Admin SDK のセットアップ
まず、Firebase Admin SDK を NestJS に組み込むためのモジュールを作成します。
// firebase-admin.module.ts
@Module({
providers: [
{
provide: "FIREBASE_ADMIN",
useFactory: () => {
return admin.initializeApp({
credential: admin.credential.applicationDefault(),
});
},
},
],
exports: ["FIREBASE_ADMIN"],
})
export class FirebaseAdminModule {}
AuthGuard の実装
Firebase ID トークンを検証する Guard を作成します。
@Injectable()
export class FirebaseAuthGuard implements CanActivate {
constructor(@Inject("FIREBASE_ADMIN") private firebaseApp: admin.app.App) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
const request = context.switchToHttp().getRequest();
const authHeader = request.headers.authorization;
if (!authHeader?.startsWith("Bearer ")) {
throw new UnauthorizedException();
}
const token = authHeader.split("Bearer ")[1];
const decoded = await this.firebaseApp.auth().verifyIdToken(token);
request.user = decoded;
return true;
}
}
ロールベースアクセス制御
カスタムデコレータと Guard を組み合わせて、ロールベースのアクセス制御を実現します。
// roles.decorator.ts
export const Roles = (...roles: string[]) => SetMetadata("roles", roles);
// roles.guard.ts
@Injectable()
export class RolesGuard implements CanActivate {
constructor(private reflector: Reflector) {}
canActivate(context: ExecutionContext): boolean {
const roles = this.reflector.get<string[]>("roles", context.getHandler());
if (!roles) return true;
const request = context.switchToHttp().getRequest();
const userRole = request.user?.role;
return roles.includes(userRole);
}
}
コントローラーでの使用
@Controller("admin")
@UseGuards(FirebaseAuthGuard, RolesGuard)
export class AdminController {
@Get("users")
@Roles("admin")
findAllUsers() {
return this.userService.findAll();
}
}
まとめ
NestJS の DI と Guard の仕組みは、Firebase Auth との相性が非常に良いです。この構成をベースに、マルチテナントや権限管理など、より複雑な要件にも対応できます。