BioPlayground

🧬
목록으로

구글 로그인 구현 — Passport + OAuth

Passport.js의 Google Strategy로 소셜 로그인을 구현합니다. 콘솔 설정부터 콜백 처리까지 전체 흐름을 다룹니다.

중급
|
15
|
검증 완료 (2026-07)
구글 로그인PassportOAuth 구현passport-google-oauth20소셜 인증
진행률0/26 (0%)

구글 로그인 구현 — Passport + OAuth

이 토픽을 마치면

Google Cloud Console에서 OAuth 클라이언트를 설정하고, Passport.js의 Google Strategy로 소셜 로그인을 구현할 수 있습니다.


전제 조건

이전 토픽에서 배운 내용이 필요합니다:

  • OAuth 2.0 흐름 — Authorization Code Flow의 4명 등장인물
  • Passport.js — Strategy 패턴과 serializeUser/deserializeUser
  • Express Session — 세션 기반 인증

이 세 가지가 합쳐져서 구글 로그인이 됩니다.


1단계 — Google Cloud Console 설정

구글에서 우리 앱을 등록해야 합니다. 이 과정은 코드가 아니라 웹 콘솔 작업입니다.

  1. Google Cloud Console → 새 프로젝트 생성
  2. "OAuth 동의 화면" → 앱 이름, 이메일 입력
  3. "사용자 인증 정보" → OAuth 2.0 클라이언트 ID 만들기
  4. 승인된 리다이렉션 URI에 http://localhost:3000/auth/google/callback 추가

결과로 Client IDClient Secret 두 개를 받습니다. 이 값은 .env에 저장합니다.

text
GOOGLE_CLIENT_ID=abc123...
GOOGLE_CLIENT_SECRET=xyz789...

2단계 — 패키지 설치

bash
npm install passport-google-oauth20

이미 passport, express-session이 설치되어 있다고 가정합니다.


3단계 — Strategy 등록

javascript
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에 구글 사용자 정보가 들어있음
    // DB에서 사용자를 찾거나 새로 생성
    const user = {
      googleId: profile.id,
      name: profile.displayName,
      email: profile.emails[0].value,
      photo: profile.photos[0].value,
    };

    // 실제로는 DB 조회/저장
    done(null, user);
  }
));

이 콜백 함수는 구글에서 인가 코드→토큰 교환이 끝난 뒤 호출됩니다. Passport가 OAuth의 복잡한 흐름을 전부 처리하고, 우리는 사용자 정보만 받으면 됩니다.


4단계 — 라우트 연결

javascript
// 구글 로그인 시작
app.get('/auth/google',
  passport.authenticate('google', { scope: ['profile', 'email'] })
);

// 구글이 인가 코드를 돌려보내는 곳
app.get('/auth/google/callback',
  passport.authenticate('google', { failureRedirect: '/login' }),
  (req, res) => {
    res.redirect('/');
  }
);

// 로그아웃
app.get('/logout', (req, res) => {
  req.logout(() => {
    res.redirect('/');
  });
});

흐름을 따라가 보겠습니다:

  1. 사용자가 /auth/google 접속 → 구글 로그인 화면으로 이동
  2. 구글에서 로그인 + 허용 → 구글이 /auth/google/callback?code=xxx로 리다이렉트
  3. Passport가 code로 토큰 교환 → Strategy 콜백 호출 → 세션에 사용자 저장
  4. res.redirect('/') → 로그인된 상태로 홈으로

5단계 — serialize/deserialize

javascript
passport.serializeUser((user, done) => {
  done(null, user.googleId);
});

passport.deserializeUser((googleId, done) => {
  // 실제로는 DB에서 googleId로 조회
  done(null, { googleId, name: '...' });
});

serialize는 세션에 뭘 저장할지, deserialize는 세션에서 꺼낸 값으로 사용자 객체를 복원하는 방법을 정의합니다.

세션에 사용자 객체 전체를 넣지 말고, ID만 저장하세요. 세션 데이터가 작을수록 서버 부담이 줄어듭니다.


전체 구조 정리

text
사용자                우리 서버              구글
  │                     │                    │
  ├─ /auth/google ─────→│                    │
  │                     ├─ redirect ────────→│
  │                     │                    │
  │←── 구글 로그인 화면 ─┤                    │
  │                     │                    │
  ├─ 로그인+허용 ───────→│                    │
  │                     │←── code ──────────┤
  │                     ├─ code+secret ─────→│
  │                     │←── access_token ──┤
  │                     ├─ token ───────────→│
  │                     │←── profile ───────┤
  │←── 세션 생성, / ─────┤                    │

Passport가 가운데 5단계(code 수신 → token 교환 → profile 요청)를 전부 처리합니다. 우리가 한 건 Strategy 등록과 라우트 연결뿐입니다.


자주 하는 실수

  1. redirect URI 불일치 — 콘솔에 등록한 URI와 코드의 callbackURL이 정확히 같아야 합니다. 슬래시 하나 차이로 에러 납니다.
  2. scope 누락scope: ['profile', 'email']을 안 넣으면 profile.emails가 undefined입니다.
  3. Client Secret 노출.env에 넣고 .gitignore.env를 추가하세요. GitHub에 Secret이 올라가면 구글이 자동으로 비활성화합니다.

핵심

Passport.js + Google Strategy는 OAuth 2.0의 복잡한 흐름을 Strategy 하나로 감싸줍니다. 우리가 할 일은 Console 설정 → Strategy 등록 → 라우트 2개 연결 — 이것이 전부입니다. 핵심 흐름: /auth/google → 구글 로그인 → /auth/google/callback → 세션 생성 → 홈 리다이렉트.