Skip to content
nuguya edited this page Nov 30, 2019 · 1 revision

Google Oauth for JWT

using Oauth with passport

๊ตฌ๊ธ€ ํด๋ผ์šฐ๋“œ ํ”Œ๋žซํผ์— ๋“ค์–ด๊ฐ€์„œ ํ”„๋กœ์ ํŠธ ๋“ฑ๋ก ํ›„ OAuth key์™€ id๋ฅผ ๋ฐœ๊ธ‰๋ฐ›๋Š”๋‹ค. - ์ด ๋•Œ ๊ฐœ๋ฐœ์šฉ์œผ๋กœ ์‚ฌ์šฉํ–ˆ๊ธฐ์— url๊ณผ ๋ฆฌ๋‹ค์ด๋ ‰์…˜ url์€ ๋กœ์ปฌํ˜ธ์ŠคํŠธ๋ฅผ ์ ์šฉํ•จ.

๋“ฑ๋ก๋ฐ›์€ key์™€ id๋ฅผ ํ™˜๊ฒฝ๋ณ€์ˆ˜๋‚˜ ๋ณ„๋„์˜ ํŒŒ์ผ๋กœ ๋ถ„๋ฆฌํ•˜์—ฌ ์ €์žฅ.

passport-google-oauth20 ๋ชจ๋“ˆ ์„ค์น˜ ํ›„ initialize๋ฅผ ์œ„ํ•œ strategy ์„ค์ •.

import passport from "passport";
import { Strategy } from "passport-google-oauth20";
import loadConfig from "../config/configLoader";
import { createHost, findHostById } from "../../DB/queries/host";

const GoogleStrategy = Strategy;

function extractProfile(profile) {
	let imageUrl = "";
	if (profile.photos && profile.photos.length) {
		imageUrl = profile.photos[0].value;
	}
	return {
		id: profile.id,
		displayName: profile.displayName,
		image: imageUrl,
		email: profile.emails[0].value,
	};
}

export default (function() {
	const { oAuthArgs } = loadConfig();
	passport.use(
		new GoogleStrategy(
			{ ...oAuthArgs },
			async (accessToken, refreshToken, profile, cb) => {
				try {
					const { id, displayName, image, email } = extractProfile(
						profile
					);
					let host = await findHostById(id);
					if (!host) host = await createHost(id, displayName, email);
					return cb(null, host);
				} catch (error) {
					console.error(error);
				}
			}
		)
	);
})();
  • ๋”ฐ๋กœ Token์„ ์ƒ์„ฑํ•˜๊ธฐ ๋•Œ๋ฌธ์— accessToken๊ณผ refreshToken์€ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Œ, profile์€ ๊ตฌ๊ธ€ ์ธ์ฆ ์„ฑ๊ณต ํ›„ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋Š” ์‚ฌ์šฉ์ž ํ”„๋กœํ•„์— ํ•ด๋‹น.
  • profile์—์„œ ๋ฐ˜ํ™˜ํ•˜๋Š” id ๊ฐ’์œผ๋กœ DB์— ์ด๋ฏธ ๋“ฑ๋ก๋˜์–ด์žˆ๋Š”์ง€ ์ฒดํฌ ํ›„ ๋“ฑ๋ก๋˜์–ด์žˆ์ง€ ์•Š์œผ๋ฉด, ์œ ์ € ์ƒ์„ฑ.
  • session์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— serialize์™€ deserialize๋Š” ์„ ์–ธํ•˜์ง€ ์•Š์Œ.

๊ตฌ๊ธ€ ๋กœ๊ทธ์ธ์— ์ ‘์† ํ•  ์ˆ˜ ์žˆ๋Š” endpoint๋ฅผ ์ •์˜ํ•˜๊ณ  routing

import express from "express";
import passport from "passport";
import { generateAccessToken } from "../authentication/token";

const router = express.Router();

router.get(
	"/login",
	passport.authenticate("google", {
		session: false,
		scope: ["email", "profile"],
		prompt: "select_account",
	})
);

router.get("/logout", function(req, res, next) {
	req.logOut();
	res.redirect("/");
});

router.get(
	"/google/callback",
	passport.authenticate("google", {
		session: false,
	}),
	(req, res) => {
		const accessToken = generateAccessToken(req.user.oauthId);
		res.cookie("vaagle", accessToken);
		res.redirect("http://localhost:3002/");
	}
);
module.exports = router;
  • req.user๋กœ ์•ž์„œ ์ •์˜ํ•œ google strategy์—์„œ์˜ cb return ๊ฐ’์„ ์ฝ์–ด์˜ฌ ์ˆ˜ ์žˆ์Œ.
  • passport.authenticate์˜ session ์˜ต์…˜์„ ๋ช…์‹œ์ ์œผ๋กœ false๋กœ ์คŒ.
  • promt option์€ ๋กœ๊ทธ์ธ ๋ฆฌ๋‹ค์ด๋ ‰์…˜ ์‹œ ์ž๋™๋กœ๊ทธ์ธ์ด ์•„๋‹Œ ๋กœ๊ทธ์ธ ๊ณ„์ •์„ ์„ ํƒํ•  ์ˆ˜ ์žˆ๋Š” ์ฐฝ์„ ๋ถˆ๋Ÿฌ์˜ค๋„๋ก ์„ค์ •.

๊ตฌ๊ธ€ ๋กœ๊ทธ์ธ์„ ํ†ตํ•ด ์‚ฌ์šฉ์ž๊ฐ€ ์ธ์ฆ๋˜๋ฉด JWT๋ฅผ ์ƒ์„ฑ ํ›„ ํด๋ผ์ด์–ธํŠธ ์ฟ ํ‚ค์— ๋“ฑ๋ก์‹œํ‚จ๋‹ค. ์ด ํ›„ ํ† ํฐ์„ ๋ฐœ๊ธ‰๋ฐ›์€ ํด๋ผ์ด์–ธํŠธ๋“ค์„ passport jwt ์ „๋žต์„ ํ†ตํ•ด ํ† ํฐ ๊ฐ’์„ ๋ณตํ˜ธ์‹œํ‚ค๊ณ  ์œ ์ €๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์ธ์ฆ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.

import passport from "passport";
import passportJwt from "passport-jwt";
import loadConfig from "../config/configLoader";
import { findHostById } from "../../DB/queries/host";

export default (function() {
	const { tokenArgs } = loadConfig();
	const jwtOptions = {
		jwtFromRequest: passportJwt.ExtractJwt.fromAuthHeaderAsBearerToken(),
		secretOrKey: tokenArgs.secret,
		issuer: tokenArgs.issuer,
		audience: tokenArgs.audience,
	};
	passport.use(
		new passportJwt.Strategy(jwtOptions, async (payload, cb) => {
			try {
				const host = findHostById(payload.sub);
				if (host) {
					return cb(null, host, payload);
				}
				return cb();
			} catch (error) {}
		})
	);
})();
  • jwtFromRequest์€ ํด๋ผ์ด์–ธํŠธ ํ—ค๋”์— ๋‹ด๊ธด jwt ํ† ํฐ์„ ์˜๋ฏธ.
  • payload๋Š” ํ† ํฐ์„ JWT payload ๋ถ€๋ถ„์— ํ•ด๋‹น.

RefreshToken ??

๋งŒ์•ฝ RefreshToken์„ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด accessToken์€ ํด๋ผ์ด์–ธํŠธ inMemory์— ์ €์žฅํ•˜๊ณ  refreshToken์€ cookie์— ์ €์žฅํ•˜์—ฌ ์‚ฌ์šฉํ•˜๋„๋ก ํ•  ์˜ˆ์ •.

ํ”„๋กœ์ ํŠธ ์ ์šฉ

diagram

Clone this wiki locally