Passport の使い方 — Node.js の認証ミドルウェア完全ガイド
一言でいうと
Passport は、Node.js(Express / Connect)向けの認証ミドルウェアです。「ストラテジー」と呼ばれるプラグイン方式を採用しており、ローカル認証から OAuth、OpenID まで 480 以上の認証方式を統一的な API で扱えます。
どんな時に使う?
- ユーザー名・パスワードによるログイン機能を Express アプリに実装したいとき
- **Google / Facebook / Twitter などのソーシャルログイン(OAuth)**を導入したいとき
- 複数の認証方式を組み合わせて使いたいとき(例:ローカル認証 + Google OAuth を同一アプリで提供)
インストール
# npm
npm install passport
# yarn
yarn add passport
# pnpm
pnpm add passport
多くの場合、認証方式に対応するストラテジーパッケージも一緒にインストールします。
# ローカル認証の場合
npm install passport-local
# Google OAuth の場合
npm install passport-google-oauth20
# JWT 認証の場合
npm install passport-jwt
TypeScript を使う場合は型定義もインストールします。
npm install -D @types/passport @types/passport-local @types/express
基本的な使い方
最もよく使われるローカル認証(ユーザー名 + パスワード)の例を示します。
import express, { Request, Response, NextFunction } from 'express';
import session from 'express-session';
import passport from 'passport';
import { Strategy as LocalStrategy } from 'passport-local';
const app = express();
// --- ダミーのユーザーデータ ---
interface User {
id: number;
username: string;
password: string;
}
const users: User[] = [
{ id: 1, username: 'admin', password: 'secret123' },
];
// --- ミドルウェア設定 ---
app.use(express.urlencoded({ extended: false }));
app.use(
session({
secret: 'your-session-secret',
resave: false,
saveUninitialized: false,
})
);
app.use(passport.initialize());
app.use(passport.session());
// --- ストラテジー設定 ---
passport.use(
new LocalStrategy((username, password, done) => {
const user = users.find((u) => u.username === username);
if (!user) {
return done(null, false, { message: 'ユーザーが見つかりません' });
}
if (user.password !== password) {
return done(null, false, { message: 'パスワードが正しくありません' });
}
return done(null, user);
})
);
// --- シリアライズ / デシリアライズ ---
passport.serializeUser((user: Express.User, done) => {
done(null, (user as User).id);
});
passport.deserializeUser((id: number, done) => {
const user = users.find((u) => u.id === id);
done(null, user || false);
});
// --- ルート ---
app.post(
'/login',
passport.authenticate('local', {
successRedirect: '/dashboard',
failureRedirect: '/login',
})
);
app.get('/dashboard', (req: Request, res: Response) => {
if (!req.isAuthenticated()) {
return res.redirect('/login');
}
res.send(`ようこそ、${(req.user as User).username} さん`);
});
app.post('/logout', (req: Request, res: Response, next: NextFunction) => {
req.logout((err) => {
if (err) return next(err);
res.redirect('/');
});
});
app.listen(3000, () => {
console.log('Server running on http://localhost:3000');
});
よく使う API
1. passport.use() — ストラテジーの登録
認証ストラテジーを Passport に登録します。名前を付けて複数のストラテジーを使い分けることも可能です。
import { Strategy as GoogleStrategy } from 'passport-google-oauth20';
// デフォルト名(ストラテジーが内部で持つ名前)で登録
passport.use(
new GoogleStrategy(
{
clientID: process.env.GOOGLE_CLIENT_ID!,
clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
callbackURL: '/auth/google/callback',
},
(accessToken, refreshToken, profile, done) => {
// DB からユーザーを検索 or 作成
done(null, profile);
}
)
);
// カスタム名で登録(同じストラテジーを複数使う場合)
passport.use(
'admin-local',
new LocalStrategy((username, password, done) => {
// 管理者専用の認証ロジック
done(null, false);
})
);
2. passport.authenticate() — 認証の実行
ルートミドルウェアとして使用し、指定したストラテジーで認証を実行します。
// 基本的なリダイレクト方式
app.post(
'/login',
passport.authenticate('local', {
successRedirect: '/dashboard',
failureRedirect: '/login',
failureMessage: true, // セッションにエラーメッセージを保存
})
);
// カスタムコールバック方式(API サーバー向け)
app.post('/api/login', (req: Request, res: Response, next: NextFunction) => {
passport.authenticate(
'local',
(err: Error | null, user: User | false, info: { message: string }) => {
if (err) return next(err);
if (!user) {
return res.status(401).json({ message: info.message });
}
req.logIn(user, (err) => {
if (err) return next(err);
return res.json({ message: 'ログイン成功', user });
});
}
)(req, res, next);
});
3. passport.serializeUser() / passport.deserializeUser() — セッション管理
セッションにユーザー情報を保存・復元するロジックを定義します。
// セッションに保存する値を決定(通常は ID のみ)
passport.serializeUser((user: Express.User, done) => {
done(null, (user as User).id);
});
// セッションから復元する処理
passport.deserializeUser(async (id: number, done) => {
try {
// 実際のアプリでは DB から取得
const user = await UserRepository.findById(id);
done(null, user);
} catch (err) {
done(err);
}
});
4. req.isAuthenticated() / req.isUnauthenticated() — 認証状態の確認
リクエストが認証済みかどうかを判定します。認証ガードの実装に使います。
// 認証ガードミドルウェア
function ensureAuthenticated(
req: Request,
res: Response,
next: NextFunction
): void {
if (req.isAuthenticated()) {
return next();
}
res.status(401).json({ message: '認証が必要です' });
}
// ルートに適用
app.get('/api/profile', ensureAuthenticated, (req: Request, res: Response) => {
res.json(req.user);
});
5. req.logIn() / req.logOut() — 手動でのログイン・ログアウト
passport.authenticate() を使わずに、手動でセッションを操作する場合に使います。
// 手動ログイン(ユーザー登録直後に自動ログインさせる場合など)
app.post('/register', async (req: Request, res: Response, next: NextFunction) => {
const newUser = await UserRepository.create(req.body);
req.logIn(newUser, (err) => {
if (err) return next(err);
res.redirect('/dashboard');
});
});
// ログアウト(v0.6.0 以降はコールバック必須)
app.post('/logout', (req: Request, res: Response, next: NextFunction) => {
req.logOut((err) => {
if (err) return next(err);
res.redirect('/');
});
});
類似パッケージとの比較
| 特徴 | passport | express-jwt | Auth.js (NextAuth) | lucia |
|---|---|---|---|---|
| 対応フレームワーク | Express / Connect | Express | Next.js / SvelteKit 等 | フレームワーク非依存 |
| 認証方式 | 480+ ストラテジー | JWT のみ | OAuth / Email 等 | セッションベース |
| セッション管理 | あり(要設定) | なし(ステートレス) | 組み込み | 組み込み |
| DB 抽象化 | なし(自由) | なし | アダプター方式 | アダプター方式 |
| TypeScript サポート | @types/passport | 組み込み | 組み込み | 組み込み |
| 学習コスト | 中 | 低 | 低〜中 | 中 |
| 柔軟性 | 非常に高い | 低い | 中 | 高い |
補足: Passport は歴史が長く情報量が豊富ですが、設計がコールバック時代のものです。新規プロジェクトで Next.js や SvelteKit を使う場合は Auth.js、より現代的なセッション管理が欲しい場合は Lucia も検討する価値があります。
注意点・Tips
1. ミドルウェアの登録順序に注意
passport.initialize() と passport.session() は、必ず express-session の後に登録してください。順序を間違えるとセッションが機能しません。
// ✅ 正しい順序
app.use(session({ /* ... */ }));
app.use(passport.initialize());
app.use(passport.session());
// ❌ 間違い — session より先に passport を登録
app.use(passport.initialize());
app.use(session({ /* ... */ }));
2. req.logout() にはコールバックが必須(v0.6.0 以降)
v0.6.0 から req.logout() が非同期になりました。コールバックを渡さないとエラーになります。
// ❌ v0.6.0 以降ではエラー
req.logout();
// ✅ コールバックを渡す
req.logout((err) => {
if (err) return next(err);
res.redirect('/');
});
3. TypeScript で req.user の型を拡張する
デフォルトでは req.user は Express.User 型です。自分のユーザー型を使うには型定義を拡張します。
// types/express.d.ts
declare global {
namespace Express {
interface User {
id: number;
username: string;
email: string;
}
}
}
export {};
4. セッションを使わない API サーバーの場合
JWT 認証など、セッション不要な場合は session: false を指定します。
app.get(
'/api/data',
passport.authenticate('jwt', { session: false }),
(req: Request, res: Response) => {
res.json(req.user);
}
);
5. 本番環境でのセッションストア
デフォルトの MemoryStore は本番環境には不向きです。Redis や DB ベースのストアを使いましょう。
import RedisStore from 'connect-redis';
import { createClient } from 'redis';
const redisClient = createClient();
await redisClient.connect();
app.use(
session({
store: new RedisStore({ client: redisClient }),
secret: process.env.SESSION_SECRET!,
resave: false,
saveUninitialized: false,
})
);
まとめ
Passport は Node.js エコシステムにおける認証のデファクトスタンダードであり、480 以上のストラテジーによってほぼあらゆる認証方式に対応できます。ストラテジーの登録、シリアライズ/デシリアライズの設定、ミドルウェアの登録順序という 3 つのポイントを押さえれば、柔軟かつ堅牢な認証基盤を構築できます。設計はやや古典的ですが、その分枯れており、Express ベースのアプリケーションでは今なお有力な選択肢です。