[passport.js] state 매개변수로 Oauth Callback API에 데이터 전달하기

서해빈·2021년 6월 30일
0

Javascript

목록 보기
11/11

발단

passport.js를 사용해 구글, 네이버, 카카오 소셜로그인을 구현했었다.
클라이언트로부터 소셜 로그인 요청이 들어올 때 로그인하는 사용자의 종류가 query로 주어지는데, 소셜 로그인 이후 redirect되는 callback API에서 이 값을 사용하고 싶었다.

처음에는 이를 위해 req.session.type같은 형태로 해당 사용자 세션에 저장하는 식으로 해결했었다. 정상적으로 작동함도 확인했지만, 추후 express의 세션을 jwt으로 대체할 계획이 있었기 때문에 다른 해결 방법을 고민하게 되었다.

// 기존 api
app.get(
  `/auth/naver`,
  (req, res, next) => {
    const { type } = req.query
    req.session.type = type;
    next();
  },
  passport.authenticate('naver')
);

// 기존 passport naver strategy
const registerNaverStrategy = passport => {
  passport.use(
    new NaverStrategy(
      {
        clientID: NAVER_CLIENT_ID,
        clientSecret: NAVER_CLIENT_SECRET,
        callbackURL: '/api/auth/naver/callback',
        passReqToCallback: true,
      },
      async (req, accessToken, refreshToken, profile, done) => {
        // ... 생략
        
        const type = req.session.Type; // session에 저장한 값 사용
        
        // ... 생략
      },
    ),
  );
};

state

네이버 개발자 문서의 로그인 API 명세에서는 state 변수에 대해 다음과 같이 설명하고 있다

state

사이트 간 요청 위조(cross-site request forgery) 공격을 방지하기 위해 애플리케이션에서 생성한 상태 토큰값으로 URL 인코딩을 적용한 값을 사용

state가 로그인 요청과 콜백 간에 동일한 상태를 유지하기 위해 사용된다는 점에서 목적에 부합하다고 생각되었다.

구현은 Dynamic Auth Redirects With PassportJS 글을 참고했다. 세세한 수정 내용은 생략하도록 하겠다.

결론

// 수정본
app.get(`/auth/naver`, (req, res) => {
  const { type } = req.query
  // Base64 Encoding
  const state = type ? Buffer.from(JSON.stringify({ type }), 'utf8').toString('base64') : null;
  passport.authenticate('naver', { state })(req, res);
});

// 수정본 passport naver strategy
const registerNaverStrategy = passport => {
  passport.use(
    new NaverStrategy(
      {
        clientID: NAVER_CLIENT_ID,
        clientSecret: NAVER_CLIENT_SECRET,
        callbackURL: '/api/auth/naver/callback',
        passReqToCallback: true,
      },
      async (req, accessToken, refreshToken, profile, done) => {
        // ... 생략
        
        const { state } = req.query;
        // Base64 Decoding
        const { userType: type } = JSON.parse(Buffer.from(state, 'base64').toString('utf8'));
        
        // ... 생략
      },
    ),
  );
};

참고 및 출처

  1. Dynamic Auth Redirects With PassportJS - 바로가기
  2. Node.js Base64 Encoding, Decoding - 바로가기
  3. [geeksforgeeks] Node.js | Buffer.from() Method - 바로가기
  4. JavaScript에서 Base64 Encode Decode 방법과 예제로 확인하기 - 바로가기

0개의 댓글