소셜 로그인이란 OAuth2.0기반으로 사용자의 정보를 이용하여 다른 웹 사이트나 애플리케이션에 간편하게 로그인할 수 있도록 하는 기능

참고 : https://datatracker.ietf.org/doc/html/rfc6749#section-1.1


OAuth는 인가 계층(authorization layer)을 도입하고 클라이언트의 역할과 리소스 소유자의 역할을 분리함으로써 이러한 문제들을 해결합니다.
예를 들어, 최종 사용자(리소스 소유자)는 인쇄 서비스(클라이언트)에 자신의 사용자 이름과 비밀번호를 공유하지 않고도 사진 공유 서비스(리소스 서버)에 저장된 자신의 보호된 사진에 대한 접근 권한을 부여할 수 있습니다. 대신, 그녀는 사진 공유 서비스가 신뢰하는 서버(인가 서버)에 직접 인증하고, 이 서버는 인쇄 서비스에 위임 관련 특정 자격 증명(액세스 토큰)을 발급합니다.
이 명세는 HTTP([RFC2616])와 함께 사용하도록 설계되었습니다. HTTP 이외의 프로토콜을 통한 OAuth의 사용은 이 문서의 범위를 벗어납니다.
정보 문서로 발표된 OAuth 1.0 프로토콜([RFC5849])은 소규모의 임시 커뮤니티 노력의 결과물이었습니다. 이 표준 트랙 명세는 OAuth 1.0의 배포 경험뿐만 아니라, 더 넓은 IETF 커뮤니티로부터 수집된 추가적인 사용 사례 및 확장성 요구사항을 기반으로 합니다. OAuth 2.0 프로토콜은 OAuth 1.0과 하위 호환되지 않습니다. 두 버전은 네트워크 상에서 공존할 수 있으며, 구현체는 둘 다 지원하도록 선택할 수 있습니다. 그러나 이 명세의 의도는 새로운 구현이 이 문서에 명시된 대로 OAuth 2.0을 지원하고, OAuth 1.0은 기존 배포를 지원하기 위해서만 사용되도록 하는 것입니다. OAuth 2.0 프로토콜은 OAuth 1.0 프로토콜과 구현 세부 사항을 거의 공유하지 않습니다. OAuth 1.0에 익숙한 구현자는 이 문서의 구조와 세부 사항에 대한 어떠한 가정도 없이 접근해야 합니다.
사용자가 가게에서 어떤 물건을 구매하고자 한다. 사용자의 돈은 모두 은행에 있다.
이 상황에서 금액을 지불하기 위해 사용자가 자신의 “계좌번호”와 “비밀번호”를 달려주는 것은 최악이다.
가게 사장이 물건 값 이상의 비용을 출금할 수 있기 때문이다. 이를 방지하기 위해 사용자는 수표를 써주기로 한다.
안녕하세요! 이제 막 개발의 세계에 발을 들인 여러분을 위해, '인증'과 '인가'라는 복잡해 보이는 산을 함께 넘어보려 합니다. 그중에서도 현대 웹 서비스의 필수 기능인 OAuth 2.0에 대해 알아보겠습니다. RFC 6749 문서는 그 표준 명세지만, 처음 보면 외계어 같을 수 있죠. 제가 실제 '구글 소셜 로그인'이 어떻게 동작하는지 보여드리면서 쉽고 재미있게 풀어드리겠습니다.
옛날 옛적, '찍스타그램'이라는 사진 편집 앱이 있다고 상상해봅시다. 이 앱은 여러분의 구글 포토에 있는 사진을 가져와서 편집하고 싶어 합니다. 어떻게 해야 할까요?
이런 끔찍한 문제를 해결하기 위해 등장한 것이 바로 OAuth (Open Authorization) 입니다. OAuth는 "비밀번호를 직접 주지 않고, 특정 권한만 제한적으로 부여하는 똑똑한 위임 방식"이라고 할 수 있습니다. 마치 호텔 룸키처럼, 레스토랑이나 수영장은 이용할 수 있지만 다른 손님의 방은 열 수 없는 '제한된 키'를 발급해주는 것과 같습니다.
OAuth 2.0에는 4명의 주요 등장인물이 있습니다. 구글 로그인 예시와 함께 살펴보죠.
awesome-service.com)accounts.google.com)googleapis.com)💡 Tip: 많은 경우, 권한 서버와 자원 서버는 같은 회사(Google)에 의해 운영되지만, 역할은 명확히 구분됩니다.
OAuth 2.0의 핵심은 '토큰'이라는 특별한 열쇠를 주고받는 것입니다.
이제 모든 조각을 맞춰봅시다. OAuth 2.0의 가장 표준적이고 안전한 방식인 'Authorization Code Grant' 흐름을 통해 구글 소셜 로그인이 어떻게 이루어지는지 단계별로 살펴보겠습니다. (RFC 6749, Section 4.1)
나 (Resource Owner)는 awesome-service.com(Client)에서 "Google로 로그인하기" 버튼을 클릭합니다.
이 간단한 클릭이 모든 여정의 시작입니다!
awesome-service.com(Client)은 나를 Google 권한 서버로 보냅니다. 이때 그냥 보내는 게 아니라, 특별한 정보들을 담아서 보냅니다.
실제로는 브라우저가 아래와 같은 URL로 리디렉션됩니다.
https://accounts.google.com/o/oauth2/v2/auth? response_type=code& client_id=YOUR_CLIENT_ID.apps.googleusercontent.com& scope=openid%20profile%20email& redirect_uri=https://awesome-service.com/auth/google/callback& state=a_random_string_to_prevent_csrf
각 파라미터의 의미는 다음과 같습니다.
response_type=code: "나중에 인증 코드(Authorization Code)를 발급해주세요" 라는 의미입니다. 이게 바로 'Authorization Code Grant' 방식의 핵심입니다.client_id: awesome-service.com이 구글에 미리 등록하고 발급받은 고유 식별자입니다. "제가 바로 그 앱이에요!"라고 신분을 밝히는 것이죠. (RFC, Section 2.2)scope: 앱이 요청하는 권한의 범위입니다. 여기서는 'openid, profile, email' 정보에 접근하겠다고 요청하고 있습니다. (RFC, Section 3.3)redirect_uri: 구글이 인증 절차를 마친 후, 사용자를 다시 돌려보낼 주소입니다. (awesome-service.com의 특정 경로) 보안을 위해 이 주소는 구글에 미리 등록되어 있어야 합니다. (RFC, Section 3.1.2)state: CSRF(Cross-Site Request Forgery) 공격을 방지하기 위한 임의의 문자열입니다. 나중에 구글이 이 값을 그대로 돌려주면, awesome-service.com은 자기가 처음에 보낸 값이 맞는지 확인합니다. (RFC, Section 10.12)Google 권한 서버는 나에게 로그인 창을 보여줍니다. 로그인을 하면, "awesome-service.com이(가) 내 이름, 이메일 주소, 프로필 사진 등에 액세스하려고 합니다. 동의하시겠습니까?" 라는 동의 화면을 보여줍니다.
여기서 내가 "동의" 버튼을 누르면, 자원에 대한 접근을 허락하는 것입니다.
내가 동의하면, Google 권한 서버는 2단계에서 지정된 redirect_uri로 나를 다시 돌려보냅니다. 이때 주소 뒤에 아주 짧은 시간만 유효한 임시 인증 코드(code)를 붙여줍니다.
브라우저는 다음 주소로 리디렉션됩니다.
중요: 아직 액세스 토큰이 아닙니다! 이건 그저 액세스 토큰으로 교환할 수 있는 '교환권'일 뿐입니다. 이 교환권은 브라우저(사용자)를 통해 전달되므로 비교적 덜 안전한 채널을 거칩니다.
awesome-service.com의 백엔드 서버는 브라우저를 통해 전달받은 인증 코드와 자신의 Client Secret(구글에 등록할 때 받은 비밀키)을 가지고, Google 권한 서버의 토큰 엔드포인트(Token Endpoint)에 직접 요청을 보냅니다.
이 과정은 사용자의 브라우저를 거치지 않고, 서버 대 서버로 안전하게 통신합니다. (RFC, Section 4.1.3)
Bash
awesome-service.com 서버가 Google 토큰 서버에 보내는 요청 예시 (curl)curl --location --request POST 'https://oauth2.googleapis.com/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'code=A_TEMPORARY_AUTHORIZATION_CODE' \
--data-urlencode 'client_id=YOUR_CLIENT_ID.apps.googleusercontent.com' \
--data-urlencode 'client_secret=YOUR_CLIENT_SECRET' \
--data-urlencode 'redirect_uri=https://awesome-service.com/auth/google/callback' \
--data-urlencode 'grant_type=authorization_code'
grant_type=authorization_code: "제가 받아온 인증 코드를 드릴 테니, 액세스 토큰으로 바꿔주세요" 라는 의미입니다.Google 권한 서버는 인증 코드, client_id, client_secret 등이 모두 유효한지 확인하고, 마침내 액세스 토큰과 리프레시 토큰을 awesome-service.com 서버에게 발급해줍니다.
성공 시 awesome-service.com 서버가 받는 응답(JSON)입니다. (RFC, Section 5.1)
{
"access_token": "A_REAL_ACCESS_TOKEN_STRING",
"expires_in": 3599,
"refresh_token": "A_LONG_LIVED_REFRESH_TOKEN",
"scope": "openid https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email",
"token_type": "Bearer"
}
이제 awesome-service.com은 드디어 진짜 열쇠(액세스 토큰)를 손에 넣었습니다! 이 토큰들은 서버의 데이터베이스에 안전하게 저장됩니다.
awesome-service.com 서버는 발급받은 액세스 토큰을 이용해 Google 자원 서버(API 서버)에 내 프로필 정보를 요청합니다.
awesome-service.com 서버가 Google API 서버에 보내는 요청 예시curl --location --request GET 'https://www.googleapis.com/oauth2/v2/userinfo' \
--header 'Authorization: Bearer A_REAL_ACCESS_TOKEN_STRING'`
Authorization: Bearer ...: HTTP 요청 헤더에 "이 Bearer(소지자) 토큰을 가지고 있으니 권한을 확인해주세요" 라는 의미로 액세스 토큰을 담아 보냅니다. (RFC, Section 7)Google 자원 서버는 액세스 토큰이 유효한지 확인하고, awesome-service.com 서버에게 내 프로필 정보(이름, 이메일 등)를 보내줍니다.
이제 awesome-service.com은 내 정보를 받았으므로, 이 정보를 바탕으로 회원가입을 시키거나 로그인을 완료하고 서비스를 제공할 수 있게 됩니다.
복잡해 보이지만 핵심은 간단합니다.
이것이 바로 OAuth 2.0이 우리의 소중한 정보를 안전하게 지키면서도 편리한 소셜 로그인을 가능하게 하는 원리입니다. 이 흐름을 잘 이해하신다면, 앞으로 API 문서를 보거나 인증 관련 기능을 구현할 때 훨씬 더 자신감을 가질 수 있을 겁니다. 화이팅입니다! 🚀