Posts passportjs를 이용한 google OAuth 로그인 기능 구현하기
Post
Cancel

passportjs를 이용한 google OAuth 로그인 기능 구현하기

0. 구글 API console에 접속해 OAuth 클라이언트 ID를 만들기


구글 API console에 접속해서 사용자 인증 정보 만들기 > OAuth 클라이언트 ID를 만든다.

OAuth 클라이언트 ID

1. frontend 서버에서 요청을 보낼 버튼 만들기


백엔드 서버 /user/google 주소로 GET요청을 보내도록 버튼을 만듭니다. 예를 들면 http://localhost:3051/user/google

components>GoogleLoginBtn.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import React, { useCallback } from 'react';
import { GoogleLoginButton } from 'react-social-login-buttons';
import { useRouter } from 'next/router';
import { backUrl } from '../config/config';
import { Tooltip } from 'antd';
const GoogleLoginBtn = () => {

    const router = useRouter();
    const onClickGoogleLogin = useCallback(() => {
        router.push(`${backUrl}/user/google`);

    }, []);
    return (
        <Tooltip
            placement="bottom"
            title=" 안드로이드 , iOS 및 OS X 사용자는 크롬 브라우저로 구글로 로그인하기 기능을 이용해주세요.">
            <GoogleLoginButton
                onClick={onClickGoogleLogin}
                align="center"
                size="40px"
                text="Google"
                style=
            />
        </Tooltip>
    );
};

export default GoogleLoginBtn;



2. backend server에서 구글 로그인 전략 짜기


.dotenv 파일에 구글 API console에서 OAuth 2.0 클라이언트 ID로 들어가면 GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET 값을 알 수 있습니다. git에는 올리지 않도록 주의하기!
callbackURL에는 받은 client 로그인 정보를 보낼 redirect url를 적어줍니다. 그러면 결과를 GET ‘/user/google/callback’으로 받습니다.

passport>google.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
const passport = require('passport');
const dotenv = require('dotenv');
const bcrypt = require('bcrypt');

//구글 로그인 전략
dotenv.config();
const { User } = require('../models');
const GoogleStrategy = require('passport-google-oauth').OAuth2Strategy;

module.exports = () => {
    passport.use(new GoogleStrategy({
        clientID: process.env.GOOGLE_CLIENT_ID,
        clientSecret: process.env.GOOGLE_CLIENT_SECRET,
        callbackURL: '/user/google/callback',
    },
        async (accessToken, refreshToken, profile, done) => {
            // console.log('profile', profile);
            try {
                const exUser = await User.findOne({
                    where: {
                        email: profile.emails[0].value,
                        provider: 'google',
                    },

                });
                if (exUser) {
                    return done(null, exUser);
                }
                else {
                    const hashedPassword = await bcrypt.hash(profile.displayName, 11);
                    const newUser = await User.create({
                        email: profile.emails[0].value,
                        password: hashedPassword,
                        nickname: profile.displayName,
                        snsId: profile.id,
                        provider: 'google',
                    });
                    done(null, newUser);
                }
            }
            catch (err) {
                console.error(err);
                done(err);
            }

        }
    ));
};



passport>index.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
const passport = require('passport');
const { User } = require('../models');
const local = require('./local');
const google = require('./google');
const facebook = require('./facebook');

//로그인 설정
module.exports = () => {
    passport.serializeUser((user, done) => {   
        done(null, user.id);
    });
    passport.deserializeUser(async (id, done) => {
        try {
            const user = await User.findOne({
                where: { id }
            });
            done(null, user);//req.user
        } catch (err) {
            console.error(err);
            done(err);
        }
    });
    local();
    google();
    facebook();
};



3. backend server에서 google oauth를 통해 받은 요청을 front로 다시 보낼 router 만들기


scope에는 클라이언트 로그인 정보 중 필요한 정보가 무엇인지 넣어주면 된다. 저는 ‘profile’, ‘email’ 값을 요청했습니다. GET /user/google 로 요청을 보내면 GET /google/callback으로 값을 받는다. 이를 다시 프론트 서버 주소(여기서는 frontUrl)로 보내주도록 합니다.

passport>routes>user.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const express = require('express');
const router = express.Router();
const passport = require('passport');
const prod = process.env.NODE_ENV === 'production';
const frontUrl = prod ? "https://ymillonga.xyz" : "http://localhost:3050";

router.get('/google', function (req, res, next) {// GET /user/google
    passport.authenticate('google', { scope: ['profile', 'email'] })(req, res, next);
});

router.get('/google/callback', passport.authenticate('google', {
    failureRedirect: '/',
}), async (req, res, next) => {
    return res.status(200).redirect(frontUrl);

});
module.exports = router;



4. 구글 redirection url 수정하기



front-login-error
저의 경우 AWS에 배포하는 과정에서 로그인을 할 때 ` isAxiosError: true`라는 에러가 발생했는데 redirection url를 배포 도메인으로 다시 설정해주지 않아서였습니다.

구글 403 승인오류


403 에러 메세지가 나온다는 것은 승인된 redirection URL에 해당 주소값을 넣어주지 않았기 때문에 발생합니다.

아래와 같이 승인된 자바스크립트 원본( 브라우저 요청에 사용)에 프론트서버 주소를, 승인된 리디렉션 URI(웹 서버의 요청에 사용)에는 백서버 주소를 넣어줍니다.

승인된 redirection URL

참고로 2016년 10월 20일 이후로 안드로이드 , iOS 및 OS X 사용자는 크롬 브라우저로만 구글 oauth를 이용한 로그인이 가능하다.

안드로이드 구글 403 승인오류

참고:

구글 API console

passportjs 공식 홈페이지

인프런 react nodebird 강의

zerocho node-js

403. Error: disallowed_useragent

This post is licensed under CC BY 4.0 by the author.

mysql timezone 수정하기

facebook OAuth redirect url 설정하기

Comments powered by Disqus.