내가 굉장히 어려워 했던 기능 중 하나인 OAuth 인증을 기록하고자 한다. OAuth를 하기 위해 쿠키, 세션, JWT 등의 인증 방식을 배우고 토큰의 개념에 친숙해 진 후, OAuth에 도전하였다. 종류는 카카오, 페이스북, 구글 등 매우 다양한 플랫폼에서 제공하지만 나는 가장 많이 사용하는 Google 플랫폼을 결정 하였다.
OAuth의 정의는 다음과 같다.
OAuth
사용자들이 비밀번호를 제공하지 않고 다른 웹사이트 상의 자신들의 정보에 대해 접근 권한을 부여할 수 있는 수단이다.
이 기능 하나를 독학으로 구현하기 위해 많은 모험을 하였다. 구글링, 블로그, 공식문서, GPT 등 여기저기 살펴보며 기능을 구현하게 됐다. 여러 곳을 둘러보게 된 이유는 도저히 하나만의 글 또는 참고 문서 등으로 오류가 되게 많았고, 실행도 되지 않아 굉장히 피로한 모험이 되었다.
모험
구글링, 공식문서는 구현 코드를 학습하고, GPT로는 OAuth의 구현이 어떻게 흘러가는지 학습하였다.
내가 실력이 부족한 것도 있겠지만, 비교적 어려운 기능이기도 한 것 같다. 심지어 기능을 모두 구현한 후에도 내 기억이 완전히 뒤죽박죽이다. 따라서 이 글을 통해 차근차근 정리해보면 좋을 것 같다.
이 글을 보는 주니어 개발자들 또한 내 글만으로 완벽히 구현이 안될 수 있다. (내가 여러 참고 문서를 보면서 그랬듯이) 따라서 다양한 곳에서 레퍼런스를 얻고 잘 이해하길 바란다.
먼저, 구글에서 인증을 어떤 과정으로 대신 해주는지 알 필요가 있다. 구글 OAuth를 사용했을 때, 구글에서 해주는 기본적인 것은 다음과 같다.
{개발자가 설정한 도메인}/?code={code} 라는 URL로 리다이렉트 해준다.※ 응답받는 구글 계정 정보는 이메일 주소, 이름 등이 포함되며, 당연히 비밀번호 같은건 담겨있지 않는다. 이 모든 것은 구글 라이브러리 또는 api로 다 제공 된다.
여기까지가 딱 Google OAuth를 사용하는 범위이다. 일반적인 로그인(OAuth 미사용)으로 따지자면 로그인과 패스워드를 입력하여 인증을 통해 회원가입 된 사용자 계정을 가져오는 것과 같다.
그러나, 구글 api를 통해 받은 계정 정보는 본인의 웹에서 필요한 정보 모두가 들어있는게 아니기 때문에, OAuth 회원가입 과정에서 구글 계정 정보 + 추가적인 정보를 붙혀서 사용자 DB에 추가해야 한다. 즉, 추가적인 정보를 붙히는 한 과정을 추가해야 하는 것이다.
코드를 구현하기에 앞서, 구글 콘솔에 클라이언트를 생성해야 한다.
해당 링크를 통해 구글 클라우드 콘솔로 이동 > API 및 서비스 > 사용자 인증 정보
사용자 인증 정보 만들기 > OAuth 클라이언트 ID
클라이언트 유형과 이름은 본인에게 맞는 것으로 설정한다.

만들기를 클릭하면 다음과 같이 OAuth 클라이언트가 생성 된다.

npm i axios @types/express google-auth-library
파일은 총 3개로 최대한 단순하게 구성하였다.
import express from "express";
import { googleOauth, googleOauthForm } from "googleOauth";
function server() {
const app = express();
// 구글 로그인 폼 응답
app.get("/form", (req, res) => {
const googleFormUrl = googleOauthForm();
res.status(200).send(googleFormUrl);
});
// 구글 계정 정보 응답
app.get("/login", async (req, res) => {
const { code } = req.query;
const googleData = await googleOauth(code as string);
res.status(200).json(googleData);
});
app.listen(5000, () => {
console.log(`http://localhost:5000`);
});
}
server();
import axios from "axios";
import { OAuth2Client } from "google-auth-library";
import keys from "./oauth2.keys.json";
const oAuth2Client = new OAuth2Client(
keys.installed.client_id,
keys.installed.client_secret,
keys.installed.redirect_uris[0]
);
export const googleOauthForm = () => {
const authorizeUrl = oAuth2Client.generateAuthUrl({
access_type: "offline",
scope: [
"https://www.googleapis.com/auth/userinfo.profile",
"https://www.googleapis.com/auth/userinfo.email",
],
});
return authorizeUrl;
};
export const googleOauth = async (googleCode: string): Promise<any> => {
const r = await oAuth2Client.getToken(googleCode);
oAuth2Client.setCredentials(r.tokens);
const googleApi = "https://www.googleapis.com/oauth2/v2/userinfo";
const googleUser = await axios.get(googleApi, {
headers: {
Authorization: `Bearer ${oAuth2Client.credentials.access_token}`,
},
});
return googleUser.data;
};
※ Typescript로 json파일 import하는 방법
// tsconfig.json { "compilerOptions": { "resolveJsonModule": true, } }
구글 콘솔에서 다음의 그림처럼 오른쪽 끝에 json형태의 key파일을 받을 수 있는 버튼이 있다.
다운받은 파일을 oauth2.keys.json으로 이름을 바꾸고 우리의 프로젝트로 가져온다. 그리고 redirect_uris만 ["http://localhost:5000/login"]으로 바꿔준다.
// oauth2.keys.json
{
"installed": {
"client_id": ...,
"project_id": ...,
"auth_uri": ...,
"token_uri": ...,
"auth_provider_x509_cert_url": ...,
"client_secret": ...,
"redirect_uris": ["http://localhost:5000/login"]
}
}
redirect_uris는 구글 로그인 폼 인증에 성공하면 열리게 될 URL을 나타낸다.
코드 구현은 이게 끝이다. 이제 실제로 실행해 보면서 잘 작동하는지 확인해보자.
먼저 local환경에서 서버를 실행시키고 http://localhost:5000/form 에 접속하도록 하자. 그러면 google 로그인 폼 url을 응답받게 된다.

해당 링크를 타고 가면 로그인 폼이 뜨는걸 볼 수 있다.

구글 로그인 인증에 성공하면 우리가 이전에 설정한 redirect_uris로 이동하게 된다. 추가로 code라는 쿼리 스트링이 같이 오는데 이 것을 갖고 구글 계정 api를 통해 계정 정보를 얻게 된다.
지금까지 google OAuth를 최대한 짧게 하여 구현해 보았다. 더 나아가 나의 사이드 프로젝트에 카카오 OAuth와 매직 링크까지 도입 한다면 퀄리티 있는 로그인 페이지가 될 것 같다.