구글·카카오 로그인은 실제로 어떻게 동작할까? 쿠키·세션부터 OIDC까지
회사에서 여러 플랫폼을 하나로 합쳐 웹 SSO 를 만드는 테스크를 진행하였다. 그 과정에서 웹에서 SSO 기술 분석을 하는 과정에서 "구글로 로그인" 버튼 하나 뒤에 얼마나 많은 약속이 숨어 있는지 처음부터 다시 뜯어보게 됐다. 막상 열어 보니 소셜 로그인은 특별한 마법이 아니라, 쿠키와 세션이라는 오래된 개념 위에 표준 프로토콜 하나를 얹은 구조였다.
이 글은 그 구조를 최대한 쉬운 말로 정리한 것이다. 소셜 로그인을 직접 붙여 본 적이 있어도 "안에서 정확히 무슨 일이 일어나는지"는 흐릿한 경우가 많은데, 이 글을 읽고 나면 그 흐름이 눈에 그려졌으면 한다. 다음 글에서 다룰 Keycloak SSO도 결국 여기서 설명하는 원리를 그대로 따라간다.
HTTP는 왜 로그인 상태를 기억하지 못할까 — 쿠키와 세션
웹의 기본 통신 규약인 HTTP는 상태를 저장하지 않는으며 이를 "Stateless(무상태)"라고 부른다.
서버 입장에서는 방금 로그인한 사람과 1초 뒤에 새 페이지를 요청한 사람이 같은 사람인지 알 방법이 없다는 것이다. 서버는 요청이 하나 들어오면 처리하고, 응답을 보내고, 그걸로 끝이다. 다음 요청이 오면 다시 처음 보는 손님처럼 대한다. 기억력이 3초짜리 금붕어라고 생각하면 편하다. 이 상태 그대로라면 우리는 페이지를 넘길 때마다 아이디와 비밀번호를 다시 입력해야 한다.
그래서 "이 사람은 아까 로그인한 그 사람"이라는 걸 이어서 기억할 장치가 필요하다. 그 장치가 바로 세션(Session)과 쿠키(Cookie)다. 이 둘은 짝을 이뤄서 동작한다. 하나는 서버가 사용자를 기억하는 방법이고, 다른 하나는 그 기억을 이어 주는 연결 고리다.
세션 — 서버가 사용자를 기억하는 방법
사용자가 아이디와 비밀번호로 로그인에 성공하면, 서버는 그 사람을 위한 메모장을 하나 만든다. 이게 세션이다. 이 메모장에는 "누구인지, 언제 로그인했는지, 언제까지 유효한지" 같은 정보가 적힌다. 로그인 시각과 만료 시각이 함께 적히는 이유는, 일정 시간이 지나면 자동으로 로그아웃시키기 위해서다. 은행 사이트가 잠깐 자리를 비우면 다시 로그인하라고 하는 게 바로 이 만료 시각 때문이다.
그리고 이 메모장에는 다른 사람 것과 겹치지 않는 고유한 번호표가 붙는다. 이걸 세션 ID라고 한다. 예를 들어 abc123 같은 값이다. 서버는 이 메모장을 자기 메모리나 Redis 같은 저장소에 보관해 둔다. 서버가 여러 대로 늘어나는 서비스에서는 메모리 대신 Redis 같은 공용 저장소에 두는 경우가 많다. 어느 서버로 요청이 들어와도 같은 세션을 찾을 수 있어야 하기 때문이다. 어쨌든 핵심은, 진짜 사용자 정보는 서버 안에 있고 밖으로 나가는 건 번호표뿐이라는 점이다.
쿠키 — 세션 ID를 브라우저에 맡기는 방법
문제는 이 번호표를 어떻게 사용자에게 전달하느냐다. 서버는 로그인에 성공한 순간, 응답 헤더에 Set-Cookie라는 항목을 실어서 세션 ID를 브라우저에게 건넨다. "이 번호표 잘 갖고 있다가 다음에 올 때 보여 주세요"라고 부탁하는 셈이다.
브라우저는 이 번호표(쿠키)를 저장해 두고, 같은 도메인에 요청을 보낼 때마다 알아서 함께 실어 보낸다. 우리가 따로 코드를 짜지 않아도 브라우저가 자동으로 해 준다. 그래서 서버는 요청에 들어 있는 세션 ID만 보고 "아, 아까 그 사람이구나" 하고 알아챈다. 참고로 이 세션 쿠키에는 보통 자바스크립트가 함부로 읽지 못하게 막는 HttpOnly, 그리고 HTTPS 연결에서만 전송되게 하는 Secure 같은 옵션을 걸어 둔다. 번호표가 중간에 새어 나가지 않도록 하는 최소한의 잠금장치라고 보면 된다. 전체 흐름을 표로 정리하면 이렇다.
| 단계 | 방향 | 하는 일 |
|---|---|---|
| 1 | 사용자 → 서버 | 로그인 요청 (아이디 / 비밀번호 전송) |
| 2 | 서버 내부 | 인증 성공 → 세션 생성 (세션 ID: abc123) |
| 3 | 서버 → 브라우저 | 응답 헤더에 Set-Cookie: SESSIONID=abc123 포함 |
| 4 | 브라우저 → 서버 | 이후 모든 요청에 Cookie: SESSIONID=abc123 자동 포함 |
| 5 | 서버 내부 | 세션 ID로 사용자 확인 → 로그인 상태 유지 |
여기서 꼭 기억할 점이 하나 있다. 쿠키는 "같은 도메인"에만 자동으로 따라간다. myapp.com에서 받은 쿠키는 myapp.com에 요청할 때만 붙고, 다른 도메인에는 붙지 않는다. 보안을 위해 브라우저가 그렇게 막아 두었다. 만약 아무 도메인에나 쿠키가 따라간다면, 악성 사이트가 내 로그인 정보를 훔쳐 갈 수 있기 때문이다. 이 단순해 보이는 규칙이 뒤에서 설명할 SSO(한 번 로그인으로 여러 서비스 이용)의 열쇠가 된다. 왜 그런지는 바로 다음 단락에서 이어진다.
한 번 로그인하면 끝 — SSO는 세션을 어디에 두나
SSO(Single Sign-On)는 말 그대로 한 번만 로그인하면 여러 서비스를 오갈 수 있는 방식이다. aaa.pro에서 로그인하면 bbb.com, ccc.com에서도 다시 로그인하지 않고 바로 들어가지는 것이다. 이게 어떻게 가능한지 이해하려면, 로그인 정보를 누가 들고 있는지를 봐야 한다.
핵심은 이렇다. 각 서비스가 로그인 자체를 직접 처리하는 게 아니라, 인증만 전담하는 서버 한 곳을 두고 그곳을 믿는 것이다. 이 전담 서버를 신원 제공자, 영어로 Identity Provider(줄여서 IdP)라고 부른다. 각 서비스는 "이 사람 로그인한 사람 맞아?"를 스스로 비밀번호를 받아 확인하지 않고, IdP의 인증 결과를 믿기로 미리 약속(신뢰 관계)해 둔다. 그래서 IdP가 "이 사람 맞다"고 하면 서비스는 그 말을 그대로 받아들인다. 덕분에 각 서비스는 로그인 화면이나 비밀번호 검증 로직을 직접 갖지 않아도 된다.
여기서 흔한 오해를 하나 풀고 가자. "IdP가 세션을 들고 있으니 각 서비스에는 세션이 없다"고 생각하기 쉬운데, 실제로는 세션이 두 겹으로 존재한다. IdP는 IdP대로 자기 로그인 세션을 갖고, 각 서비스도 로그인이 끝나면 자기 세션(또는 토큰)을 따로 만든다. 차이는 '최초 확인'에 있다. 각 서비스는 사용자가 처음 왔을 때 비밀번호를 직접 검증하는 대신 IdP에게 확인을 맡기고, 그다음부터는 자기 세션으로 사용자를 관리한다. 그러니까 IdP가 들고 있는 건 '한 번만 로그인하면 여러 서비스를 오갈 수 있게 해 주는 중앙 세션'이고, 각 서비스의 세션은 그것과 별개로 따로 존재한다. 이 구분을 잡아 두면 뒤에 나올 이야기가 훨씬 정확하게 읽힌다.
첫 번째 로그인 — 서비스 A에 처음 들어갈 때
사용자가 서비스 A에 처음 접속하는 상황을 따라가 보자.
- 사용자 → 서비스 A: 서비스 A에 접속한다. 아직 로그인한 적이 없으니 인증이 필요하다.
- 서비스 A → IdP: 서비스 A가 "로그인은 저쪽에서 하세요" 하며 브라우저를 IdP로 보낸다.
- IdP 내부: IdP가 로그인 화면을 띄우고, 사용자가 아이디와 비밀번호를 입력해 인증을 마친다.
- IdP → 브라우저: IdP가 자기만의 세션을 만들고, 그 번호표를
Set-Cookie로 브라우저에 심는다. 이때 쿠키의 도메인은 IdP 도메인(예:idp.example.com)이다. - IdP → 서비스 A: 다시 서비스 A로 돌려보내면 로그인이 끝난다.
여기서 4번이 중요하다. 로그인 세션이 서비스 A가 아니라 IdP 쪽에 생겼다는 점이다. 이 차이가 다음 장면에서 전부를 결정한다.
두 번째 접속 — 서비스 B에 갈 때 (SSO의 핵심)
이제 같은 사용자가 서비스 B에 처음 접속한다.
- 사용자 → 서비스 B: 서비스 B에 접속한다. 서비스 B 입장에선 처음 보는 사람이라 인증이 필요하다.
- 서비스 B → IdP: 서비스 B도 브라우저를 IdP로 보낸다.
- 브라우저 → IdP: 여기서 마법이 일어난다. 브라우저는 IdP 도메인으로 요청을 보내는 것이므로, 아까 4번에서 받아 둔 IdP 쿠키를 자동으로 함께 보낸다.
- IdP 내부: IdP가 그 쿠키에 담긴 세션을 확인한다. "어, 이 사람 아까 로그인했네." 이미 인증된 사용자다.
- IdP → 서비스 B: 로그인 화면을 다시 띄울 필요 없이 곧바로 서비스 B로 돌려보낸다. 사용자 눈에는 자동 로그인처럼 보인다.
사용자 입장에서는 서비스 B의 주소를 눌렀을 뿐인데, 화면이 잠깐 깜빡하더니 이미 로그인된 상태로 들어가진다. 그 짧은 깜빡임 사이에 위의 7~10번이 전부 일어난 것이다. 정리하면, 브라우저가 같은 도메인(IdP)에 요청할 때 쿠키를 자동으로 실어 보내는 성질, 그리고 IdP가 자기 세션을 계속 들고 있다는 점. 이 두 가지가 맞물려서 SSO가 성립한다. IdP의 쿠키와 세션이 살아 있는 한, 사용자는 처음 한 번만 로그인하면 된다.
반대로 로그아웃도 한 곳에서 관리할 수 있다. IdP의 세션을 끊어 버리면 연결된 모든 서비스에서 함께 로그아웃되는데, 이걸 통합 로그아웃이라고 부른다. 보안 사고가 의심될 때 특정 사용자를 모든 서비스에서 한 번에 로그아웃시킬 수 있다는 점은, 인증을 한 곳에 모았을 때 얻는 큰 이점이다. 만약 서비스마다 세션이 흩어져 있었다면, 한 명을 로그아웃시키려고 서비스 세 곳을 각각 손봐야 했을 것이다. 이게 SSO의 본질이다. 어떤 대단한 신기술이 아니라, 앞에서 배운 쿠키·세션의 성질을 인증 전담 서버 한 곳에 몰아넣은 것뿐이다.
OAuth 2.0과 OIDC는 뭐가 다를까 — 열쇠와 신분증
쿠키·세션으로 "로그인 상태를 어떻게 이어 가는지"는 알았다. 그런데 소셜 로그인에는 한 가지가 더 필요하다. 내 서비스가 구글에게 "이 사람 정보 좀 줘"라고 안전하게 물어보는 규칙이다. 여기서 OAuth 2.0과 OIDC라는 두 이름이 등장한다. 자주 헷갈리는데, 역할이 분명히 다르다.
OAuth 2.0 — "이거 해도 돼?"를 다루는 인가 프로토콜
OAuth 2.0은 인가(Authorization) 프로토콜이다. 쉽게 말하면 "이 앱이 이 사용자의 무언가에 접근해도 되나요?"라는 허락을 다룬다. 예를 들어 "이 앱이 내 구글 드라이브 파일을 읽어도 되나요?" 같은 상황이다. 사용자가 동의하면, 그 앱은 접근 권한을 담은 Access Token(액세스 토큰)을 받는다. OAuth 2.0의 결과물이 바로 이 토큰이다. 이 토큰은 "이 문을 열어도 된다"는 출입증에 가깝다.
그런데 OAuth 2.0만으로는 답하지 못하는 질문이 있다. "그래서 이 사람이 누구인데?"라는 질문이다. 비유하자면 발렛파킹 요원에게 발렛 키를 건네는 것과 같다. 그 키로 차 문을 열고 시동을 걸 수는 있지만(권한), 정작 그 키를 든 사람이 누구인지는 키만 봐서는 알 수 없다. 키에는 이름표가 붙어 있지 않으니까. 즉 OAuth 2.0은 "무엇을 해도 되는가"는 알려 주지만 "누구인가"는 알려 주지 않는다.
그래서 OIDC가 없던 시절에는, 그리고 지금도 OIDC를 지원하지 않는 서비스에서는, 개발자들이 조금 돌아가는 방법을 쓴다.
- 일단 Access Token을 받는다.
- 그 토큰으로 소셜 플랫폼의 프로필 API(
GET /user같은 것)를 호출한다. - 응답으로 온 프로필 정보(JSON)를 보고 "아, 이 사람이구나" 하고 식별한다.
권한을 얻은 다음, 그 권한을 이용해 신원을 거꾸로 알아내는 방식이다. 동작은 하지만 표준이 아니라서 플랫폼마다 API 주소도, 응답 형식도 제각각이다. 여기서 짚을 게 있다. 이건 단순히 옛날이야기가 아니다. 지금도 OIDC를 지원하지 않는 GitHub 같은 서비스는 이 방식으로 로그인을 처리한다. 그러니 '과거의 방법'이라기보다 'OIDC를 지원하지 않는 곳의 방법'이라고 보는 게 정확하다. 소셜 로그인을 여러 개 붙여 본 사람이면 이렇게 제각각인 응답을 맞추느라 고생한 기억이 있을 것이다.
OIDC — "여기 신분증도 같이 드릴게요"
이 번거로움을 정리하려고 2014년, OAuth 2.0 위에 얇은 신원 확인 층을 하나 더 올렸다. 그게 바로 OIDC(OpenID Connect)다.
OIDC를 적용하면 인증 서버의 응답이 달라진다. 이전에는 "여기 열쇠(Access Token) 받으세요"가 전부였다면, 이제는 "열쇠 받으시고, 이 사람이 누구인지 증명하는 신분증(ID Token)도 같이 드릴게요"가 된다. 출입증에 더해 신분증을 함께 주는 셈이다.
이 신분증이 바로 ID Token이고, JWT라는 형식으로 되어 있다. 개발자는 별도 API를 호출해 "너 누구야?"라고 다시 물어볼 필요 없이, 함께 배달된 ID Token 하나로 사용자 정보를 확인할 수 있다. 그 안에 사용자 정보가 표준화된 항목으로 들어 있기 때문이다. 대표적으로 sub(사용자 고유 번호), iss(발급한 곳), email, name 같은 값이다. 플랫폼이 달라도 항목 이름이 같으니 훨씬 다루기 편하다. 아까처럼 플랫폼마다 응답을 따로 맞출 필요가 없어진 것이다.
여기서 초보 때 흔히 하는 실수를 하나 짚고 가자. ID Token은 그냥 열어 본다고 끝이 아니다. JWT는 누구나 내용을 들여다볼 수 있는 형식이라, 열어 보기(디코딩)만 하고 "확인 끝"이라고 여기면 위험하다. 실제 서비스에서는 이 토큰을 쓰기 전에 반드시 검증을 거쳐야 한다. 진짜 그 인증 서버가 발급한 게 맞는지(서명 검증), 나에게 발급된 게 맞는지(aud), 믿을 수 있는 발급처인지(iss), 아직 유효기간이 남았는지(exp)를 확인한 뒤에야 안에 든 정보를 믿고 쓸 수 있다. 디코딩이 봉투를 뜯는 일이라면, 검증은 그게 위조가 아닌 진짜 문서인지 확인하는 일이다. 이 둘은 전혀 다르다.
여기서 두 토큰의 쓰임을 헷갈리지 않는 게 중요하다. ID Token은 "이 사람이 누구인지" 확인하는 신분증이고, Access Token은 "무언가에 접근할 때" 내미는 출입증이다. 로그인 처리에는 ID Token을 쓰고, 이후 자원 접근에는 Access Token을 쓴다. 신분증을 출입증 대신 쓰거나 그 반대로 쓰면 안 된다는 뜻이다. 이 구분만 잡아 두어도 소셜 로그인 코드를 읽을 때 훨씬 덜 헷갈린다. 한 문장으로 요약하면, 지금 소셜 로그인을 붙이고 있다면 사실은 OAuth 2.0 문법을 쓰는 OIDC를 구현하고 있는 것이다. 많은 사람이 "OAuth로 로그인 붙였다"고 말하지만, 로그인(신원 확인)까지 하고 있다면 그건 정확히는 OIDC다.
소셜 로그인의 진짜 흐름 — Authorization Code Flow 5단계
구글, 카카오, 네이버 로그인은 모두 OIDC와 OAuth 2.0의 Authorization Code Flow(인가 코드 방식)를 기반으로 동작한다. 여러 방식 중 가장 안전한 표준이고, 백엔드 서버가 있는 서비스에 권장되는 방식이다. 이름은 거창하지만, 앞에서 본 개념들이 순서대로 엮이는 것뿐이다. 다섯 단계로 나눠 보자.
1단계 — 인가 요청
사용자가 "구글로 로그인" 버튼을 누르면, 서비스는 브라우저를 구글의 인가 엔드포인트로 보낸다.
GET https://accounts.google.com/o/oauth2/v2/auth?
response_type=code
&client_id=my-app-client-id
&redirect_uri=https://myapp.com/callback
&scope=openid email profile
&state=random-csrf-token
response_type=code: 인가 코드를 달라는 뜻이다.scope=openid: OIDC를 쓰겠다고 명시하는 부분이다. 이 값이 있으면 신분증(ID Token)까지 받겠다는 신호다. OAuth와 OIDC가 갈라지는 지점이 바로 여기다. 뒤에 붙은email profile은 이메일과 기본 프로필도 함께 달라는 요청이다.state: 요청을 위조하는 CSRF 공격을 막기 위한 무작위 값이다. 나중에 응답으로 돌아온 값과 비교해서 내가 보낸 요청이 맞는지 확인한다.
2단계 — 사용자 인증
구글이 로그인 화면을 띄우고, 사용자가 아이디와 비밀번호를 넣은 뒤 권한에 동의한다. 이 과정은 전부 구글 도메인에서 일어난다. 그래서 내 서비스는 사용자의 비밀번호를 절대 보지 못한다. 이게 소셜 로그인이 안전한 첫 번째 이유다. 비밀번호는 오직 구글만 다루고, 우리 서비스는 "구글이 확인해 준 결과"만 넘겨받는다.
3단계 — 인가 코드 전달
인증에 성공하면 구글은 미리 등록해 둔 redirect_uri로 인가 코드(code)를 돌려보낸다.
GET https://myapp.com/callback?code=4/0AX4XfWh...&state=random-csrf-token
이 코드는 일회용이고 수명이 아주 짧다. 그리고 설령 이 코드가 중간에 유출되더라도, 코드만으로는 사용자 정보를 알아낼 수 없다. 진짜 정보를 얻으려면 다음 단계가 하나 더 필요하기 때문이다. 이때 함께 돌아온 state 값이 1단계에서 보낸 값과 같은지도 확인한다. 다르면 위조된 요청으로 보고 거부한다.
4단계 — 토큰 교환 (백채널)
이제 서비스의 백엔드 서버가 이 코드를 들고 구글의 토큰 엔드포인트에 토큰을 요청한다. 이 통신은 브라우저를 거치지 않고 서버끼리 직접 주고받는다. 이런 서버 간 통신을 백채널(back-channel)이라고 부른다. 브라우저에 노출되지 않으니 그만큼 안전하다.
POST https://oauth2.googleapis.com/token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code=4/0AX4XfWh...
&client_id=my-app-client-id
&client_secret=my-app-secret
&redirect_uri=https://myapp.com/callback
응답은 이렇게 온다.
{
"access_token": "ya29.a0AfH6SM...",
"id_token": "eyJhbGciOiJSUzI1NiIs...",
"refresh_token": "1//0eXx...",
"token_type": "Bearer",
"expires_in": 3600
}
여기서 핵심 장치 중 하나가 client_secret이다. 이 비밀 값은 백엔드 서버에만 있고 브라우저에는 절대 나가지 않는다. 그래서 3단계에서 인가 코드가 탈취되더라도, client_secret이 없으면 토큰으로 바꿀 수 없다. 코드 한 조각만으로는 아무것도 못 하게 막아 둔 것이다.
다만 client_secret 하나만으로 안전해지는 건 아니다. HTTPS 통신, 일회용인 인가 코드, 그리고 미리 등록해 둔 주소와 redirect_uri가 일치하는지 확인하는 절차 같은 장치들이 함께 맞물려서 안전을 만든다. 그리고 client_secret은 비밀을 안전하게 숨겨 둘 수 있는 백엔드 서버가 있을 때 이야기다. 비밀을 숨길 곳이 없는 브라우저 앱(SPA)이나 모바일 앱은 client_secret을 쓰지 않는 대신, PKCE라는 방식으로 같은 문제를 해결한다. 정리하면, 백엔드 서버가 있는 우리 같은 경우에는 client_secret이 코드 탈취에 대한 추가 보호막이 되어 준다.
참고로 토큰 응답에 refresh_token이 함께 오기도 한다. Access Token이 만료됐을 때 다시 로그인하지 않고 새 토큰을 받는 용도인데, 항상 주어지는 건 아니다. 예를 들어 구글은 access_type=offline 같은 옵션을 줬을 때만 발급한다. 그래서 "필요한 경우 함께 발급된다" 정도로 이해하면 된다.
5단계 — 사용자 식별과 세션 생성
토큰까지 받았으면 이제 사용자를 식별할 차례다. 상황이 두 가지로 나뉜다.
ID Token이 함께 온 경우 (OIDC 표준)
구글, 카카오처럼 OIDC를 지원하는 곳은 토큰 응답에 ID Token(JWT)을 함께 준다. 이 토큰을 검증한 뒤 열어 보면 추가 API 호출 없이 사용자 정보를 확인할 수 있다(앞에서 말한 서명·iss·aud·exp 검증이 먼저다).
{
"iss": "https://accounts.google.com",
"sub": "1104236838...",
"aud": "my-app-client-id",
"email": "user@gmail.com",
"name": "홍길동",
"picture": "https://lh3.googleusercontent.com/...",
"exp": 1713520800
}
ID Token이 없는 경우 (순수 OAuth 2.0만 지원)
OIDC를 지원하지 않는 플랫폼이라면, Access Token을 그 플랫폼의 UserInfo 엔드포인트에 보내서 정보를 받아 와야 한다. 앞에서 이야기한 "OIDC 이전의 돌아가는 방법"과 똑같은 패턴이다.
GET https://www.googleapis.com/oauth2/v3/userinfo
Authorization: Bearer ya29.a0AfH6SM...
{
"sub": "1104236838...",
"name": "홍길동",
"email": "user@gmail.com",
"email_verified": true,
"picture": "https://lh3.googleusercontent.com/..."
}
정리하면, ID Token이 있으면 그걸 쓰고 없으면 Access Token으로 UserInfo를 호출한다. 구글과 카카오는 OIDC를 지원하고, 네이버도 OIDC를 쓸 수 있다. 다만 네이버는 기본이 OAuth 2.0 방식이라 OIDC를 옵션으로 켜서 써야 한다. 그래서 OIDC를 지원하는 곳에서는 ID Token을 쓰는 게 표준이라고 보면 된다.
여기까지 오면 서비스가 할 일이 남는다. 이렇게 받은 이메일 같은 정보를 가지고 자체 데이터베이스에서 사용자를 찾고, 없으면 가입시키고, 서비스 접근 권한을 주고, 앞에서 배운 자체 세션이나 토큰을 발급한다. 이 뒷부분은 표준이 정해 주지 않는, 각 서비스가 직접 짜야 하는 비즈니스 로직이다.
여기까지의 뼈대 정리
길게 왔지만 구조는 단순하다. HTTP는 상태를 기억하지 못하니 세션으로 기억하고, 그 세션의 번호표를 쿠키로 주고받는다. 인증만 전담하는 IdP 한 곳에 세션을 몰아 두면 한 번 로그인으로 여러 서비스를 오갈 수 있고(SSO), 그 서비스끼리 신원을 안전하게 주고받는 규칙이 OAuth 2.0 위에 신원 층을 얹은 OIDC다. 그리고 실제 흐름은 인가 요청 → 사용자 인증 → 인가 코드 → 토큰 교환 → 사용자 식별의 5단계로 돈다. 이 원리를 이해하면 구글을 붙이든 카카오를 붙이든 큰 그림은 똑같다는 게 보인다. 결국 구글도 하나의 IdP일 뿐이고, 다음 글에서 다룰 Keycloak도 우리가 직접 운영하는 IdP라는 점만 다를 뿐 내부 원리는 거의 같다. 소셜 로그인의 원리가 곧 SSO의 원리이고, SSO를 우리 손으로 운영하는 도구가 Keycloak인 셈이다.
다음 글에서는 이 "구글의 역할"을 우리가 직접 운영하는 서버로 가져오는 이야기를 한다. 회사에서 여러 서비스의 로그인을 하나로 합치기 위해 Keycloak을 어떻게 골랐고, 왜 그게 소셜 로그인과 정확히 같은 원리인지 이어서 정리하겠다.
'인증 · 보안' 카테고리의 다른 글
| Keycloak SPI 정석 가이드 - 빌드·배포까지 (0) | 2026.07.19 |
|---|---|
| Keycloak으로 SSO 구축한 이야기 (0) | 2026.07.18 |

