OAuth 학습하기

arrrrrr·2023년 3월 9일

OAuth 개념 알아보기

OAuth는 인증을 중개해주는 매커니즘이다. 이미 사용자 정보를 가지고 있는 웹 서비스(네이버, 카카오..)에서 사용자 인증을 대신해주고, 접근 권한에 대한 토큰을 발급해준다.

  • 예시 : 소셜 로그인 등
  • 이점 : 직접 정보를 노출하지 않기 때문에 더 안전하다.
    새로운 서비스라 신뢰할 수 없는 경우에 직접 정보를 제공하지 않고도 로그인이 가능하기 때문에 안전하다.

주체

  • 사용자 : Resource Owner → 정보 주인
  • 사용중인 서비스 : Resource Server, Authorization Server → 내 정보를 가지고 있는 서버
  • 새로운 서비스 : Application

인증 방식의 종류

  • Implicit Grant Type : 보통 잘 사용 안함
  • Authorization Code Grant Type : Implicit Grant Type 방식에서 Authorization Code 단계 추가로 안전성을 높임

    아래의 흐름 이해가 중요하다 🔥
  • Refresh Token Grant Type : 토큰을 통해 검증을 하는 방법이다.

장점

  • 간편하고 안전하게 새로운 서비스를 이용할 수 있다.
  • Application은 회원정보 관리에서 발생하는 유출의 위험 부담을 덜 수 있다.
  • 사용자는 원하는 정보만 선택하여 Application의 접근을 허용할 수 있다.

OAuth 2.0 실습하기

사전 세팅

  • GitHub에 내 앱 등록하기(참고)
    여기에서 작성하는 Authorization callback URL은 내 앱으로 돌아가기 위한 callback URL이다.
    (OAuth 메커니즘은 인증 과정이 끝난 후 리디렉션을 통해 다시 내 앱으로 이동하는 원리임)

소셜 로그인 로직 플로우 이해하기

  • 1 ~ 2 (Login.js)
export default function Login() {
    const CLIENT_ID = "GitHub App에서 발급한 Client ID";

    const loginRequestHandler = () => {
        return window.location.assign(
            `https://github.com/login/oauth/authorize?client_id=${CLIENT_ID}`
        );
    };
  • 4 ~ 5 (App.js)
function App() {
const [accessToken, setAccessToken] = useState("");

    const getAccessToken = (authorizationCode) => {
        axios
            .post("http://localhost:4000/callback", { authorizationCode })
            .then((res) => {
                setAccessToken(res.data.accessToken);
            });
}
  • 6 ~ 8 (callback.js)
module.exports = async (req, res) => {
  	// (6)
    try {
        const result = await axios({
            method: "post",
            url: `https://github.com/login/oauth/access_token`,
            headers: {
                accept: "application/json",
            },
            data: {
                client_id: CLIENT_ID,
                client_secret: CLIENT_SECRET,
                code: req.body.authorizationCode,
            },
        });
        const accessToken = result.data.access_token;
        // (7)
        return res.status(200).send({ accessToken });
    } catch (err) {
        // (8)
        return res.status(401).send({ message: "error" });
    }
};
  • 9 (App.js)
useEffect(() => {
        if (accessToken) {
            // (9)
            setIsLogin(true);
        }
    }, [accessToken]);
  • 10 (Mypage.js)
useEffect(() => {
        axios
            //(10)
            .post("http://localhost:4000/userInfo", { accessToken })
            .then((res) => {
               setGithubUser(res.data.githubUserData);
           		setServerResource(res.data.serverResource);
                setIsLoading(false);
            });
    }, []);
  • 11, 13 (userInfo.js)
module.exports = async (req, res) => {
    const { accessToken } = req.body;
    return (
        axios
            // (11)
            .get("https://api.github.com/user", {
                headers: {
                    Authorization: `token ${accessToken}`,
                },
            })
            .then((res) => res.data)
            .then((githubUserData) => {
                // (13)
                res.send({ githubUserData, serverResource });
            })
            .catch((e) => {
                res.sendStatus(403);
            })
    );
};

0개의 댓글