Googleログインの実装 — Passport + OAuth
このトピックを終えると
Google Cloud ConsoleでOAuthクライアントを設定し、Passport.jsのGoogle Strategyを使ってソーシャルログインを実装できるようになります。
前提条件
以前のトピックで学んだ内容が必要です。
- OAuth 2.0フロー — Authorization Code Flowの4つの登場人物
- Passport.js — StrategyパターンとserializeUser/deserializeUser
- Express Session — セッションベース認証
これら3つを組み合わせることで、Googleログインが実現します。
1단계 — Google Cloud Consoleの設定
Googleでアプリケーションを登録する必要があります。この手順はコードではなく、Webコンソールの操作です。
- Google Cloud Console → 新しいプロジェクトの作成
- 「OAuth同意画面」→ アプリケーション名、メールアドレスを入力
- 「認証情報」→ OAuth 2.0クライアントIDの作成
- 許可されたリダイレクトURIに
http://localhost:3000/auth/google/callbackを追加
その結果、クライアントIDとクライアントシークレットの2つを受け取ります。これらの値を.envに保存します。
GOOGLE_CLIENT_ID=abc123...
GOOGLE_CLIENT_SECRET=xyz789...2단계 — パッケージのインストール
npm install passport-google-oauth20すでにpassportとexpress-sessionがインストールされていると仮定します。
3단계 — Strategyの登録
const passport = require('passport');
const GoogleStrategy = require('passport-google-oauth20').Strategy;
passport.use(new GoogleStrategy({
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: '/auth/google/callback',
},
(accessToken, refreshToken, profile, done) => {
// profileにGoogleユーザー情報が含まれています
// データベースからユーザーを検索するか、新規作成します
const user = {
googleId: profile.id,
name: profile.displayName,
email: profile.emails[0].value,
photo: profile.photos[0].value,
};
// 実際にはデータベースの検索/保存を行います
done(null, user);
}
));このコールバック関数は、Googleからの認証コード→トークンの交換が完了した後に呼び出されます。PassportがOAuthの複雑なフローをすべて処理し、私たちはユーザー情報だけを受け取ります。
4단계 — ルートの接続
// Googleログインの開始
app.get('/auth/google',
passport.authenticate('google', { scope: ['profile', 'email'] })
);
// Googleが認証コードを返す場所
app.get('/auth/google/callback',
passport.authenticate('google', { failureRedirect: '/login' }),
(req, res) => {
res.redirect('/');
}
);
// ログアウト
app.get('/logout', (req, res) => {
req.logout(() => {
res.redirect('/');
});
});フローを追ってみましょう。
- ユーザーが
/auth/googleにアクセス→Googleログイン画面にリダイレクト - Googleでログイン+許可→Googleが
/auth/google/callback?code=xxxにリダイレクト - Passportが
codeでトークンを交換→Strategyコールバックを呼び出し→セッションにユーザー情報を保存 res.redirect('/')→ログインされた状態でホームページにリダイレクト
5단계 — serialize/deserialize
passport.serializeUser((user, done) => {
done(null, user.googleId);
});
passport.deserializeUser((googleId, done) => {
// 実際にはデータベースからgoogleIdで検索します
done(null, { googleId, name: '...' });
});serializeは、セッションに何を保存するかを、deserializeは、セッションから取り出した値からユーザーオブジェクトを復元する方法を定義します。
セッションにユーザーオブジェクト全体を保存するのではなく、IDだけを保存してください。セッションデータが少ないほど、サーバーの負担が軽減されます。
全体構造の整理
ユーザー サーバー Google
│ │ │
├─ /auth/google ─────→│ │
│ ├─ redirect ────────→│
│ │ │
│←── Googleログイン画面 ─┤ │
│ │ │
├─ ログイン+許可 ───────→│ │
│ │←── code ──────────┤
│ ├─ code+secret ─────→│
│ │←── access_token ──┤
│ ├─ token ───────────→│
│ │←── profile ───────┤
│←── セッション作成、/ ─────┤ │Passportが中央の5段階(codeの受信→トークンの交換→profileのリクエスト)をすべて処理します。私たちがすることは、Strategyの登録とルートの接続だけです。
よくある間違い
- リダイレクトURIの不一致 — コンソールに登録したURIとコードの
callbackURLが正確に一致している必要があります。スラッシュが1つ違うだけでエラーが発生します。 - スコープの欠落 —
scope: ['profile', 'email']を設定しないと、profile.emailsがundefinedになります。 - クライアントシークレットの露出 —
.envに保存し、.gitignoreに.envを追加してください。GitHubにシークレットがアップロードされると、Googleが自動的に無効化します。
核心
Passport.js + Google Strategyは、OAuth 2.0の複雑なフローをStrategy1つにまとめてくれます。 私たちがすることは、コンソールの設定→Strategyの登録→ルート2つの接続—これだけです。 主要なフロー:
/auth/google→Googleログイン→/auth/google/callback→セッションの作成→ホームページへのリダイレクト。