BACKEND / SECURITY / OAUTH2 • 2026. 05. 02

Google OAuth 2.0 완벽 가이드:
개인화를 향한 첫걸음

안녕하세요, eleslog입니다. eleslog.work를 운영하며 가장 많이 받은 질문 중 하나는 "어떻게 하면 사용자의 데이터를 안전하게 보관하면서도 로그인을 편하게 만들 수 있을까?"였습니다. 그 해답은 바로 전 세계 웹 서비스의 표준과도 같은 OAuth 2.0에 있습니다.

이번 포스팅에서는 라이브러리의 도움 없이 순수하게 원리를 파헤치며, 구글 소셜 로그인을 우리 서비스에 이식하는 과정을 아주 상세하게 다뤄보겠습니다. 양이 다소 많지만, 끝까지 읽으시면 소셜 로그인에 대한 막연한 두려움이 사라지실 겁니다.

1. OAuth 2.0: 신뢰를 위임하는 기술

우리가 직접 사용자의 비밀번호를 데이터베이스에 저장하는 방식(전통적인 방식)은 위험합니다. 데이터가 유출될 경우 모든 책임이 운영자에게 돌아오기 때문이죠. 반면 OAuth 2.0은 "인증(Authentication)"과 "인가(Authorization)"를 구분합니다.

인증 vs 인가, 헷갈리지 마세요!
- 인증 (Authentication): "너 누구니?"를 확인하는 절차입니다. (구글 로그인 화면)
- 인가 (Authorization): "너 이 방에 들어올 자격이 있니?"를 확인하는 절차입니다. (구글이 주는 Access Token)

OAuth 2.0을 사용하면 구글이 인증을 대신해주고, 우리 사이트에는 특정 정보에 접근할 수 있는 권한인 인가 증명서를 넘겨줍니다. 이 과정이 어떻게 유기적으로 연결되는지 상세히 살펴봅시다.

2. 구글 API 콘솔에서 서비스 등록하기

코드를 짜기 전, 구글에게 "나 이런 사이트 운영할 건데 허가해줘"라고 요청해야 합니다. Google Cloud Console에서 프로젝트를 생성하고 'OAuth 동의 화면'을 구성하세요.

01 승인된 리디렉션 URI (Redirect URI): 가장 중요한 설정입니다. 구글이 인증을 마친 사용자를 다시 보낼 주소입니다. 보안을 위해 https 주소만 허용되며, 개발 단계에서는 http://localhost도 가능합니다.
02 Client ID & Secret: 우리 서비스의 '신분증'입니다. Secret은 절대 외부(GitHub 등)에 노출되지 않도록 .env 파일로 관리해야 합니다.

3. 백엔드 구현: 마법이 일어나는 4단계 Flow

1단계: 인증 URL 생성 및 사용자 리다이렉트

사용자가 로그인 버튼을 누르면, 우리는 구글의 인증 서버로 사용자를 보냅니다. 이때 단순히 보내는 게 아니라 어떤 정보가 필요한지를 쿼리스트링에 담아야 합니다.


const GOOGLE_AUTH_URL = "https://accounts.google.com/o/oauth2/v2/auth";

app.get('/auth/google', (req, res) => {
    const params = new URLSearchParams({
        client_id: process.env.GOOGLE_CLIENT_ID,
        redirect_uri: process.env.GOOGLE_REDIRECT_URI,
        response_type: "code", // 우리는 코드를 먼저 받을 거야!
        scope: "openid email profile", // 필요한 권한 목록
        access_type: "offline", // 나중에 재발급 토큰(Refresh)을 받으려면 필수
        state: "random_security_string" // 보안을 위한 암호값
    });
    res.redirect(`${GOOGLE_AUTH_URL}?${params.toString()}`);
});
        

2단계: 콜백 처리와 '인가 코드' 수신

구글 로그인이 끝나면 구글은 사용자를 우리 서버의 /auth/google/callback 주소로 돌려보냅니다. 이때 URL 끝에 ?code=4/0Af... 처럼 아주 긴 코드가 붙어 있습니다. 하지만 주의하세요! 이 코드는 아직 사용자 정보가 아닙니다. 정보를 얻기 위한 일시적인 교환권일 뿐입니다.

3단계: Token 교환 (The Real Deal)

이제 서버 대 서버로 구글에게 다시 요청을 보냅니다. "방금 사용자가 나한테 이 코드를 줬어. 이거 확인해보고 진짜면 정보를 가져올 수 있는 토큰(Access Token)으로 바꿔줘!"


const response = await axios.post('https://oauth2.googleapis.com/token', {
    code: receivedCode,
    client_id: process.env.GOOGLE_CLIENT_ID,
    client_secret: process.env.GOOGLE_CLIENT_SECRET,
    redirect_uri: process.env.GOOGLE_REDIRECT_URI,
    grant_type: 'authorization_code',
});

const { access_token, id_token } = response.data;
        

4단계: 사용자 정보 획득 및 서비스 가입

획득한 access_token을 사용해 구글 유저 정보 API를 호출합니다. 여기서 얻은 이메일과 고유 ID(sub)를 우리 DB에 대조해봅니다. 이미 있는 회원이면 로그인 처리를, 처음 온 분이라면 회원가입을 시켜드리면 됩니다.

4. 실무급 보안: CSRF와 state 파라미터

많은 개발자가 간과하는 것이 state 값입니다. 만약 해커가 로그인을 시작하는 요청을 낚아채서 자신의 인증 코드를 일반 사용자에게 밀어넣는다면? 이를 로그인 CSRF 공격이라고 합니다.

이를 막기 위해 로그인을 시작할 때 서버 세션에 랜덤한 문자열(state)을 저장하고 구글로 보냅니다. 구글은 이 값을 그대로 돌려주는데, 콜백 함수에서 세션의 값과 구글이 준 값이 일치하는지 반드시 확인해야 합니다. 불일치한다면 누군가 중간에 요청을 조작한 것입니다.

5. Refresh Token: 끊기지 않는 연결고리

Access Token은 보통 1시간이면 만료됩니다. 사용자가 1시간마다 다시 로그인하게 만들 순 없겠죠? 이때 필요한 것이 Refresh Token입니다. 처음 로그인할 때 한 번 발급받아 우리 DB에 안전하게 보관해두면, Access Token이 만료될 때마다 구글에게 "이 사람 예전에 허락받았으니까 새 토큰 좀 줘"라고 요청할 수 있습니다.

마스터의 팁:
Refresh Token은 사용자가 '내 계정 연결 끊기'를 하기 전까지 유효하므로, 보안 강도가 매우 높아야 합니다. 데이터베이스에 저장할 때 반드시 암호화하여 저장하세요.

마치며: eleslog.work가 나아갈 방향

소셜 로그인은 단순히 '편리함'을 넘어, 사용자에게 **"이 서비스는 내 데이터를 소중히 다루고 있구나"**라는 신뢰를 주는 첫인상입니다. eleslog.work의 모든 실시간 프로젝트(채팅, 플래너 등)는 이제 이 견고한 기반 위에서 더욱 풍성해질 것입니다.

다음 포스팅에서는 로그인한 사용자의 정보를 어떻게 하면 Redis를 활용해 초고속으로 조회할 수 있는지, 캐싱 전략에 대해 깊이 있게 다뤄보겠습니다. 긴 글 읽어주셔서 감사합니다!