OAuth·OIDC·PKCE가 필요한 이유
인증 생태계의 큰 그림에서 인증은 “누구인가”, 인가는 “무엇을 해도 되는가”를 판단한다고 보았다. 이제 **비밀번호를 다른 앱에 넘기지 않고 이 일을 처리하려면 무엇이 필요한가?**를 생각해 보자. OAuth 2.0·OIDC·PKCE라는 이름은 그 문제를 하나씩 푼 뒤에 붙인다. 이 장에서는 목적을 이해하고, 실제 요청 순서는 OAuth 2.0과 OpenID Connect 로그인에서 따라간다.
이 장에서 처음 나오는 말2개
client클라이언트 앱- 다른 서비스에 접근하거나 로그인 결과를 받으려는 앱. 브라우저 자체를 뜻하는 말은 아니며 서버 앱도 client가 된다.
token토큰- 발급자가 만든 결과를 받는 쪽에서 검증해 사용하는 값. API 접근용인지 로그인 확인용인지에 따라 목적과 확인 주체가 다르다.
다른 앱에 비밀번호를 주지 않고 일을 맡기려면
섹션 제목: “다른 앱에 비밀번호를 주지 않고 일을 맡기려면”설명용으로 사진 보관 서비스와 사진 인화 앱을 생각하자. 사용자는 인화 앱에 사진을 읽는 일만 맡기고 싶다. 그런데 사진 서비스의 아이디와 비밀번호를 인화 앱에 주면, 인화 앱은 읽기뿐 아니라 사진 삭제나 계정 설정 변경까지 시도할 수 있다. 비밀번호가 유출될 곳도 하나 더 생긴다.
대신 사용자는 사진 서비스에서 직접 인증하고, 인화 앱에 허용할 접근 범위를 정한다. 인화 앱은 비밀번호 대신 access token을 받아 사진 API에 제시한다. 사진 API는 토큰과 자기 정책을 검사해 허용된 요청만 처리한다. 읽기만 허용한 이 예에서는 사진 조회는 허용하고 삭제는 거부해야 한다.
이처럼 비밀번호를 공유하지 않고 제한된 접근을 앱에 위임하는 규칙이 OAuth 2.0이다. access token을 받았다는 이유로 모든 작업이 허용되는 것은 아니며, 최종 접근 결정은 API가 맡는다.
그 계정으로 앱에 로그인도 하려면
섹션 제목: “그 계정으로 앱에 로그인도 하려면”이번에는 인화 앱이 “사진 서비스 계정으로 로그인”도 제공한다고 하자. 앱은 접근 권한뿐 아니라 어느 사용자가 인증했는지를 알아야 자기 사용자 계정과 로그인 세션을 연결할 수 있다. 사진 읽기용 access token을 받았다는 사실만으로 이 로그인 확인 절차가 정해지지는 않는다.
OpenID Connect(OIDC)는 OAuth 2.0에 사용자 인증 결과를 주고받는 규칙을 더한다. 핵심 결과인 ID token에는 사용자를 식별하는 정보와 발급자·받을 앱·유효 기간 등이 담긴다. 앱은 이를 검증한 뒤 로그인한 사용자를 확인한다. ID token은 사진 API에 접근 권한을 제시하는 access token과 쓰임이 다르다.
그래서 “사진을 읽게 해 달라”에는 OAuth 2.0의 접근 위임이, “인증한 사람이 누구인지 알려 달라”에는 OIDC의 로그인 규칙이 필요하다. OIDC가 OAuth 2.0을 기반으로 하므로 한 로그인 흐름에 두 이름이 함께 등장한다.
로그인 결과를 곧바로 넘기지 않고 code를 거치는 이유
섹션 제목: “로그인 결과를 곧바로 넘기지 않고 code를 거치는 이유”사용자를 로그인 서버로 보냈다가 앱으로 돌려보내려면 브라우저의 이동이 필요하다. 서버 앱에서는 API 호출에 쓸 토큰을 브라우저의 이동 URL에 싣지 않고 서버가 직접 받게 할 수 있다.
Authorization Code 흐름은 브라우저로 짧은 수명의 일회용 code를 먼저 돌려준다. code는 API 이용권 자체가 아니라 토큰으로 교환할 증표다. 앱은 이 code를 발급 서버에 제시하고 필요한 검증을 거쳐 토큰을 받는다. 이 덱의 첫 사례에서는 앱 서버가 그 교환을 맡는다.
Authorization Code는 OAuth·OIDC와 나란히 고르는 별도 로그인 제품이 아니라, 결과를 받는 절차의 이름이다. OIDC도 이 절차를 이용해 ID token과 access token을 받는다.
중간에서 code를 가로채면 어떻게 막을까
섹션 제목: “중간에서 code를 가로채면 어떻게 막을까”code를 한 번 더 교환하게 해도, 다른 주체가 그 code를 가로채 먼저 교환하려는 문제는 남는다. code를 가져왔다는 사실에 더해 처음 요청을 시작할 때 준비한 비밀값도 알고 있는지 확인해야 한다.
이를 위한 보호 장치가 PKCE(Proof Key for Code Exchange)다.
앱은 요청마다 무작위 비밀값인 verifier를 만들고, 그 값에서 계산한 challenge를 먼저 보낸다.
나중에 code를 교환할 때 verifier를 제시하면 발급 서버가 둘의 관계를 대조한다. 이 덱의 S256
방식에서는 challenge를 보고 verifier를 알아내기 어렵게 하므로 code만 훔친 주체의 교환을 막는다.
PKCE는 사용자 비밀번호를 검사하거나 API 권한을 정하지 않는다. code 교환을 보호하는 역할이며, 앱 자체를 인증하는 client secret과도 별개다. verifier와 challenge가 실제로 어디에 남는지는 로그인 흐름의 용어 설명에서 확인할 수 있다.
Keycloak 로그인에서는 함께 사용한다
섹션 제목: “Keycloak 로그인에서는 함께 사용한다”| 해결할 문제 | 쓰는 규칙 | 받거나 확인하는 것 |
|---|---|---|
| 앱에 제한된 API 접근을 맡긴다 | OAuth 2.0 | API에 제시할 access token |
| 앱이 인증한 사용자를 확인한다 | OAuth 2.0 위의 OIDC | 앱이 검증할 ID token |
| 로그인 결과를 code로 먼저 받아 교환한다 | Authorization Code | 짧은 수명의 일회용 code |
| code만 훔친 주체의 교환을 막는다 | Code 흐름에 더하는 PKCE | verifier와 challenge의 연결 |
사내 앱에 대입하면 Keycloak이 사용자 인증과 토큰 발급을 맡는다. 앱은 ID token으로 로그인 신원을 확인하고, 업무 API를 호출할 때는 access token을 사용한다. 이 덱은 그 토큰을 받는 절차로 Authorization Code를 쓰고 PKCE로 교환을 보호한다. 세 약어 중 하나만 선택하는 구성이 아니다.
- OAuth 2.0은 제한된 접근을 맡기기 위해, OIDC는 인증한 사용자를 확인하기 위해 쓴다.
- Authorization Code는 토큰을 받는 절차이고, PKCE는 그 code의 교환을 보호한다.
- 이제 OAuth 2.0과 OpenID Connect 로그인에서 브라우저·앱 서버·Keycloak이 이 규칙에 따라 무엇을 주고받는지 확인한다.