โ ์ด๊ฒ์ bit, bytes, protocol์ ๋ํ ๊ฒ์ด ์๋๋ค.
์ด์ต๊ณผ ์์ค, ๊ทธ๋ฆฌ๊ณ ๋ง์ง์ ๋ํ ๊ฒ์ด๋ค. โ- Lou Gerstner
๋งฅํจ์ง CEO

์นด์นด์ค ๋ก๊ทธ์ธ OAuth ์ ์ฒญ
์นด์นด์ค ๋ก๊ทธ์ธ์ ์ํด์๋ ์นด์นด์ค ๊ฐ๋ฐ์ ๊ณ์ ๊ณผ ๋ก๊ทธ์ธ์ฉ ์ ํ๋ฆฌ์ผ์ด์ ๋ฑ๋ก์ด ํ์ํ๋ค.
https://developers.kakao.com ์ ์ ์ํ์ฌ ๊ฐ๋ฐ์ ๊ณ์ ์ ๋ง๋ค๊ณ ์์ด๋๋ฅผ ๋ง๋ค์ด์ฃผ์.
Kakao Developers
์นด์นด์ค API๋ฅผ ํ์ฉํ์ฌ ๋ค์ํ ์ดํ๋ฆฌ์ผ์ด์ ์ ๊ฐ๋ฐํด๋ณด์ธ์. ์นด์นด์ค ๋ก๊ทธ์ธ, ๋ฉ์์ง ๋ณด๋ด๊ธฐ, ์น๊ตฌ API, ์ธ๊ณต์ง๋ฅ API ๋ฑ์ ์ ๊ณตํฉ๋๋ค.
developers.kakao.com
1. ๋ก๊ทธ์ธ์ ํ๊ณ ์ ํ๋ฆฌ์ผ์ด์ ์ถ๊ฐ๋ฅผ ์งํํ์.
์์ ์ด ์งํํ๋ ํฌํธํด๋ฆฌ์ค ํ๋ก์ ํธ๋ฅผ ์ ์ด์ฃผ๋ฉด ๋๋ค.


2. ๋๋ฉ์ธ์ ๋ฑ๋กํด์ค๋ค.
์ฝ๋ฐฑ ๋ฐ์ ๋๋ฉ์ธ์ ๋ฑ๋กํด์ผ ์นด์นด์ค ์๋ฒ๋ก๋ถํฐ ์นด์นด์ค ๊ณ์ ์ ๋ณด๋ฅผ ๋๊ฒจ ๋ฐ์์ ์๊ธฐ ๋๋ฌธ์ด๋ค.
๋๋ฉ์ธ์ ์ฌ๋ฌ๊ฐ๋ฅผ ์ ์ด์ค์ ์๋ค.


3. ์นด์นด์ค ๋ก๊ทธ์ธ์ ํ์ฑํํ๊ณ Redirect URI๋ฅผ ์ ์ด์ค๋ค.
์นด์นด์ค ์๋ฒ์์ ์ด๋ ์ฃผ์๋ก REST API GET์์ฒญ์ ๋ณด๋ผ์ง ์ ๋ ๊ฒ์ด๋ค.


4. ์นด์นด์ค ์ ๋ณด ๋์ ํญ๋ชฉ์ ์ค์ ํ๋ค.
๋๊ฒจ ๋ฐ์ ์นด์นด์ค ์ ๋ณด๋ฅผ ์ด๋๊ฑธ ๋ฐ์์ง ์ค์ ํ๋ ๊ฒ์ด๋ค.
์ด ํญ๋ชฉ์ ์ค์ ํ๋ค๋ฉด, ์ฌ์ฉ์๋ ๋ก๊ทธ์ธ ํ ๋ ๋์์๋ฅผ ์ฒ๋ฆฌํด์ผ ํ๋ค.


5. ์์ ์ ํ๋ก์ ํธ์ ํค ๋ฑ๋ก
REST APIํค๋ฅผ ํ๊ฒฝ๋ณ์๋ก ์ค์ ํด์ ๋ฑ๋กํด์ฃผ์.
์ด๋ kakaoStrategy์์ ์ฌ์ฉ๋ ์์ ์ด๋ค.


์นด์นด์ค ๋ก๊ทธ์ธ ๋ผ์ฐํฐ ์ ๋ต ๊ตฌํ
์นด์นด์ค ๋ก๊ทธ์ธ์ ๋ก๊ทธ์ธ ์ธ์ฆ ๊ณผ์ ์ ์นด์นด์ค์ ๋งก๊ธด๋ค.
์ฌ์ฉ์๋ ๋ฒ๊ฑฐ๋กญ๊ฒ ์๋ก์ด ์ฌ์ดํธ์ ํ์๊ฐ์ ํ ํ์๊ฐ ์์ด ์ข๊ณ , ์๋น์ค ์ ๊ณต์๋ ๋ก๊ทธ์ธ ๊ณผ์ ์ ๊ฒ์ฆ๋ SNS์ ์์ฌํ๊ณ ๋งก๊ธธ ์ ์์ด ํธํ๊ณ ์ข๋ค.
SNS ๋ก๊ทธ์ธ์ ํน์ง์ ํ์๊ฐ์ ์ ์ฐจ๊ฐ ๋ฐ๋ก ์๋ค๋ ๊ฒ์ด๋ค.
์นด์นด์ค๋ฅผ ์์๋ก ๋ค๊ฒฝ์ฐ, ๋ก๊ทธ์ธ๋ง ํ๋ฉด, ๋ฐ๋ก ํ์๊ฐ์ ์ ์ฐจ ์์ด ์ฌ์ดํธ์ ๋ก๊ทธ์ธ ํ ์ ์๋๊ฑธ ๋ด์์ ๊ฒ์ด๋ค.


passport-kakao ์ค์น
> npm install passport passport-kakao
passport-kakao
kakao oauth2 login module. Latest version: 1.0.1, last published: a year ago. Start using passport-kakao in your project by running `npm i passport-kakao`. There is 1 other project in the npm registry using passport-kakao.
www.npmjs.com
...๋ค์ด๊ฐ๊ธฐ์ ์์ ๐
passport ๋ฌธ๋ฒ์ ๊ต์ฅํ ๋ํดํ๊ณ ์ด๋ ต๋ค.
๋ฐ๋ผ์ ๋ณธ ๊ฐ์๋ passport์ฒ๋ฆฌ๊ณผ์ ์ ํ๋ํ๋์ฉ ์์ธํ ๋ค๋ฃฐ ์์ ์ด๋ค.
๋จผ์ ๊ทธ๋ฆผ์ผ๋ก ์ด๋ป๊ฒ ์์๋๋ก ์ฒ๋ฆฌ๋๋์ง๋ฅผ ๋ณด์ฌ์ฃผ๊ณ ๋ฐ๋ก ๋ค์, ์์ธํ ์ฝ๋ ์ค๋ช
์ ํตํด ๊ฐ์๋ฅผ ์ด์ด ๋๊ฐ ์์ ์ด๋ค.
์ฝ๋ ๋ฌธ๋ฒ๊ณผ ์ฒ๋ฆฌ๊ณผ์ ๊ทธ๋ฆผ์ ๊ณ์ ๋ฒ๊ฐ์ ๋ณด๋ฉฐ ์ดํดํ๋ ๊ฒ์ ๊ฐ๋ ฅ์ด ๊ถ์ฅํ๋ค.
๊ทธ๋ฆฌ๊ณ ๊ธฐ๋ณธ์ ์ผ๋ก OAuth์ ๋ํ ์ง์๊ณผ passport ๊ธฐ๋ณธ ๊ตฌ์กฐ์ ๋ํด์ ์๊ณ ์์ด์ผ ์ด ๊ฐ์ข๋ฅผ ์ด์ด๋๊ฐ์ ์๊ธฐ ๋๋ฌธ์ ๋ค์ ํฌ์คํ ์ ๊ฐ๋ ฅํ ์ฐธ๊ณ ํด์ ์ต๋ํ๊ณ ์ด์ด๋๊ฐ๊ธธ ๊ถ์ฅํ๋ค.
[WEB] ๐ OAuth 2.0 ๊ฐ๋ ๐ฏ ์ ๋ฆฌ
OAuth๋? ์น ์ํ์ ํ๋ค ๋ณด๋ฉด Google๊ณผ Facebook ๋ฑ์ ์ธ๋ถ ์์ ๊ณ์ ์ ๊ธฐ๋ฐ์ผ๋ก ๊ฐํธํ ํ์๊ฐ์ ๋ฐ ๋ก๊ทธ์ธํ ์ ์๋ ์น ์ดํ๋ฆฌ์ผ์ด์ ์ ์ฝ๊ฒ ์ฐพ์๋ณผ ์ ์๋ค. ํด๋ฆญ ํ ๋ฒ์ผ๋ก ๊ฐํธํ๊ฒ ๋ก๊ทธ์ธํ
inpa.tistory.com
[NODE] ๐ Passport ๋ชจ๋ (๊ทธ๋ฆผ์ผ๋ก ์ฒ๋ฆฌ ๊ณผ์ ๐ฏ ์ดํดํ์)
Passport Passport๋ ์ด๋ฆ ๊ทธ๋๋ก ์๋น์ค๋ฅผ ์ฌ์ฉํ ์ ์๊ฒ๋ ํด์ฃผ๋ ์ฌ๊ถ ๊ฐ์ ์ญํ ์ ํ๋ ๋ชจ๋์ด๋ค. ํ์๊ฐ์ ๊ณผ ๋ก๊ทธ์ธ์ ์ง์ ๊ตฌํํ ์๋ ์์ง๋ง, ์ธ์ ๊ณผ ์ฟ ํค ์ฒ๋ฆฌ ๋ฑ ๋ณต์กํ ์์ ์ด ๋ง์ผ๋ฏ๋ก
inpa.tistory.com
์นด์นด์ค ๋ก๊ทธ์ธ ์ธ์ฆ ์ ๋ต ์ฒ๋ฆฌ๊ณผ์
1. ๋ผ์ฐํฐ๋ฅผ ํตํด /kakao ์์ฒญ์ด ์๋ฒ๋ก ์จ๋ค.
2. passport.authenticate('kakao')๋ฅผ ํตํด์ ์นด์นด์ค ๋ก๊ทธ์ธ ํ์ด์ง๋ก ์ด๋ํ๋ค.
3. ์นด์นด์ค ๋ก๊ทธ์ธ์ ํ๋ฉด, ์นด์นด์ค ๋ก๊ทธ์ธ developer์์ ์ค์ ํ redirect url ๊ฒฝ๋ก์ ๋ฐ๋ผ ์๋ณ๊ฐ์ ์ ๋ฌํ๋ค
- Redirect URL : ํด๋น ํด๋ผ์ด์ธํธ๋ฅผ ์๋ณํ๊ณ ์๋ณ๊ฐ(Access token)์ ์ ๋ฌํ ํต๋ก
4. /kakao/callback ๋ผ์ฐํฐ๋ก ์์ฒญ์ด ์ค๊ฒ ๋๋ค.

5. passport.authenticate('kakao')์์ kakaoStrategy๋ก ์ธ์ฆ ์ ๋ต ์ํ. ์ ๋ต์๋ ์นด์นด์ค ์๋ฒ์์ ๋ณด๋ธ ์นด์นด์ค ๊ณ์ ์ ๋ณด๊ฐ ๋ค์ด์๋ค.

6. ์นด์นด์ค์ ๋ต์์ DB์์ ๊ฐ์ ์ด๋ ฅ ์กฐ์ฌ
7. ๊ฐ์ ์ด๋ ฅ ์์ผ๋ฉด ๋ฐ๋ก ์ฑ๊ณต done()์ ๋ณด๋ด๊ณ , ์๋ค๋ฉด ๋ฐ๋ก ํ์๊ฐ์ ์ํค๊ณ ์ฑ๊ณต done()์ ๋ณด๋
8. ํด๋ผ์ด์ธํฐ์ ์ธ์ ์ฟ ํค๋ฅผ ๋ณด๋์ผ๋ก์ ๋ก๊ทธ์ธ ์ธ์ฆ ์๋ฃ

์นด์นด์ค ๋ก๊ทธ์ธ ์ธ์ฆ ์ ๋ต ์ฝ๋
๋ธ๋ผ์ฐ์ ํ๊ทธ์ ์์ฒญํ๊ธฐ ์ํ href=/auth/kakao ๋งํฌ ํ๊ทธ๋ฅผ ์ค์ ํ๋ค.
์ด ์นด์นด์คํก ๋ก๊ทธ์ธ ๋ฒํผ์ ๋๋ฅด๊ฒ ๋๋ฉด, ๋ผ์ฐํฐ GET /auth/kakao ๋ก ์ ๊ทผํด ์นด์นด์ค ๋ก๊ทธ์ธ ๊ณผ์ ์ด ์์๋๊ฒ ๊ตฌ์ฑํ ๊ฒ์ด๋ค.
<a id="kakao" href="/auth/kakao" class="btn">์นด์นด์คํก ๋ก๊ทธ์ธ</a>
๊ทธ๋์ ๋ค์๊ณผ ๊ฐ์ด ๊ตฌ์ฑํ๋ฉด, /auth ์ชฝ์ผ๋ก ์๋ฒ๊ฐ ์์ฒญ์ค๋ฉด authRouter(./routes/auth.js) ํ์ผ๋ก ๊ฐ๊ฒ ๋ ๊ฒ์ด๋ค.
...
const pageRouter = require('./routes/page');
const authRouter = require('./routes/auth');
...
app.use('/', pageRouter);
app.use('/auth', authRouter);
...
routes/auth.js
//* ์นด์นด์ค๋ก ๋ก๊ทธ์ธํ๊ธฐ ๋ผ์ฐํฐ ***********************
//? /kakao๋ก ์์ฒญ์ค๋ฉด, ์นด์นด์ค ๋ก๊ทธ์ธ ํ์ด์ง๋ก ๊ฐ๊ฒ ๋๊ณ , ์นด์นด์ค ์๋ฒ๋ฅผ ํตํด ์นด์นด์ค ๋ก๊ทธ์ธ์ ํ๊ฒ ๋๋ฉด, ๋ค์ ๋ผ์ฐํฐ๋ก ์์ฒญํ๋ค.
router.get('/kakao', passport.authenticate('kakao'));
//? ์์์ ์นด์นด์ค ์๋ฒ ๋ก๊ทธ์ธ์ด ๋๋ฉด, ์นด์นด์ค redirect url ์ค์ ์ ๋ฐ๋ผ ์ด์ชฝ ๋ผ์ฐํฐ๋ก ์ค๊ฒ ๋๋ค.
router.get(
'/kakao/callback',
//? ๊ทธ๋ฆฌ๊ณ passport ๋ก๊ทธ์ธ ์ ๋ต์ ์ํด kakaoStrategy๋ก ๊ฐ์ ์นด์นด์ค๊ณ์ ์ ๋ณด์ DB๋ฅผ ๋น๊ตํด์ ํ์๊ฐ์
์ํค๊ฑฐ๋ ๋ก๊ทธ์ธ ์ฒ๋ฆฌํ๊ฒ ํ๋ค.
passport.authenticate('kakao', {
failureRedirect: '/', // kakaoStrategy์์ ์คํจํ๋ค๋ฉด ์คํ
}),
// kakaoStrategy์์ ์ฑ๊ณตํ๋ค๋ฉด ์ฝ๋ฐฑ ์คํ
(req, res) => {
res.redirect('/');
},
);
GET /auth/kakao์์ ๋ก๊ทธ์ธ ์ ๋ต์ ์ํํ๋๋ฐ, ์ด ๋ ์นด์นด์ค ๋ก๊ทธ์ธ ์ฐฝ์ผ๋ก ๋ฆฌ๋ค์ด๋ ํธํ๋ค.
๊ทธ๋ฆฌ๊ณ ๋ก๊ทธ์ธ ์ฐฝ์์ ์ฌ์ฉ์๊ฐ ID/PW๋ฅผ ์ณ์ ๋ก๊ทธ์ธํ๋ฉด, ์ฑ๊ณต ์ฌ๋ถ ๊ฒฐ๊ณผ๋ฅผ GET /auth/kakao/callback์ผ๋ก ๋ฐ๊ฒ๋๋ค.
๊ทธ๋ฆฌ๊ณ kakao/callback ๋ผ์ฐํฐ์์๋ ์นด์นด์ค ๋ก๊ทธ์ธ ์ ๋ต์ ๋ค์ ์ํํ๋ค.
๋ก์ปฌ ๋ก๊ทธ์ธ๊ณผ ๋ค๋ฅธ ์ ์ passport.authenticate ๋ฉ์๋์ ์ฝ๋ฐฑ ํจ์๋ฅผ ์ ๊ณตํ์ง ์๋๋ค๋ ์ ์ด๋ค.
์นด์นด์ค ๋ก๊ทธ์ธ์ ๋ก๊ทธ์ธ ์ฑ๊ณต ์ ๋ด๋ถ์ ์ผ๋ก req.login์ ํธ์ถํ๋ฏ๋ก, ์ฐ๋ฆฌ๊ฐ ์ง์ ํธ์ถํ ํ์๊ฐ ์๋ค.
์ฝ๋ฐฑ ํจ์ ๋์ ๋ก๊ทธ์ธ์ ์คํจํ์ ๋ ์ด๋๋ก ์ด๋ํ ์ง๋ฅผ failureRedirect ์์ฑ์ ์ ์ด์ค๋ค.
์ฑ๊ณตํ์ ๋์๋ ์ด๋๋ก ์ด๋ํ ์ง๋ฅผ ๋ฏธ๋ค์จ์ด์ ์ ์ด์ค๋ค.
passport/kakaoStrategy.js
const passport = require('passport');
const KakaoStrategy = require('passport-kakao').Strategy;
const User = require('../models/user');
module.exports = () => {
passport.use(
new KakaoStrategy(
{
clientID: process.env.KAKAO_ID, // ์นด์นด์ค ๋ก๊ทธ์ธ์์ ๋ฐ๊ธ๋ฐ์ REST API ํค
callbackURL: '/auth/kakao/callback', // ์นด์นด์ค ๋ก๊ทธ์ธ Redirect URI ๊ฒฝ๋ก
},
/*
* clientID์ ์นด์นด์ค ์ฑ ์์ด๋ ์ถ๊ฐ
* callbackURL: ์นด์นด์ค ๋ก๊ทธ์ธ ํ ์นด์นด์ค๊ฐ ๊ฒฐ๊ณผ๋ฅผ ์ ์กํด์ค URL
* accessToken, refreshToken: ๋ก๊ทธ์ธ ์ฑ๊ณต ํ ์นด์นด์ค๊ฐ ๋ณด๋ด์ค ํ ํฐ
* profile: ์นด์นด์ค๊ฐ ๋ณด๋ด์ค ์ ์ ์ ๋ณด. profile์ ์ ๋ณด๋ฅผ ๋ฐํ์ผ๋ก ํ์๊ฐ์
*/
async (accessToken, refreshToken, profile, done) => {
console.log('kakao profile', profile);
try {
const exUser = await User.findOne({
// ์นด์นด์ค ํ๋ซํผ์์ ๋ก๊ทธ์ธ ํ๊ณ & snsIdํ๋์ ์นด์นด์ค ์์ด๋๊ฐ ์ผ์นํ ๊ฒฝ์ฐ
where: { snsId: profile.id, provider: 'kakao' },
});
// ์ด๋ฏธ ๊ฐ์
๋ ์นด์นด์ค ํ๋กํ์ด๋ฉด ์ฑ๊ณต
if (exUser) {
done(null, exUser); // ๋ก๊ทธ์ธ ์ธ์ฆ ์๋ฃ
} else {
// ๊ฐ์
๋์ง ์๋ ์ ์ ๋ฉด ํ์๊ฐ์
์ํค๊ณ ๋ก๊ทธ์ธ์ ์ํจ๋ค
const newUser = await User.create({
email: profile._json && profile._json.kakao_account_email,
nick: profile.displayName,
snsId: profile.id,
provider: 'kakao',
});
done(null, newUser); // ํ์๊ฐ์
ํ๊ณ ๋ก๊ทธ์ธ ์ธ์ฆ ์๋ฃ
}
} catch (error) {
console.error(error);
done(error);
}
},
),
);
};
๋ก์ปฌ ๋ก๊ทธ์ธ๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก ์ฒซ ๋ฒ์งธ ์ธ์๋ก ์นด์นด์ค ๋ก๊ทธ์ธ์ ๋ํ ์ค์ ์ ํ๋ค.
- clientID๋ ์นด์นด์ค์์ ๋ฐ๊ธํด์ฃผ๋ ์์ด๋์ด๋ค. ๋ ธ์ถ๋์ง ์์์ผํ๋ฏ๋ก .env ํ์ผ์ ๋ฃ์ด์ค ๊ฒ์ด๋ค.
- callbackURL์ ์นด์นด์ค๋ก๋ถํฐ ์ธ์ฆ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ์ ๋ผ์ฐํฐ ์ฃผ์์ด๋ค.
๊ทธ ํ๋ก ๋ค์ด์ค๋ ๋ ๋ฒ์งธ ์ธ์ ์ฝ๋ฐฑ์ด ์คํ๋๋ค.
๋จผ์ , ๊ธฐ์กด์ ์นด์นด์ค๋ฅผ ํตํด ํ์๊ฐ์ ํ ์ฌ์ฉ์๊ฐ ์๋์ง๋ฅผ profile.id๋ก ์กฐํํ๋ค.
์๋ค๋ฉด ์ด๋ฏธ ํ์๊ฐ์ ์ด ๋์ด ์๋ ๊ฒฝ์ฐ์ด๋ฏ๋ก ์ฌ์ฉ์ ์ ๋ณด์ ํจ๊ป done ํจ์๋ฅผ ํธ์ถํ๊ณ ์ ๋ต์ ์ข ๋ฃํ๋ค.
๋ง์ผ ์นด์นด์ค๋ฅผ ํตํด ํ์๊ฐ์ ํ ์ฌ์ฉ์๊ฐ ์๋ค๋ฉด ํด๋น ์ฌ์ฉ์์ ํ์๊ฐ์ ์ ์๋์ผ๋ก ์งํํ๋ค.
์นด์นด์ค์์๋ ์ธ์ฆ ํ callbackURL์ ์ ํ ์ฃผ์๋ก accessToken, refreshToken๊ณผ profile์ ๋ณด๋ด๋๋ฐ, profile์ ์ฌ์ฉ์ ์ ๋ณด๋ค์ด ๋ค์ด์๋ค.
์ดํ ์ํ๋ ์ ๋ณด๋ค์ profile ๊ฐ์ฒด์์ ๊บผ๋ด์ ํ์๊ฐ์ ์ ์งํํ๋ฉด ๋๋ค.
์ฌ์ฉ์๋ฅผ ์์ฑํ ๋ค done ํจ์๋ฅผ ํธ์ถํ๊ฒ ๋๋ค.
passport/index.js
- kakaoStrategy.js ๋ฅผ passport์ ๋ฑ๋กํ๋ค.
const passport = require('passport');
const local = require('./localStrategy'); // ๋ก์ปฌ์๋ฒ๋ก ๋ก๊ทธ์ธํ ๋
const kakao = require('./kakaoStrategy'); // ์นด์นด์ค์๋ฒ๋ก ๋ก๊ทธ์ธํ ๋
const User = require('../models/user');
module.exports = () => {
passport.serializeUser((user, done) => {
done(null, user.id);
});
passport.deserializeUser((id, done) => {
//? ๋๋ฒ inner ์กฐ์ธํด์ ๋๋ฅผ ํ๋ก์ฐํ๋ followerid์ ๋ด๊ฐ ํ๋ก์ฐ ํ๋ followingid๋ฅผ ๊ฐ์ ธ์ ํ
์ด๋ธ์ ๋ถ์ธ๋ค
User.findOne({ where: { id } })
.then(user => done(null, user))
.catch(err => done(err));
});
local();
kakao(); // ๊ตฌ๊ธ ์ ๋ต ๋ฑ๋ก
};
์ด ๊ธ์ด ์ข์ผ์ จ๋ค๋ฉด ๊ตฌ๋ & ์ข์์
์ฌ๋ฌ๋ถ์ ๊ตฌ๋
๊ณผ ์ข์์๋
์ ์์๊ฒ ํฐ ํ์ด ๋ฉ๋๋ค.